[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/env\",\n      {\n        \"targets\": {\n          \"chrome\": \"130\",\n          \"node\": \"20.9.0\"\n        }\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
    "content": "name: Bug Report\ndescription: Report an issue or unexpected behavior that occurs within the application\ntitle: \"[Bug]: \"\nlabels: [\"bug\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        **README: Before You Submit Your Issue**\n        - Issues are not a place to go ask support questions or start discussions. Please ask support questions or start discussions on the [discussions page](https://github.com/FreeTubeApp/FreeTube/discussions).\n  - type: checkboxes\n    attributes:\n      label: Guidelines\n      description: Please ensure you've completed all of the following.\n      options:\n        - label: I have encountered this bug in the [latest release of FreeTube](https://github.com/FreeTubeApp/FreeTube/releases).\n          required: true\n        - label: I have encountered this bug in the [official downloads of FreeTube](https://github.com/FreeTubeApp/FreeTube#official-downloads).\n          required: true\n        - label: I have [searched the issue tracker for open and closed issues](https://github.com/FreeTubeApp/FreeTube/issues?q=is%3Aissue+sort%3Arelevance-desc) that are similar to the bug report I want to file, without success.\n          required: true\n        - label: I have searched the [documentation](https://docs.freetubeapp.io/) for information that matches the description of the bug I want to file, without success.\n          required: true\n        - label: This issue contains only one bug.\n          required: true\n        - label: I have read and agree to follow the [rules](https://docs.freetubeapp.io/community/rules/).\n          required: true\n  - type: textarea\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is.\n      placeholder: |\n          1. Go to '...'\n          2. Click on '....'\n          3. Scroll down to '....'\n          4. See error\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Expected Behavior\n      description: A clear and concise description of what you expected to happen.\n    validations:\n      required: true\n  - type: dropdown\n    attributes:\n      label: 'Issue Labels'\n      description: Please select a label that fits this bug report. Choose multiple, if applicable.\n      multiple: true\n      options:\n        - accessibility issue\n        - API issue\n        - causes crash\n        - content not loading\n        - data loss\n        - feature stopped working\n        - inconsistent behavior\n        - keyboard control not working\n        - only happens in developer mode\n        - race condition\n        - text/string issue\n        - usability issue\n        - visual bug\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: FreeTube Version\n      description: |\n        If using releases, enter the version.\n        If using nightly builds, enter commit hash or build number, you can find it via about page in the FreeTube application.\n      placeholder: v0.14.0, 8c4278\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: Operating System Version\n      description: What operating system version are you using? On Windows, click Start button > Settings > System > About. On macOS, click the Apple Menu > About This Mac. On Linux, use lsb_release or uname -a.\n      placeholder: \"e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04\"\n    validations:\n      required: true\n  - type: dropdown\n    attributes:\n      label: Installation Method\n      description: When you select an unofficial installation method, you must have verified that the bug is also present in one of the official installation methods. Please make sure you uninstall the unofficial installation before installing one of the official installations. If you can't reproduce this in one of the official installation methods, you should report the bug to the maintainer of the unofficial installation method you used.\n      options:\n        - .AppImage\n        - .deb\n        - .dmg\n        - .exe\n        - Flathub\n        - .pacman\n        - Portable\n        - .rpm\n        - .zip / .7z\n        - .apk (FreeTubeAndroid Unofficial)\n        - .apk (Alpine Linux Package Unofficial)\n        - AUR (Unofficial)\n        - Chocolatey (Unofficial)\n        - Homebrew (Unofficial)\n        - Nix (Unofficial)\n        - PortableApps (Unofficial)\n        - Scoop (Unofficial)\n        - Snapcraft (Unofficial)\n        - WAPT (Unofficial)\n        - winget (Unofficial)\n        - other\n    validations:\n      required: true\n  - type: dropdown\n    attributes:\n      label: Primary API used\n      description: What is the primary API being used?\n      multiple: false\n      options:\n        - Local API\n        - Invidious API\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: 'Last Known Working FreeTube Version (If Any)'\n      description: What is the last version of FreeTube this worked in, if applicable?\n      placeholder: v0.14.0\n  - type: upload\n    id: screenshots\n    attributes:\n      label: Upload screenshots or videos\n      description: If applicable, add screenshots or videos to help explain your problem.\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Additional Information\n      description: |\n        Add additional information here.\n        You may drag-and-drop log files here, or paste the log file in code blocks.\n  - type: checkboxes\n    attributes:\n      label: Nightly Build\n      description: Please ensure you've completed the following, if applicable.\n      options:\n        - label: I have encountered this bug in the latest [nightly build](https://docs.freetubeapp.io/development/nightly-builds).\n          required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Discussions\n    url: https://github.com/FreeTubeApp/FreeTube/discussions/categories/general\n    about: View discussions or start one yourself\n  - name: Questions\n    url: https://github.com/FreeTubeApp/FreeTube/discussions/categories/q-a\n    about: Ask and answer questions\n  - name: Matrix Community\n    url: https://matrix.to/#/#freetube:matrix.org\n    about: 'Join our Matrix chatroom - \"Note: Bugs and Feature requests should be made on GitHub and not in the Matrix room\"'\n  - name: Translate FreeTube\n    url: https://hosted.weblate.org/engage/free-tube/\n    about: Help translate FreeTube on Weblate\n  - name: FreeTube Documentation\n    url: https://docs.freetubeapp.io/\n    about: View the Documentation to find all relevant information about FreeTube\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yaml",
    "content": "name: Feature request\ndescription: Suggest an idea for FreeTube which you would like to see in a future release\ntitle: \"[Feature Request]: \"\nlabels: \"enhancement\"\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        **README: Before You Submit Your Issue**\n        - Issues are not a place to go ask support questions or start discussions. Please ask support questions or start discussions on the [discussions page](https://github.com/FreeTubeApp/FreeTube/discussions).\n  - type: checkboxes\n    attributes:\n      label: Guidelines\n      description: Please ensure you've completed all of the following.\n      options:\n          - label: I have [searched the issue tracker for open and closed issues](https://github.com/FreeTubeApp/FreeTube/issues?q=is%3Aissue+sort%3Arelevance-desc) that are similar to the feature request I want to file, without success.\n            required: true\n          - label: I have searched the [documentation](https://docs.freetubeapp.io/) for information that matches the description of the feature request I want to file, without success.\n            required: true\n          - label: This issue contains only one feature request.\n            required: true\n          - label: I have read and agree to follow the [rules](https://docs.freetubeapp.io/community/rules/).\n            required: true\n  - type: textarea\n    attributes:\n      label: Problem Description\n      description: Please add a clear and concise description of the problem you are seeking to solve with this feature request.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Proposed Solution\n      description: Describe the solution you'd like in a clear and concise manner.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Alternatives Considered\n      description: A clear and concise description of any alternative solutions or features you've considered.\n    validations:\n      required: true\n  - type: dropdown\n    attributes:\n      label: 'Issue Labels'\n      description: Please select a label that fits this feature request. Choose multiple, if applicable.\n      multiple: true\n      options:\n        - display more information to user\n        - ease of use improvement\n        - improvement to existing feature\n        - new feature\n        - new keyboard shortcut\n        - new optional setting\n        - support for external software\n        - visual improvement\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: FreeTube Version\n      description: |\n        If using releases, enter the version.\n        If using nightly builds, enter commit hash or build number, you can find it via about page in the FreeTube application.\n      placeholder: v0.14.0, 8c4278\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: Operating System Version\n      description: What operating system version are you using? On Windows, click Start button > Settings > System > About. On macOS, click the Apple Menu > About This Mac. On Linux, use lsb_release or uname -a.\n      placeholder: \"e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04\"\n    validations:\n      required: true\n  - type: dropdown\n    attributes:\n      label: Installation Method\n      description: If you are using an unofficial installation method, please verify that the requested feature is not already available in one of the official installation methods. If the feature only relates to an unofficial installation, please direct the request to the maintainer of that installation method instead.\n      options:\n        - .AppImage\n        - .deb\n        - .dmg\n        - .exe\n        - Flathub\n        - .pacman\n        - Portable\n        - .rpm\n        - .zip / .7z\n        - .apk (FreeTubeAndroid Unofficial)\n        - .apk (Alpine Linux Package Unofficial)\n        - AUR (Unofficial)\n        - Chocolatey (Unofficial)\n        - Homebrew (Unofficial)\n        - Nix (Unofficial)\n        - PortableApps (Unofficial)\n        - Scoop (Unofficial)\n        - Snapcraft (Unofficial)\n        - WAPT (Unofficial)\n        - winget (Unofficial)\n        - other\n    validations:\n      required: true\n  - type: upload\n    id: screenshots\n    attributes:\n      label: Upload screenshots or videos\n      description: If applicable, add screenshots or videos to help explain your request.\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Additional Information\n      description: |\n        Add any other context about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Thanks for sending a pull request! Make sure to follow the contributing guidelines. -->\n<!-- Important note, we may remove your pull request if you do not use this provided PR template correctly. -->\n<!-- Do not create PR's with AI! (PRs created mainly with AI will be closed. They waste our team's time. We ban repeat offenders.) -->\n\n## Pull Request Type\n<!-- Please select what type of pull request this is: [x] -->\n- [ ] Bugfix\n- [ ] Feature Implementation\n- [ ] Documentation\n- [ ] Other\n\n## Related issue\n<!-- Please link the issue your pull request is referring to. -->\n<!-- If this pull request fully resolves the relevant issue, put \"closes\" before the issue number. -->\n<!-- Example: \"closes #123456\". -->\n\n## Description\n<!-- Please write a clear and concise description of what the pull request does. -->\n\n## Screenshots <!-- If appropriate -->\n<!-- Please add before and after screenshots if there is a visible change. -->\n\n## Testing\n<!-- How can reviewers verify that the PR produces correct results? -->\n<!-- Please provide instructions so that others can ensure that your pull request would produce correct results. For examples see, https://github.com/FreeTubeApp/FreeTube/pull/5743, https://github.com/FreeTubeApp/FreeTube/pull/7349, https://github.com/FreeTubeApp/FreeTube/pull/5125, https://github.com/FreeTubeApp/FreeTube/pull/7338 -->\n\n## Desktop\n<!-- Please complete the following information-->\n- **OS:**\n- **OS Version:**\n- **FreeTube version:**\n\n## Additional context\n<!-- Add any other context about the pull request here. -->\n"
  },
  {
    "path": ".github/auto-merge.yml",
    "content": "minApprovals:\n    COLLABORATOR: 2\nmaxRequestedChanges:\n  COLLABORATOR: 0\nmergeMethod: squash\nrequiredBaseBranches:\n- development\n- test\nreportStatus: true\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"PR: waiting for review\"\n      - \"PR: dependencies\"\n    open-pull-requests-limit: 15\n    groups:\n      babel:\n        patterns:\n          - \"@babel/*\"\n          - \"babel-*\"\n      eslint:\n        patterns:\n          - \"eslint\"\n          - \"eslint-*\"\n          - \"@eslint/*\"\n          - \"vue-eslint-parser\"\n          - \"neostandard\"\n          - \"@intlify/eslint-plugin-vue-i18n\"\n          - \"@stylistic/eslint-plugin\"\n      stylelint:\n        patterns:\n          - \"stylelint\"\n          - \"stylelint-*\"\n          - \"postcss\"\n          - \"postcss-*\"\n          - \"@double-great/stylelint-a11y\"\n      fortawesome:\n        patterns:\n          - \"@fortawesome/*\"\n      webpack:\n        patterns:\n          - \"css-loader\"\n          - \"mini-css-extract-plugin\"\n          - \"sass\"\n          - \"sass-loader\"\n          - \"webpack\"\n          - \"webpack-*\"\n          - \"*-webpack-plugin\"\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"PR: waiting for review\"\n      - \"PR: dependencies\"\n"
  },
  {
    "path": ".github/issue-labeler.yml",
    "content": "'B: visual':\n    - '(visual bug)'\n\n'B: Unofficial Download':\n    - '(AUR \\(Unofficial\\)|Chocolatey \\(Unofficial\\)|\\.apk \\(FreeTubeAndroid Unofficial\\)|Homebrew \\(Unofficial\\)|PortableApps \\(Unofficial\\)|WAPT \\(Unofficial\\)|winget \\(Unofficial\\)|Scoop \\(Unofficial\\)|Snapcraft \\(Unofficial\\)|Nix \\(Unofficial\\))'\n\n'B: keyboard control':\n    - '(keyboard control not working)'\n\n'B: text/string':\n    - '(text/string issue)'\n\n'B: content not loading':\n    - '(content not loading)'\n\n'B: accessibility':\n    - '(accessibility issue)'\n\n'B: usability':\n    - '(usability issue)'\n\n'B: crash':\n    - '(causes crash)'\n\n'B: feature stopped working':\n    - '(feature stopped working)'\n\n'B: inconsistent behavior':\n    - '(inconsistent behavior)'\n\n'B: data loss':\n    - '(data loss)'\n\n'B: race condition':\n    - '(race condition)'\n\n'B: API issue':\n    - '(API issue)'\n\n'B: developer mode':\n    - '(only happens in developer mode)'\n\n'E: improvement existing feature':\n    - '(improvement to existing feature)'\n\n'E: new optional setting':\n    - '(new optional setting)'\n\n'E: visual improvement':\n    - '(visual improvement)'\n\n'E: display more information':\n    - '(display more information to user)'\n\n'E: ease of use improvement':\n    - '(ease of use improvement)'\n\n'E: support external software':\n    - '(support for external software)'\n\n'E: new feature':\n    - '(new feature)'\n\n'E: keyboard shortcut':\n    - '(new keyboard shortcut)'\n"
  },
  {
    "path": ".github/pr-labeler.yml",
    "content": "'PR: waiting for review':\n- changed-files:\n  - any-glob-to-any-file: '**'\n\n'PR: dependencies':\n- any:\n  - changed-files:\n    - any-glob-to-any-file: ['yarn.lock', 'package.json']\n"
  },
  {
    "path": ".github/workflows/autoMerge.yml",
    "content": "name: Auto Merge PR\non:\n  pull_request_target:\n    types: [opened, reopened, auto_merge_disabled, ready_for_review]\n\npermissions: {}\n\njobs:\n  build:\n    if: |\n      github.event.pull_request.state == 'open' &&\n      !github.event.pull_request.draft &&\n      (contains(github.event.pull_request.base.ref, 'development') || contains(github.event.pull_request.base.ref, 'RC'))\n    runs-on: ubuntu-slim\n\n    permissions:\n      contents: write\n\n    steps:\n    - name: Auto Merge PR\n      shell: bash\n      env:\n        GH_TOKEN: ${{ secrets.PUSH_TOKEN }}\n        PR_URL: ${{ github.event.pull_request.html_url }}\n      run: gh pr merge \"$PR_URL\" --auto --squash\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Build\n\non:\n  push:\n    branches: [ master, development, '**-RC' ]\n  workflow_dispatch:\n\npermissions: {}\n\njobs:\n  build:\n\n    # As this action runs on every push to the default branch and uses quite a lot of resources (both minutes and caches),\n    # only run it in the FreeTubeApp/FreeTube repository to avoid unnecessary GitHub Actions usage/billing in forks.\n    # Still allow manually triggering the workflow.\n    # If a fork does need this workflow to run on every push to the default branch, they can change this condition in their fork to include their repository.\n    if: github.repository == 'FreeTubeApp/FreeTube' || github.event_name == 'workflow_dispatch'\n\n    permissions:\n      actions: write\n      contents: read\n\n    strategy:\n      matrix:\n        node-version: [24.x]\n        runtime:\n          - linux-x64\n          - linux-armv7l\n          - linux-arm64\n          - win-x64\n          - win-arm64\n          - osx-x64\n          - osx-arm64\n        include:\n        - runtime: linux-x64\n          os: ubuntu-latest\n\n        - runtime: linux-armv7l\n          os: ubuntu-latest\n\n        - runtime: linux-arm64\n          os: ubuntu-latest\n\n        - runtime: osx-x64\n          os: macOS-latest\n\n        - runtime: osx-arm64\n          os: macOS-latest\n\n        - runtime: win-x64\n          os: windows-latest\n\n        - runtime: win-arm64\n          os: windows-latest\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n    - name: 'Use faster D: drive for yarn cache on Windows'\n      if: startsWith(matrix.os, 'windows')\n      shell: cmd\n      run: yarn config set cache-folder D:\\ft_yarn_cache\n\n    - name: Get yarn cache directory\n      id: cache_dir\n      shell: bash\n      run: |\n        {\n          echo 'cache_dir<<EOF'\n          yarn cache dir\n          echo EOF\n        } >> \"$GITHUB_OUTPUT\"\n\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f #v6.3.0\n      with:\n        node-version: ${{ matrix.node-version }}\n        package-manager-cache: false\n\n    - name: Restore yarn cache\n      id: restore_cache\n      uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 #v5.0.3\n      with:\n        key: ${{ format('node-cache-{0}-{1}-yarn-{2}', runner.os, runner.arch, hashFiles('yarn.lock')) }}\n        path: ${{ steps.cache_dir.outputs.cache_dir }}\n\n    - run: yarn run ci\n      shell: bash\n      env:\n        ELECTRON_SKIP_BINARY_DOWNLOAD: '1'\n    - run: yarn run lint\n      shell: bash\n    - name: Set version number\n      id: versionNumber\n      shell: bash\n      run: |\n        original_version=\"$(jq -r '.version' package.json)\"\n        version=\"$original_version\"\n\n        lower_case_ref=\"$(echo -E \"$GITHUB_REF\" | tr '[:upper:]' '[:lower:]')\"\n\n        if [[ \"$lower_case_ref\" == *development* ]]; then\n          version=\"${original_version}-nightly-${GITHUB_RUN_NUMBER}\"\n        elif [[ \"$lower_case_ref\" == *rc* ]]; then\n          version=\"${original_version}-RC-${GITHUB_RUN_NUMBER}\"\n        fi\n\n        package_json=\"$(jq --arg version \"$version\" '.version = $version' package.json)\"\n\n        echo -E \"$package_json\" > package.json\n        echo \"version=${version}\" >> \"$GITHUB_OUTPUT\"\n\n    - name: Install libarchive-tools\n      if: startsWith(matrix.os, 'ubuntu')\n      shell: bash\n      run: |\n        sudo apt update\n        sudo apt -y install libarchive-tools\n\n    - name: Build x64 with Node.js ${{ matrix.node-version}}\n      if: contains(matrix.runtime, 'x64')\n      shell: bash\n      run: yarn run build\n\n    - name: Build ARMv7l with Node.js ${{ matrix.node-version}}\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      shell: bash\n      run: yarn run build:arm32\n\n    - name: Build ARM64 with Node.js ${{ matrix.node-version}}\n      if: contains(matrix.runtime, 'arm64')\n      shell: bash\n      run: yarn run build:arm64\n\n    - name: Convert X64 AppImage to static runtime\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      shell: bash\n      env:\n        VERSION: ${{ steps.versionNumber.outputs.version }}\n      run: |\n        sudo apt install desktop-file-utils\n        cd build\n        appimage=\"FreeTube-${VERSION}.AppImage\"\n        wget \"https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage\" -O ./appimagetool.AppImage\n        chmod +x ./\"$appimage\" ./appimagetool.AppImage\n        ./\"$appimage\" --appimage-extract && rm -f ./\"$appimage\"\n        ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \\\n          -n ./squashfs-root ./\"$appimage\"\n        rm -rf ./squashfs-root ./appimagetool.AppImage\n\n    - name: Upload Linux .zip x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-x64-portable.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.zip\n\n    - name: Upload Linux .7z x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-x64-portable.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.7z\n\n    - name: Upload Linux .zip ARMv7l Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-armv7l-portable.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-armv7l.zip\n\n    - name: Upload Linux .7z ARMv7l Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-armv7l-portable.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-armv7l.7z\n\n    - name: Upload Linux .zip ARM64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-arm64-portable.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64.zip\n\n    - name: Upload Linux .7z ARM64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-linux-arm64-portable.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64.7z\n\n    - name: Upload .deb x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube_${{ steps.versionNumber.outputs.version }}_amd64.deb\n        path: build/freetube_${{ steps.versionNumber.outputs.version }}_amd64.deb\n\n    - name: Upload .deb ARMv7l Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      with:\n        name: freetube_${{ steps.versionNumber.outputs.version }}_armv7l.deb\n        path: build/freetube_${{ steps.versionNumber.outputs.version }}_armv7l.deb\n\n    - name: Upload .deb ARM64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      with:\n        name: freetube_${{ steps.versionNumber.outputs.version }}_arm64.deb\n        path: build/freetube_${{ steps.versionNumber.outputs.version }}_arm64.deb\n\n    - name: Upload AppImage x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-amd64.AppImage\n        path: build/FreeTube-${{ steps.versionNumber.outputs.version }}.AppImage\n\n    - name: Upload AppImage ARMv7l Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-armv7l.AppImage\n        path: build/FreeTube-${{ steps.versionNumber.outputs.version }}-armv7l.AppImage\n\n    - name: Upload AppImage ARM64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-arm64.AppImage\n        path: build/FreeTube-${{ steps.versionNumber.outputs.version }}-arm64.AppImage\n\n    - name: Upload .rpm x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}.amd64.rpm\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.x86_64.rpm\n\n    # rpm are not built for armv7l\n\n    - name: Upload .rpm ARM64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}.arm64.rpm\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.aarch64.rpm\n\n    - name: Upload Pacman .pacman x64 Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-amd64.pacman\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.pacman\n\n    - name: Upload Windows x64 .exe Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-setup-x64.exe\n        path: build/freetube Setup ${{ steps.versionNumber.outputs.version }}.exe\n\n    - name: Upload Windows x64 Portable Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-x64-portable.exe\n        path: build/freetube ${{ steps.versionNumber.outputs.version }}.exe\n\n    - name: Upload Windows x64 .zip Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-x64-portable.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-win.zip\n\n    - name: Upload Windows x64 .7z Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-x64-portable.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-win.7z\n\n    - name: Upload Windows arm64 .exe Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-setup-arm64.exe\n        path: build/freetube Setup ${{ steps.versionNumber.outputs.version }}.exe\n\n    - name: Upload Windows arm64 Portable Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-arm64-portable.exe\n        path: build/freetube ${{ steps.versionNumber.outputs.version }}.exe\n\n    - name: Upload Windows arm64 .zip Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-arm64-portable.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64-win.zip\n\n    - name: Upload Windows arm64 .7z Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-win-arm64-portable.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64-win.7z\n\n    - name: Upload Mac x64 .dmg Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-x64.dmg\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}.dmg\n\n    - name: Upload Mac x64 .zip Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-x64.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-mac.zip\n\n    - name: Upload Mac x64 .7z Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-x64.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-mac.7z\n\n    - name: Upload Mac arm64 .dmg Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-arm64.dmg\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64.dmg\n\n    - name: Upload Mac arm64 .zip Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-arm64.zip\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64-mac.zip\n\n    - name: Upload Mac arm64 .7z Artifact\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      with:\n        name: freetube-${{ steps.versionNumber.outputs.version }}-mac-arm64.7z\n        path: build/freetube-${{ steps.versionNumber.outputs.version }}-arm64-mac.7z\n\n    - name: Save yarn cache\n      uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 #v5.0.3\n      # Only save the cache if we weren't able to restore an existing one above\n      if: steps.restore_cache.outputs.cache-primary-key != steps.restore_cache.outputs.cache-matched-key\n      with:\n        key: ${{ steps.restore_cache.outputs.cache-primary-key }}\n        path: ${{ steps.cache_dir.outputs.cache_dir }}\n"
  },
  {
    "path": ".github/workflows/calibreapp-image-actions.yml",
    "content": "# Compress images on demand (workflow_dispatch), and at 12am every Sunday (schedule).\n# Open a Pull Request if any images can be compressed.\nname: Compress Images\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '0 0 * * 0'\n\npermissions: {}\n\njobs:\n  build:\n    # As this action runs on a schedule, only run it in the FreeTubeApp/FreeTube repository to avoid unnecessary GitHub Actions usage/billing in forks.\n    # Still allow the workflow to be manually triggered.\n    # If a fork does need this workflow, they can change this condition in their fork to include their repository.\n    if: github.repository == 'FreeTubeApp/FreeTube' || github.event_name == 'workflow_dispatch'\n\n    name: calibreapp/image-actions\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: write\n      pull-requests: write\n\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Compress Images\n        id: calibre\n        uses: calibreapp/image-actions@d9c8ee5c3dc52ae4622c82ead88d658f4b16b65f\n        with:\n          githubToken: ${{ secrets.GITHUB_TOKEN }}\n          compressOnly: true\n      - name: Create New Pull Request If Needed\n        if: steps.calibre.outputs.markdown != ''\n        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0\n        with:\n          title: Compressed Images Nightly\n          branch-suffix: timestamp\n          commit-message: Compressed Images\n          body: ${{ steps.calibre.outputs.markdown }}\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ \"development\" ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ \"development\" ]\n  schedule:\n    - cron: '36 3 * * 5'\n\npermissions: {}\n\njobs:\n  analyze:\n    # As this action runs on a schedule, only run it in the FreeTubeApp/FreeTube repository to avoid unnecessary GitHub Actions usage/billing in forks.\n    # We still allow it to run if it was triggered by a pull request or a push as active forks should care about security.\n    # If a fork does need this workflow to run on a schedule, they can change this condition in their fork to include their repository.\n    if: github.repository == 'FreeTubeApp/FreeTube' || github.event_name != 'schedule'\n\n    name: Analyze (${{ matrix.language }})\n    runs-on: ubuntu-latest\n\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - language: actions\n            build-mode: none\n          - language: javascript-typescript\n            build-mode: none\n          # https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\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        build-mode: ${{ matrix.build-mode }}\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/conflicts.yml",
    "content": "name: \"Conflicts\"\non:\n  # So that PRs touching the same files as the push are updated\n  push:\n  # So that the `dirtyLabel` is removed if conflicts are resolve\n  # We recommend `pull_request_target` so that github secrets are available.\n  # In `pull_request` we wouldn't be able to change labels of fork PRs\n  pull_request_target:\n    types: [synchronize]\n\npermissions: {}\n\njobs:\n  main:\n    runs-on: ubuntu-slim\n\n    permissions:\n      pull-requests: write\n\n    steps:\n      - name: check if prs are dirty\n        uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 #v3.0.3\n        with:\n          dirtyLabel: \"PR: merge conflicts / rebase needed\"\n          removeOnDirtyLabel: \"PR: waiting for review\"\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          commentOnDirty: \"This pull request has conflicts, please resolve those before we can evaluate the pull request.\"\n          commentOnClean: \"Conflicts have been resolved. A maintainer will review the pull request shortly.\"\n"
  },
  {
    "path": ".github/workflows/flatpak.yml",
    "content": "# This is a basic workflow that is manually triggered\n\nname: Create Flatpak PR\n\n# Controls when the action will run. Workflow runs when manually triggered using the UI\n# or API.\non:\n  workflow_dispatch:\n  # Disable running automatically as we now use flathub's external data checker\n  # to automatically open pull requests when we release updates\n  # release:\n  #   types: [published]\n\npermissions: {}\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: read\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n      with:\n        repository: flathub/io.freetubeapp.FreeTube\n        token: ${{ secrets.FLATHUB_TOKEN }}\n        persist-credentials: true\n\n    - name: Get Repo Release List\n      uses: moustacheful/github-api-exec-action@2135aaccb1220f81e6fa4f14c90cc20efba069fe #v0\n      id: list_results\n      with:\n        # Command to execute, (e.g: `pulls.create`), see https://octokit.github.io/rest.js/ for available commands\n        command: repos.listReleases\n        payload: >\n            {\n              \"owner\": \"FreeTubeApp\",\n              \"repo\": \"FreeTube\"\n            }\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    - name: Install xmlstarlet\n      shell: bash\n      run: sudo apt -y install xmlstarlet\n    - name: Create Version Variable\n      uses: bluwy/substitute-string-action@70ff0b17357670ffd3fee68e95b6de9963b66bad #v3.0.0\n      id: sub\n      with:\n        _input-text: ${{ fromJson(steps.list_results.outputs.result)[0].tag_name }}\n        -beta: ''\n        v: ''\n    - name: Create Release Branch\n      shell: bash\n      env:\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: |\n        git checkout -b \"release-v${VERSION}\"\n        git push --set-upstream origin \"release-v${VERSION}\"\n    - name: Download x64 Release\n      uses: fabriciobastian/download-release-asset-action@35e62aa5a2fe4a6ec79004f6052918349013ae4f #v1.0.6\n      with:\n        version: v${{ steps.sub.outputs.result }}-beta\n        repository: FreeTubeApp/FreeTube\n        file: freetube-${{ steps.sub.outputs.result }}-beta-linux-x64-portable.zip\n    - name: Download ARM Release\n      uses: fabriciobastian/download-release-asset-action@35e62aa5a2fe4a6ec79004f6052918349013ae4f #v1.0.6\n      with:\n        version: v${{ steps.sub.outputs.result }}-beta\n        repository: FreeTubeApp/FreeTube\n        file: freetube-${{ steps.sub.outputs.result }}-beta-linux-arm64-portable.zip\n    - name: Set x64 Hash Variable\n      id: hash_x64\n      shell: bash\n      env:\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: |\n        echo 'HASH_X64<<EOF' >> \"$GITHUB_OUTPUT\"\n        sha256sum \"freetube-${VERSION}-beta-linux-x64-portable.zip\" | awk '{print $1}' >> \"$GITHUB_OUTPUT\"\n        echo 'EOF' >> \"$GITHUB_OUTPUT\"\n    - name: Set ARM Hash Variable\n      id: hash_arm64\n      shell: bash\n      env:\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: |\n        echo 'HASH_ARM64<<EOF' >> \"$GITHUB_OUTPUT\"\n        sha256sum \"freetube-${VERSION}-beta-linux-arm64-portable.zip\" | awk '{print $1}' >> \"$GITHUB_OUTPUT\"\n        echo 'EOF' >> \"$GITHUB_OUTPUT\"\n\n    - name: Set Date Variable\n      id: current_date\n      shell: bash\n      run: |\n        echo 'CURRENT_DATE<<EOF' >> \"$GITHUB_OUTPUT\"\n        date +\"%Y-%m-%d\" >> \"$GITHUB_OUTPUT\"\n        echo 'EOF' >> \"$GITHUB_OUTPUT\"\n    - name: Update x64 File Location in yml File\n      shell: bash\n      env:\n        VERSION: steps.sub.outputs.result\n      run: |\n        yq -i '.modules[0].sources[0].url = \"https://github.com/FreeTubeApp/FreeTube/releases/download/v\" + strenv(VERSION) + \"-beta/freetube-\" + strenv(VERSION) + \"-beta-linux-x64-portable.zip\"' io.freetubeapp.FreeTube.yml\n\n    - name: Update x64 Hash in yml File\n      shell: bash\n      env:\n        HASH_X64: ${{ steps.hash_x64.outputs.HASH_X64 }}\n      run: |\n        yq -i '.modules[0].sources[0].sha256 = strenv(HASH_X64)' io.freetubeapp.FreeTube.yml\n\n    - name: Update ARM File Location in yml File\n      shell: bash\n      env:\n        VERSION: steps.sub.outputs.result\n      run: |\n        yq -i '.modules[0].sources[1].url = \"https://github.com/FreeTubeApp/FreeTube/releases/download/v\" + strenv(VERSION) + \"-beta/freetube-\" + strenv(VERSION) + \"-beta-linux-arm64-portable.zip\"' io.freetubeapp.FreeTube.yml\n\n    - name: Update ARM Hash in yml File\n      shell: bash\n      env:\n        HASH_ARM64: ${{ steps.hash_arm64.outputs.HASH_ARM64 }}\n      run: |\n        yq -i '.modules[0].sources[1].sha256 = strenv(HASH_ARM64)' io.freetubeapp.FreeTube.yml\n\n    - name: Add Patch Notes to XML File\n      shell: bash\n      env:\n        CURRENT_DATE: ${{ steps.current_date.outputs.current_date }}\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: xmlstarlet ed -L -i /component/releases/release[1] -t elem -n releaseTMP -v \"\" -i //releaseTMP -t attr -n version -v \"${VERSION} Beta\" -i //releaseTMP -t attr -n date -v \"${CURRENT_DATE}\" -s //releaseTMP -t elem -n url -v \"\" -s //releaseTMP/url -t text -n \"\" -v \"https://github.com/FreeTubeApp/FreeTube/releases/tag/v${VERSION}-beta\" -r //releaseTMP -v \"release\" io.freetubeapp.FreeTube.metainfo.xml\n    - name: Remove Release Files\n      shell: bash\n      env:\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: |\n        rm \"freetube-${VERSION}-beta-linux-x64-portable.zip\"\n        rm \"freetube-${VERSION}-beta-linux-arm64-portable.zip\"\n    - name: Commit Files\n      uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 #v7.1.0\n      with:\n        # Optional but recommended\n        # Defaults to \"Apply automatic changes\"\n        commit_message: Update files for v${{ steps.sub.outputs.result }}\n\n        # Optional options appended to `git-commit`\n        # See https://git-scm.com/docs/git-commit for a list of available options\n        commit_options: '--no-verify --signoff'\n\n        # Optional: Disable dirty check and always try to create a commit and push\n        skip_dirty_check: true\n    - name: Create PR\n      shell: bash\n      env:\n        GH_TOKEN: ${{ secrets.FLATHUB_TOKEN }}\n        VERSION: ${{ steps.sub.outputs.result }}\n      run: gh pr create --title \"Release v${VERSION}\" --body \"This is an automated PR for the v${VERSION} release. This PR will be updated and merged once testing is complete.\"\n"
  },
  {
    "path": ".github/workflows/label-issue.yml",
    "content": "name: \"Issue Labeler\"\non:\n  issues:\n    types: [opened]\n\npermissions: {}\n\njobs:\n  triage:\n    runs-on: ubuntu-slim\n\n    permissions:\n      contents: read\n      issues: write\n\n    steps:\n    - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 #v3.4\n      with:\n        configuration-path: .github/issue-labeler.yml\n        enable-versioned-regex: 0\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/label-pr.yml",
    "content": "name: \"Pull Request Labeler\"\non:\n  pull_request_target:\n    types: [opened, reopened, ready_for_review]\n\npermissions: {}\n\njobs:\n  triage:\n    permissions:\n      contents: read\n      pull-requests: write\n\n    runs-on: ubuntu-slim\n    if: ${{ !github.event.pull_request.draft }}\n    steps:\n    - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b #v6.0.1\n      with:\n        repo-token: \"${{ secrets.GITHUB_TOKEN }}\"\n        configuration-path: .github/pr-labeler.yml\n"
  },
  {
    "path": ".github/workflows/linter.yml",
    "content": "# This is a basic workflow to help you get started with Actions\n\nname: Linter\n\n# Controls when the action will run. Triggers the workflow on push or pull request\n# events but only for the master branch\non:\n  pull_request:\n    branches: [ master, development, '**-RC' ]\n\npermissions: {}\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  # This workflow contains a single job called \"build\"\n  lint:\n    # The type of runner that the job will run on\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: read\n\n    # Steps represent a sequence of tasks that will be executed as part of the job\n    steps:\n    - name: Get yarn cache directory\n      id: cache_dir\n      shell: bash\n      run: |\n        {\n          echo 'cache_dir<<EOF'\n          yarn cache dir\n          echo EOF\n        } >> \"$GITHUB_OUTPUT\"\n\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: Use Node.js 24.x\n      uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f #v6.3.0\n      with:\n        node-version: 24.x\n        package-manager-cache: false\n\n    # This workflow runs on pull requests which are untrusted\n    # so we only restore the yarn cache, we don't save it to avoid cache poisoning\n    - name: Restore yarn cache\n      id: restore_cache\n      uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 #v5.0.3\n      with:\n        key: ${{ format('node-cache-{0}-{1}-yarn-{2}', runner.os, runner.arch, hashFiles('yarn.lock')) }}\n        path: ${{ steps.cache_dir.outputs.cache_dir }}\n\n    - run: yarn run ci\n      shell: bash\n      env:\n        ELECTRON_SKIP_BINARY_DOWNLOAD: '1'\n    - run: yarn run lint\n      shell: bash\n    # let's verify that webpack is able to package the project\n    - run: yarn run pack\n      shell: bash\n    # verify that webpack is able to package the project using the web config\n    - run: yarn run pack:web\n      shell: bash\n"
  },
  {
    "path": ".github/workflows/no-response.yml",
    "content": "name: No Response\n\n# Both `issue_comment` and `scheduled` event types are required for this Action\n# to work properly.\non:\n  issue_comment:\n    types: [created]\n  schedule:\n    # Run daily at midnight.\n    - cron: '0 0 * * *'\n\npermissions: {}\n\njobs:\n  noResponse:\n    # As this action runs on a schedule, only run it in the FreeTubeApp/FreeTube repository to avoid unnecessary GitHub Actions usage/billing in forks.\n    # If a fork does need this workflow, they can change this condition in their fork to include their repository.\n    if: github.repository == 'FreeTubeApp/FreeTube'\n\n    runs-on: ubuntu-slim\n\n    permissions:\n      issues: write\n\n    steps:\n      - uses: lee-dohm/no-response@9bb0a4b5e6a45046f00353d5de7d90fb8bd773bb #v0.5.0\n        with:\n          token: ${{ github.token }}\n          closeComment: >\n            This issue has been automatically closed because there has been no response to our request for more information from the original author.\n            With only the information that is currently in the issue, we don't have enough information to take action.\n            Please reach out if you have or find the answers we need so that we can investigate further.\n          daysUntilClose: 7\n          responseRequiredLabel: \"U: Waiting for Response from Author\"\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "# This is a basic workflow that is manually triggered\n\nname: Upload Release\n\n# Controls when the action will run. Workflow runs when manually triggered using the UI\n# or API.\non:\n  workflow_dispatch:\n    inputs:\n      releaseId:\n        type: string\n        required: true\n        description: Release ID\n\npermissions: {}\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  build:\n\n    permissions:\n      contents: write\n\n    strategy:\n      matrix:\n        node-version: [24.x]\n        runtime:\n          - linux-x64\n          - linux-armv7l\n          - linux-arm64\n          - win-x64\n          - win-arm64\n          - osx-x64\n          - osx-arm64\n        include:\n        - runtime: linux-x64\n          os: ubuntu-latest\n\n        - runtime: linux-armv7l\n          os: ubuntu-latest\n\n        - runtime: linux-arm64\n          os: ubuntu-latest\n\n        - runtime: osx-x64\n          os: macOS-latest\n\n        - runtime: osx-arm64\n          os: macOS-latest\n\n        - runtime: win-x64\n          os: windows-latest\n\n        - runtime: win-arm64\n          os: windows-latest\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n      with:\n        persist-credentials: false\n\n    # Do not restore the yarn cache, to avoid cache poisoning affecting releases\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f #v6.3.0\n      with:\n        node-version: ${{ matrix.node-version }}\n        package-manager-cache: false\n\n    - run: yarn run ci\n      shell: bash\n      env:\n        ELECTRON_SKIP_BINARY_DOWNLOAD: '1'\n    - run: yarn run lint\n      shell: bash\n\n    - name: Get Version Number\n      id: getPackageInfo\n      shell: bash\n      run: |\n        jq --raw-output '\"version=\" + .version' package.json >> \"$GITHUB_OUTPUT\"\n\n    - name: Install libarchive-tools\n      if: startsWith(matrix.os, 'ubuntu')\n      shell: bash\n      run: |\n        sudo apt update\n        sudo apt -y install libarchive-tools\n\n    - name: Build x64 with Node.js ${{ matrix.node-version}}\n      if: contains(matrix.runtime, 'x64')\n      shell: bash\n      run: yarn run build\n\n    - name: Build ARMv7l with Node.js ${{ matrix.node-version}}\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      shell: bash\n      run: yarn run build:arm32\n\n    - name: Build ARM64 with Node.js ${{ matrix.node-version}}\n      if: contains(matrix.runtime, 'arm64')\n      shell: bash\n      run: yarn run build:arm64\n\n    - name: Convert X64 AppImage to static runtime and add update information\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      shell: bash\n      env:\n        VERSION: ${{ steps.getPackageInfo.outputs.version }}\n      run: |\n        sudo apt install desktop-file-utils\n        cd build\n        appimage=\"FreeTube-${VERSION}.AppImage\"\n        wget \"https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage\" -O ./appimagetool.AppImage\n        chmod +x ./\"$appimage\" ./appimagetool.AppImage\n        update_information='gh-releases-zsync|FreeTubeApp|FreeTube|latest-all|freetube-*-amd64.AppImage.zsync'\n        ./\"$appimage\" --appimage-extract && rm -f ./\"$appimage\"\n        ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \\\n          -u \"$update_information\" -n ./squashfs-root ./\"$appimage\"\n        rm -rf ./squashfs-root ./appimagetool.AppImage\n\n    - name: Convert ARMv7l AppImage to static runtime and add update information\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      shell: bash\n      env:\n        VERSION: ${{ steps.getPackageInfo.outputs.version }}\n      run: |\n        sudo apt install desktop-file-utils\n        cd build\n        appimage=\"FreeTube-${VERSION}.AppImage\"\n        wget \"https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage\" -O ./appimagetool.AppImage\n        wget \"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64\" -O runtime\n        chmod +x ./\"$appimage\" ./appimagetool.AppImage ./runtime\n        update_information='gh-releases-zsync|FreeTubeApp|FreeTube|latest-all|freetube-*-armv7l.AppImage.zsync'\n        TARGET_APPIMAGE=\"$appimage\" ./runtime --appimage-extract && rm -f ./\"$appimage\"\n        ARCH=armhf ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \\\n          -u \"$update_information\" -n ./squashfs-root ./\"$appimage\"\n        rm -rf ./squashfs-root ./appimagetool.AppImage ./runtime\n\n    - name: Convert ARM64 AppImage to static runtime and add update information\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      shell: bash\n      env:\n        VERSION: ${{ steps.getPackageInfo.outputs.version }}\n      run: |\n        sudo apt install desktop-file-utils\n        cd build\n        appimage=\"FreeTube-${VERSION}.AppImage\"\n        wget \"https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage\" -O ./appimagetool.AppImage\n        wget \"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64\" -O runtime\n        chmod +x ./\"$appimage\" ./appimagetool.AppImage ./runtime\n        update_information='gh-releases-zsync|FreeTubeApp|FreeTube|latest-all|freetube-*-arm64.AppImage.zsync'\n        TARGET_APPIMAGE=\"$appimage\" ./runtime --appimage-extract && rm -f ./\"$appimage\"\n        ARCH=aarch64 ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \\\n          -u \"$update_information\" -n ./squashfs-root ./\"$appimage\"\n        rm -rf ./squashfs-root ./appimagetool.AppImage ./runtime\n\n    - name: Upload Linux .zip x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-x64-portable.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.zip\n        asset_content_type: application/zip\n\n    - name: Upload Linux .7z x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-x64-portable.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Linux .zip ARMv7l Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-armv7l-portable.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-armv7l.zip\n        asset_content_type: application/zip\n\n    - name: Upload Linux .7z ARMv7l Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-armv7l-portable.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-armv7l.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Linux .zip ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-arm64-portable.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64.zip\n        asset_content_type: application/zip\n\n    - name: Upload Linux .7z ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-linux-arm64-portable.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Linux .deb x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube_${{ steps.getPackageInfo.outputs.version }}_beta_amd64.deb\n        asset_path: build/freetube_${{ steps.getPackageInfo.outputs.version }}_amd64.deb\n        asset_content_type: application/vnd.debian.binary-package\n\n    - name: Upload Linux .deb ARMv7l Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube_${{ steps.getPackageInfo.outputs.version }}_beta_armv7l.deb\n        asset_path: build/freetube_${{ steps.getPackageInfo.outputs.version }}_armv7l.deb\n        asset_content_type: application/vnd.debian.binary-package\n\n    - name: Upload Linux .deb ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube_${{ steps.getPackageInfo.outputs.version }}_beta_arm64.deb\n        asset_path: build/freetube_${{ steps.getPackageInfo.outputs.version }}_arm64.deb\n        asset_content_type: application/vnd.debian.binary-package\n\n    - name: Upload AppImage x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-amd64.AppImage\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}.AppImage\n        asset_content_type: application/vnd.appimage\n\n    - name: Upload AppImage .zsync x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-amd64.AppImage.zsync\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}.AppImage.zsync\n        asset_content_type: application/x-zsync\n\n    - name: Upload AppImage ARMv7l Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-armv7l.AppImage\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}-armv7l.AppImage\n        asset_content_type: application/vnd.appimage\n\n    - name: Upload AppImage .zsync ARMv7l Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-armv7l.AppImage.zsync\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}-armv7l.AppImage.zsync\n        asset_content_type: application/x-zsync\n\n    - name: Upload AppImage ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-arm64.AppImage\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}-arm64.AppImage\n        asset_content_type: application/vnd.appimage\n\n    - name: Upload AppImage .zsync ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-arm64.AppImage.zsync\n        asset_path: build/FreeTube-${{ steps.getPackageInfo.outputs.version }}-arm64.AppImage.zsync\n        asset_content_type: application/x-zsync\n\n    - name: Upload Linux .rpm x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta.amd64.rpm\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.x86_64.rpm\n        asset_content_type: application/x-rpm\n\n      # rpm are not built for armv7l\n\n    - name: Upload Linux .rpm ARM64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta.arm64.rpm\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.aarch64.rpm\n        asset_content_type: application/x-rpm\n\n    - name: Upload Pacman .pacman x64 Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-amd64.pacman\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.pacman\n        asset_content_type: application/x-zstd-compressed-tar\n\n    - name: Upload Windows x64 .exe Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-setup-x64.exe\n        asset_path: build/freetube Setup ${{ steps.getPackageInfo.outputs.version }}.exe\n        asset_content_type: application/x-ms-dos-executable\n\n    - name: Upload Windows x64 portable Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-x64-portable.exe\n        asset_path: build/FreeTube ${{ steps.getPackageInfo.outputs.version }}.exe\n        asset_content_type: application/x-ms-dos-executable\n\n    - name: Upload Windows x64 .zip Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-x64-portable.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-win.zip\n        asset_content_type: application/zip\n\n    - name: Upload Windows x64 .7z Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-x64-portable.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-win.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Windows arm64 .exe Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-setup-arm64.exe\n        asset_path: build/freetube Setup ${{ steps.getPackageInfo.outputs.version }}.exe\n        asset_content_type: application/x-ms-dos-executable\n\n    - name: Upload Windows arm64 portable Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-arm64-portable.exe\n        asset_path: build/FreeTube ${{ steps.getPackageInfo.outputs.version }}.exe\n        asset_content_type: application/x-ms-dos-executable\n\n    - name: Upload Windows arm64 .zip Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-arm64-portable.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-win.zip\n        asset_content_type: application/zip\n\n    - name: Upload Windows arm64 .7z Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-win-arm64-portable.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-win.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Mac x64 .dmg Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-x64.dmg\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.dmg\n        asset_content_type: application/x-apple-diskimage\n\n    - name: Upload Mac x64 .zip Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-x64.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-mac.zip\n        asset_content_type: application/zip\n\n    - name: Upload Mac x64 .7z Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-x64.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-mac.7z\n        asset_content_type: application/x-7z-compressed\n\n    - name: Upload Mac arm64 .dmg Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-arm64.dmg\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64.dmg\n        asset_content_type: application/x-apple-diskimage\n\n    - name: Upload Mac arm64 .zip Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-arm64.zip\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-mac.zip\n        asset_content_type: application/x-apple-diskimage\n\n    - name: Upload Mac arm64 .7z Release\n      uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2\n      if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ inputs.releaseId }}/assets{?name,label}\n        asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-beta-mac-arm64.7z\n        asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-mac.7z\n        asset_content_type: application/x-7z-compressed\n"
  },
  {
    "path": ".github/workflows/remove-outdated-labels.yml",
    "content": "name: Remove outdated labels\non:\n  pull_request_target:\n    types:\n      - closed\n      - converted_to_draft\n      - ready_for_review\n\npermissions: {}\n\njobs:\n  remove-closed-pr-labels:\n    name: Remove closed and merged pull request labels\n    if: github.event.action == 'closed'\n    runs-on: ubuntu-slim\n\n    permissions:\n      pull-requests: write\n\n    steps:\n      - name: Remove labels\n        shell: bash\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          PR_URL: ${{ github.event.pull_request.html_url }}\n        run: |\n          labels='PR: waiting for review,'\n          labels+='PR: WIP,'\n          labels+='PR: changes requested,'\n          labels+='PR: merge conflicts / rebase needed,'\n          labels+='PR/Issue: dependent,'\n          labels+='PR: stale'\n\n          gh pr edit \"$PR_URL\" --remove-label \"$labels\"\n\n  remove-draft-pr-labels:\n    name: Remove labels from draft pull requests\n    if: |\n      github.event.action == 'converted_to_draft' && contains(github.event.pull_request.labels.*.name, 'PR: waiting for review')\n    runs-on: ubuntu-slim\n\n    permissions:\n      pull-requests: write\n\n    steps:\n      - name: Remove label\n        shell: bash\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          PR_URL: ${{ github.event.pull_request.html_url }}\n        run: |\n          gh pr edit \"$PR_URL\" --remove-label 'PR: waiting for review'\n\n  remove-ready-pr-labels:\n    name: Remove labels when draft pr is marked ready for review\n    if: |\n      github.event.action == 'ready_for_review' && contains(github.event.pull_request.labels.*.name, 'PR: WIP')\n    runs-on: ubuntu-slim\n\n    permissions:\n      pull-requests: write\n\n    steps:\n      - name: Remove label\n        shell: bash\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          PR_URL: ${{ github.event.pull_request.html_url }}\n        run: |\n          gh pr edit \"$PR_URL\" --remove-label 'PR: WIP'\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: 'Close stale PRs'\non:\n  schedule:\n    - cron: '30 1 * * *'\n\npermissions: {}\n\njobs:\n  stale:\n    # As this action runs on a schedule, only run it in the FreeTubeApp/FreeTube repository to avoid unnecessary GitHub Actions usage/billing in forks.\n    # If a fork does need this workflow, they can change this condition in their fork to include their repository.\n    if: github.repository == 'FreeTubeApp/FreeTube'\n\n    runs-on: ubuntu-slim\n\n    permissions:\n      actions: write\n      pull-requests: write\n\n    steps:\n      - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f #v10.2.0\n        with:\n          stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.'\n          close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.'\n          days-before-pr-stale: 14\n          days-before-pr-close: 14\n          stale-pr-label: 'PR: stale'\n          exempt-pr-labels: 'PR: WIP'\n\n          # actions/stale doesn't have a way of running only on pull requests\n          # so set the issue thresholds to -1 so it at least doesn't try to label or close them\n          days-before-stale: -1\n          days-before-close: -1\n"
  },
  {
    "path": ".github/workflows/updateSite.yml",
    "content": "# This is a basic workflow that is manually triggered\n\nname: Update Site Version Number\n\n# Controls when the action will run. Workflow runs when manually triggered using the UI\n# or API.\non:\n  workflow_dispatch:\n  release:\n    types: [published]\n\npermissions: {}\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: read\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2\n      with:\n        repository: FreeTubeApp/FreeTubeApp.io\n        token: ${{ secrets.FLATHUB_TOKEN }}\n        persist-credentials: true\n\n    - name: Get Repo Release List\n      uses: moustacheful/github-api-exec-action@2135aaccb1220f81e6fa4f14c90cc20efba069fe #v0\n      id: list_results\n      with:\n        # Command to execute, (e.g: `pulls.create`), see https://octokit.github.io/rest.js/ for available commands\n        command: repos.listReleases\n        payload: >\n            {\n              \"owner\": \"FreeTubeApp\",\n              \"repo\": \"FreeTube\"\n            }\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    - name: Create Current Version Variable\n      uses: bluwy/substitute-string-action@70ff0b17357670ffd3fee68e95b6de9963b66bad #v3.0.0\n      id: current\n      with:\n        _input-text: ${{ fromJson(steps.list_results.outputs.result)[0].tag_name }}\n        -beta: ''\n        v: ''\n    - name: Create Previous Version Variable\n      uses: bluwy/substitute-string-action@70ff0b17357670ffd3fee68e95b6de9963b66bad #v3.0.0\n      id: previous\n      with:\n        _input-text: ${{ fromJson(steps.list_results.outputs.result)[1].tag_name }}\n        -beta: ''\n        v: ''\n    - name: Set Master Branch\n    # Currently the default branch is master, but if that changes later, then this acts as a failsafe.\n      shell: bash\n      run: |\n        git checkout master\n    - name: Update index.php\n      shell: bash\n      env:\n        CURRENT: ${{ steps.current.outputs.result }}\n        PREVIOUS: ${{ steps.previous.outputs.result }}\n      run: |\n        sed -i \"s/${PREVIOUS}/${CURRENT}/g\" src/index.php\n    - name: Commit Files\n      uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 #v7.1.0\n      with:\n        # Optional but recommended\n        # Defaults to \"Apply automatic changes\"\n        commit_message: Update version number to v${{ steps.current.outputs.result }}\n\n        # Optional options appended to `git-commit`\n        # See https://git-scm.com/docs/git-commit for a list of available options\n        commit_options: '--no-verify --signoff'\n\n        # Optional: Disable dirty check and always try to create a commit and push\n        skip_dirty_check: true\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\ndist/electron/*\nstoryboards/*\ndashFiles/*\nstatic/dashFiles\nstatic/storyboards\nstatic/dashFiles/*\nstatic/storyboards/*\ndist/web/*\nbuild/*\n!build/icons\ncoverage\nnode_modules/\nnpm-debug.log\nnpm-debug.log.*\nthumbs.db\n!.gitkeep\ndata/tmp/\n.tmp/\ntmp/\n.cache\ndist\ncoverage\n__coverage__\ncsak-timelog.json\n.idea/\ndebug/\n\n# Lefthook\nlefthook-local.yml\n\nlocale-errors.json\n"
  },
  {
    "path": ".stylelintignore",
    "content": "src/data/\nsrc/datastores/\nsrc/main/\nsrc/renderer/videoJS.css\ndist/\nstatic/\nnode_modules/\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"editorconfig.editorconfig\",\n    \"dbaeumer.vscode-eslint\",\n    \"stylelint.vscode-stylelint\",\n    \"syler.sass-indented\",\n    \"redhat.vscode-yaml\",\n    \"vue.volar\",\n    \"eamodio.gitlens\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"dev-runner (Electron)\",\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"program\": \"${workspaceFolder}/_scripts/dev-runner.js\",\n      \"args\": [\"--remote-debug\"]\n    },\n    {\n      \"name\": \"Attach to renderer process (Electron)\",\n      \"type\": \"chrome\",\n      \"request\": \"attach\",\n      \"port\": 9223,\n      \"webRoot\": \"http://localhost:9080\",\n      \"sourceMapPathOverrides\": {\n        \"webpack://freetube/./~/*\": \"${workspaceFolder}/node_modules/*\",\n        \"webpack://freetube/./*\": \"${workspaceFolder}/*\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"stylelint.packageManager\": \"yarn\",\n  \"stylelint.snippet\": [\n      \"css\",\n      \"less\",\n      \"postcss\",\n      \"sass\",\n      \"scss\"\n  ],\n  \"stylelint.validate\": [\n      \"css\",\n      \"less\",\n      \"postcss\",\n      \"scss\"\n  ],\n  \"eslint.packageManager\": \"yarn\",\n  \"eslint.probe\": [\n      \"javascript\",\n      \"vue\",\n      \"json\",\n      \"jsonc\",\n      \"yml\",\n      \"yaml\"\n  ],\n  \"eslint.validate\": [\n    \"javascript\",\n    \"vue\",\n    \"json\",\n    \"jsonc\",\n    \"yml\",\n    \"yaml\"\n  ],\n  \"javascript.preferences.importModuleSpecifier\": \"relative\"\n}\n"
  },
  {
    "path": ".whitesource",
    "content": "##########################################################\n#### WhiteSource \"Bolt for Github\" configuration file ####\n##########################################################\n\n# Configuration #\n#---------------#\nws.repo.scan=true\nvulnerable.check.run.conclusion.level=failure\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Code Contributions\n\n## Before starting to code\n Please follow these guidelines before starting to code you feature or bugfix.\n * If you want to implement a bugfix or feature request from an existing issue, please comment on that issue that you will work on it. This helps us to coordinate what needs to be done and what not.\n * If you want to implement a feature request without an existing issue, please create an issue, so we know what you are working on and discuss the feature.\n * For major feature implementations make sure you are able to maintain your code in the future in regard to bugs and possible code conflicts in future updates. Optionally you could join the [Matrix](https://matrix.to/#/#freetube:matrix.org) channel, so you will hear instantly if something needs to be worked on. \n * Do not open pull requests that are primarily written by AI. It's a waste of our team's time. Repeat offenders will be banned.\n\n## Before your Pull Request\nPlease follow these guidelines before sending your pull request and making contributions.\n* When you submit a pull request, you agree that your code is published under the [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html)\n* Please link the issue you are referring to.\n* Do not include non-free software or modules with your code.\n* Make sure your pull request is set up to merge your branch to FreeTube's development branch.\n* Make sure your branch is up to date with the development branch before submitting your pull request.\n* Stick to a similar style of code already in the project.  Please look at current code to get an idea on how to do this.\n* Follow [ES6](https://rse.github.io/es6-features/) standards in your code. Ex: Use `let` and `const` instead of `var`. Do not use `function(response){//code}` for callbacks, use `(response) => {//code}`.\n* Comment your code when necessary.  Follow the [JavaScript Documentation and Comments Standard](https://www.drupal.org/docs/develop/standards/javascript/javascript-api-documentation-and-comment-standards) for functions.\n* Please follow proper Vue structure when creating new code / components.  Use existing code as well as the [Vue.js Guide](https://vuejs.org/guide/introduction.html) for reference.\n* Please test your code.  Make sure new features work as well as existing core features such as watching videos or loading subscriptions.  New features need to work with both the Local API as well as the Invidious API\n* Please make sure your code does not violate any standards set by our linter.  It's up to you to make fixes whenever necessary.  You can run `yarn run lint` to check locally and `yarn run lint-fix` to automatically fix smaller issues.\n* Please limit the amount of Node Modules that you introduce into the project.  Only include them when **absolutely necessary** for your code to work (Ex: Using nedb for databases) or if a module provides similar functionality to what you are trying to achieve (Ex: Using autolinker to create links to outside URLs instead of writing the functionality myself).\n* Please try to stay involved with the community and maintain your code.  We are only a handful of developers working on FreeTube in our spare time.  We do not have time to work on everything, and it would be nice if you can maintain your code when necessary.\n\n# Setting up Your Environment\n\nCheck out the [wiki](https://docs.freetubeapp.io/development/getting-started/) page to learn how to set up your environment and get started.\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n <img alt=\"\" src=\"/_icons/logoColor.svg\" width=500 align=\"center\">\n</p>\n\nFreeTube is an open source desktop YouTube player built with privacy in mind.\nUse YouTube without advertisements and prevent Google from tracking you with their cookies and JavaScript.\nAvailable for Windows (10 and later), Mac (macOS 12 and later) & Linux thanks to Electron.\n\n<p align=\"center\"><a href=\"https://github.com/FreeTubeApp/FreeTube/releases\">Download FreeTube</a></p>\n<p align=\"center\">\n  <a href=\"https://github.com/FreeTubeApp/FreeTube/actions/workflows/build.yml\">\n    <img alt='Build status' src=\"https://github.com/FreeTubeApp/FreeTube/actions/workflows/build.yml/badge.svg?branch=development\" />\n  </a>\n  <a href=\"https://hosted.weblate.org/engage/free-tube/\">\n    <img src=\"https://hosted.weblate.org/widgets/free-tube/-/svg-badge.svg\" alt=\"Translation status\" />\n  </a>\n</p>\n\n<hr>\n<p align=\"center\"><a href=\"#screenshots\">Screenshots</a> &bull; <a href=\"#how-does-it-work\">How does it work?</a> &bull; <a href=\"#features\">Features</a> &bull; <a href=\"#download-links\">Download Links</a> &bull; <a href=\"#contributing\">Contributing</a> &bull; <a href=\"#localization\">Localization</a> &bull; <a href=\"#contact\">Contact</a> &bull; <a href=\"#donate\">Donate</a> &bull; <a href=\"#license\">License</a></p>\n<p align=\"center\"><a href=\"https://freetubeapp.io/\">Website</a> &bull; <a href=\"https://blog.freetubeapp.io/\">Blog</a> &bull; <a href=\"https://docs.freetubeapp.io/\">Documentation</a> &bull; <a href=\"https://docs.freetubeapp.io/faq/\">FAQ</a> &bull; <a href=\"https://github.com/FreeTubeApp/FreeTube/discussions\">Discussions</a></p>\n<hr>\n\n> [!NOTE] \n> FreeTube is currently in Beta. While it should work well for most users, there are still bugs and missing features that need to be addressed.\n>\n> If you have an idea or if you found a bug, please submit a [GitHub issue](https://github.com/FreeTubeApp/FreeTube/issues/new/choose) so that we can track it.  Please [search the existing issues](https://github.com/FreeTubeApp/FreeTube/issues?q=is%3Aissue+sort%3Arelevance-desc) before submitting to prevent duplicates!\n\n## Screenshots\n| The main FreeTube window                                                                         |\n|--------------------------------------------------------------------------------------------------|\n| ![](https://raw.githubusercontent.com/FreeTubeApp/FreeTubeApp.io/master/src/images/FreeTube1.png)|\n\n| Watching a video                                                                                 |\n|--------------------------------------------------------------------------------------------------|\n| ![](https://raw.githubusercontent.com/FreeTubeApp/FreeTubeApp.io/master/src/images/FreeTube2.png)|\n\n| Settings                                                                                         |\n|--------------------------------------------------------------------------------------------------|\n| ![](https://raw.githubusercontent.com/FreeTubeApp/FreeTubeApp.io/master/src/images/FreeTube3.png)|\n\n## How does it work?\nFreeTube uses a built in extractor to grab and serve data / videos. The [Invidious API](https://github.com/iv-org/invidious) can also optionally be used. FreeTube does not use any official APIs to obtain data. While YouTube can still see your video requests, it can no\nlonger track you using cookies or JavaScript. Your subscriptions, playlists and history are stored locally on your computer and never sent out.\n\n> [!IMPORTANT]  \n> Using a VPN or Tor is highly recommended to hide your IP while using FreeTube.\n\n## Features\n* Watch videos without ads\n* Use YouTube without Google tracking you using cookies and JavaScript\n* Two extractor APIs to choose from (Built in or Invidious)\n* Subscribe to channels without an account\n* Connect to an externally setup proxy such as Tor\n* View and search your local subscriptions, playlists and history\n* Organize your subscriptions into \"Profiles\" to create a more focused feed\n* Export & import subscriptions\n* YouTube Trending\n* YouTube Chapters\n* Most popular videos page based on the set Invidious instance\n* SponsorBlock\n* DeArrow\n* Open videos from your browser directly into FreeTube (with extension)\n* Watch videos using an external player\n* Full Theme support\n* Make a screenshot of a video\n* Multiple windows\n* Mini Player (Picture-in-Picture)\n* Keyboard shortcuts\n* Option to show only family friendly content\n* Show/hide functionality or elements within the app using the distraction free settings\n* View channel posts\n\n### Browser Extensions\nThe following extensions open YouTube links directly in FreeTube:\n\n- [LibRedirect](https://libredirect.github.io/)\n- [RedirectTube](https://github.com/MStankiewiczOfficial/RedirectTube)\n\nLibRedirect automatically redirect YouTube links to FreeTube.\n> [!IMPORTANT]\n> To ensure proper functionality, select FreeTube as Frontend in the Services settings of the extension.\n\nRedirectTube, doesn’t automatically open YouTube links in FreeTube. Instead, it adds buttons to the toolbar and context menu, which you can click to open videos in FreeTube manually.\n\n- Download LibRedirect from [Mozilla Add-ons](https://addons.mozilla.org/firefox/addon/libredirect/) (for Firefox based-browsers) or [developer's website](https://libredirect.github.io/download_chromium.html) (for Chrome and Chromium-based browsers).\n\n- Download RedirectTube from [Mozilla Add-ons](https://addons.mozilla.org/firefox/addon/redirecttube/) (for Firefox based-browsers).\n\n> [!NOTE]\n> These extensions do not work on Linux portable builds!\n>\n> If you have issues with the extension working with FreeTube, please create an issue in this repository instead of the extension repository.\n\n## Download Links\n### Official Downloads\n\n> [!CAUTION]\n> FreeTube is only supported on Windows 10 and later, macOS 12 and above, and various Linux distributions. Installing it on unsupported systems may result in unexpected issues.\n\n* [GitHub Releases](https://github.com/FreeTubeApp/FreeTube/releases)\n\n* [FreeTube Website](https://freetubeapp.io/#download)\n\n* Flatpak on Flathub: [Download](https://flathub.org/apps/details/io.freetubeapp.FreeTube) and [Source Code](https://github.com/flathub/io.freetubeapp.FreeTube)\n\n#### Automated Builds (Nightly / Weekly)\n> [!WARNING]\n> Use these builds at your own risk. These are pre-release versions and are only intended for people that want to test changes early and are willing to accept that things could break from one build to another. \n\nBuilds are automatically created from changes to our development branch via [GitHub Actions](https://github.com/FreeTubeApp/FreeTube/actions?query=workflow%3ABuild).\n\nThe first build with a green check mark is the latest build.  \n\n> [!IMPORTANT]\n> You will need to have a GitHub account to download these builds.\n\n### Unofficial Downloads\n> [!WARNING]\n> These builds are maintained by the community. While they should be safe, download at your own risk. There may be issues with using these versus the official builds. Any issues specific with these builds should be sent to their respective maintainer. Make sure you always try an [official download](https://github.com/freetubeapp/freetube/#official-downloads) before reporting your issue to us!\n\n* Arch User Repository (AUR): [Download](https://aur.archlinux.org/packages/freetube-bin/)\n\n* Chocolatey: [Download](https://chocolatey.org/packages/freetube/)\n\n* FreeTubeAndroid (FreeTube port for Android and PWA): [Download](https://github.com/MarmadileManteater/FreeTubeAndroid/releases) and [Source Code](https://github.com/MarmadileManteater/FreeTubeAndroid)\n\n* Homebrew Formulae (Mac only): [Download for Apple Silicon](https://github.com/PikachuEXE/homebrew-FreeTube)\n\n* Nix Packages: [Download](https://search.nixos.org/packages?query=freetube)\n\n* PortableApps (Windows Only): [Download](https://github.com/rddim/FreeTubePortable/releases) and [Source Code](https://github.com/rddim/FreeTubePortable)\n\n* Scoop (Windows Only): [Usage](https://github.com/ScoopInstaller/Scoop)\n\n* Snap: [Download](https://snapcraft.io/freetube) and [Source Code](https://git.launchpad.net/freetube)\n\n* WAPT: [Download](https://wapt.tranquil.it/store/en/tis-freetube)\n\n* Windows Package Manager (winget): [Usage](https://docs.microsoft.com/en-us/windows/package-manager/winget/)\n\n## Contributing\nThank you very much to the [People and Projects](https://docs.freetubeapp.io/credits/) that make FreeTube possible!\n\nIf you like to get your hands dirty and want to contribute, we would love to\nhave your help.  Send a pull request and someone will review your code. \n\n> [!IMPORTANT]\n> Please follow the [Contribution Guidelines](https://github.com/FreeTubeApp/FreeTube/blob/development/CONTRIBUTING.md) before sending your pull request.\n\n## Localization\n<a href=\"https://hosted.weblate.org/engage/free-tube/\">\n<img src=\"https://hosted.weblate.org/widgets/free-tube/-/287x66-grey.png\" alt=\"Translation status\" />\n</a>\n\nWe are actively looking for translations!  We use [Weblate](https://hosted.weblate.org/engage/free-tube/) to make it easy for translators to get involved.  Click on the badge above to learn how to get involved.\n\nFor the Linux Flatpak, the desktop entry comment string can be translated at our [Flatpak repository](https://github.com/flathub/io.freetubeapp.FreeTube/blob/master/io.freetubeapp.FreeTube.desktop).\n\n## Contact\nIf you ever have any questions, feel free to ask it on our [Discussions](https://github.com/FreeTubeApp/FreeTube/discussions) page.  Alternatively, you can email us at FreeTubeApp@protonmail.com or you can join our [Matrix Room](https://matrix.to/#/#freetube:matrix.org).  \n\n> [!IMPORTANT]\n> Don't forget to check out the [rules](https://docs.freetubeapp.io/community/matrix/) before joining.\n\n## Donate\nIf you enjoy using FreeTube, you're welcome to leave a donation using the following method.  \n\n* Bitcoin Address: `1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS`\n\nWhile your donations are much appreciated, only donate if you really want to.  Donations are used for keeping the website up and running and eventual code signing costs. \n\n> [!TIP]\n> If you are using the Invidious API then we recommend that you donate to the instance that you use. You can also donate to the [Invidious team](https://invidious.io/donate/) or the [Local API developer](https://github.com/sponsors/LuanRT).\n\n## License\n[![GNU AGPLv3 Image](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.html)  \n\nFreeTube is Free Software: You can use, study share and improve it at your\nwill. Specifically you can redistribute and/or modify it under the terms of the\n[GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html) as\npublished by the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.  \n"
  },
  {
    "path": "_scripts/ProcessLocalesPlugin.js",
    "content": "const { existsSync, readFileSync } = require('fs')\nconst { readFile } = require('fs/promises')\nconst { join } = require('path')\nconst { brotliCompress, constants } = require('zlib')\nconst { promisify } = require('util')\nconst { load: loadYaml } = require('js-yaml')\n\nconst brotliCompressAsync = promisify(brotliCompress)\n\nconst PLUGIN_NAME = 'ProcessLocalesPlugin'\n\nclass ProcessLocalesPlugin {\n  constructor(options = {}) {\n    this.compress = !!options.compress\n    this.hotReload = !!options.hotReload\n\n    if (typeof options.inputDir !== 'string') {\n      throw new Error('ProcessLocalesPlugin: no input directory `inputDir` specified.')\n    } else if (!existsSync(options.inputDir)) {\n      throw new Error('ProcessLocalesPlugin: the specified input directory does not exist.')\n    }\n    this.inputDir = options.inputDir\n\n    if (typeof options.outputDir !== 'string') {\n      throw new Error('ProcessLocalesPlugin: no output directory `outputDir` specified.')\n    }\n    this.outputDir = options.outputDir\n\n    /** @type {Map<string, any>} */\n    this.locales = new Map()\n    this.localeNames = []\n\n    /** @type {Map<string, any>} */\n    this.cache = new Map()\n\n    this.filePaths = []\n    this.previousTimestamps = new Map()\n    this.startTime = Date.now()\n\n    /** @type {(updatedLocales: [string, string][]) => void|null} */\n    this.notifyLocaleChange = null\n\n    this.loadLocales()\n  }\n\n  /** @param {import('webpack').Compiler} compiler  */\n  apply(compiler) {\n    const { Compilation, DefinePlugin } = compiler.webpack\n\n    new DefinePlugin({\n      'process.env.HOT_RELOAD_LOCALES': this.hotReload\n    }).apply(compiler)\n\n    compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {\n      compilation.hooks.processAssets.tapPromise({\n        name: PLUGIN_NAME,\n        stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL\n      }, async (_assets) => {\n        // While running in the webpack dev server, this hook gets called for every incremental build.\n        // For incremental builds we can return the already processed versions, which saves time\n        // and makes webpack treat them as cached\n\n        /** @type {[string, string][]} */\n        const updatedLocales = []\n        if (this.hotReload && !this.notifyLocaleChange) {\n          console.warn('ProcessLocalesPlugin: Unable to live reload locales as `notifyLocaleChange` is not set.')\n        }\n\n        const promises = []\n        for (const [locale, data] of this.locales) {\n          promises.push(this.processLocale(locale, data, updatedLocales, compiler, compilation))\n        }\n\n        await Promise.all(promises)\n\n        if (this.hotReload && this.notifyLocaleChange && updatedLocales.length > 0) {\n          this.notifyLocaleChange(updatedLocales)\n        }\n      })\n    })\n\n    compiler.hooks.afterCompile.tap(PLUGIN_NAME, (compilation) => {\n      if (compiler.watching) {\n        // watch locale files for changes\n        compilation.fileDependencies.addAll(this.filePaths)\n      }\n    })\n  }\n\n  /**\n   * @param {string} locale\n   * @param {any} data\n   * @param {[string, string][]} updatedLocales\n   * @param {import('webpack').Compiler} compiler\n   * @param {import('webpack').Compilation} compilation\n   */\n  async processLocale(locale, data, updatedLocales, compiler, compilation) {\n    if (compiler.watching && compiler.fileTimestamps) {\n      const filePath = join(this.inputDir, `${locale}.yaml`)\n\n      const timestamp = compiler.fileTimestamps.get(filePath)?.safeTime\n\n      if (timestamp && timestamp > (this.previousTimestamps.get(locale) ?? this.startTime)) {\n        this.previousTimestamps.set(locale, timestamp)\n\n        const contents = await readFile(filePath, 'utf-8')\n        data = loadYaml(contents)\n      } else {\n        const { filename, source } = this.cache.get(locale)\n        compilation.emitAsset(filename, source, { minimized: true })\n        return\n      }\n    }\n\n    this.removeEmptyValues(data)\n\n    let filename = `${this.outputDir}/${locale}.json`\n    let output = JSON.stringify(data)\n\n    if (this.hotReload && compiler.fileTimestamps) {\n      updatedLocales.push([locale, output])\n    }\n\n    if (this.compress) {\n      filename += '.br'\n      output = await this.compressLocale(output)\n    }\n\n    let source = new compiler.webpack.sources.RawSource(output)\n\n    if (compiler.watching) {\n      source = new compiler.webpack.sources.CachedSource(source)\n      this.cache.set(locale, { filename, source })\n\n      // we don't need the unmodified sources anymore, as we use the cache `this.cache`\n      // so we can clear this to free some memory\n      this.locales.set(locale, null)\n    }\n\n    compilation.emitAsset(filename, source, { minimized: true })\n  }\n\n  loadLocales() {\n    const activeLocales = JSON.parse(readFileSync(`${this.inputDir}/activeLocales.json`))\n\n    for (const locale of activeLocales) {\n      const filePath = join(this.inputDir, `${locale}.yaml`)\n\n      this.filePaths.push(filePath)\n\n      const contents = readFileSync(filePath, 'utf-8')\n      const data = loadYaml(contents)\n      this.locales.set(locale, data)\n\n      this.localeNames.push(data['Locale Name'] ?? locale)\n    }\n  }\n\n  async compressLocale(data) {\n    const buffer = Buffer.from(data, 'utf-8')\n\n    return await brotliCompressAsync(buffer, {\n      params: {\n        [constants.BROTLI_PARAM_MODE]: constants.BROTLI_MODE_TEXT,\n        [constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,\n        [constants.BROTLI_PARAM_SIZE_HINT]: buffer.byteLength\n      }\n    })\n  }\n\n  /**\n   * vue-i18n doesn't fallback if the translation is an empty string\n   * so we want to get rid of them and also remove the empty objects that can get left behind\n   * if we've removed all the keys and values in them\n   * @param {object|string} data\n   */\n  removeEmptyValues(data) {\n    for (const key of Object.keys(data)) {\n      const value = data[key]\n      if (typeof value === 'object') {\n        this.removeEmptyValues(value)\n      }\n\n      if (!value || (typeof value === 'object' && Object.keys(value).length === 0)) {\n        delete data[key]\n      }\n    }\n  }\n}\n\nmodule.exports = ProcessLocalesPlugin\n"
  },
  {
    "path": "_scripts/_undefinedDefaultExport.mjs",
    "content": "export default undefined\n"
  },
  {
    "path": "_scripts/build.mjs",
    "content": "import { Arch, build, Platform } from 'electron-builder'\nimport config from './ebuilder.config.mjs'\n\nconst args = process.argv\n\n/** @type {Map<import('electron-builder').Platform, Map<import('electron-builder').Arch, Array<string>>>} */\nlet targets\nconst platform = process.platform\n\nif (platform === 'darwin') {\n  let arch = Arch.x64\n\n  if (args[2] === 'arm64') {\n    arch = Arch.arm64\n  }\n\n  targets = Platform.MAC.createTarget(['DMG', 'zip', '7z'], arch)\n} else if (platform === 'win32') {\n  let arch = Arch.x64\n\n  if (args[2] === 'arm64') {\n    arch = Arch.arm64\n  }\n\n  targets = Platform.WINDOWS.createTarget(['nsis', 'zip', '7z', 'portable'], arch)\n} else if (platform === 'linux') {\n  let arch = Arch.x64\n\n  if (args[2] === 'arm64') {\n    arch = Arch.arm64\n  }\n\n  if (args[2] === 'arm32') {\n    arch = Arch.armv7l\n  }\n\n  targets = Platform.LINUX.createTarget(['deb', 'zip', '7z', 'rpm', 'AppImage', 'pacman'], arch)\n}\n\nconst output = await build({ targets, config, publish: 'never' })\nconsole.log(output)\n"
  },
  {
    "path": "_scripts/clean.mjs",
    "content": "import { rm } from 'fs/promises'\nimport { join } from 'path'\n\nconst BUILD_PATH = join(import.meta.dirname, '..', 'build')\nconst DIST_PATH = join(import.meta.dirname, '..', 'dist')\n\nawait Promise.all([\n  rm(BUILD_PATH, { recursive: true, force: true }),\n  rm(DIST_PATH, { recursive: true, force: true })\n])\n"
  },
  {
    "path": "_scripts/dev-runner.js",
    "content": "process.env.NODE_ENV = 'development'\n\nconst electron = require('electron')\nconst webpack = require('webpack')\nconst WebpackDevServer = require('webpack-dev-server')\nconst kill = require('tree-kill')\n\nconst path = require('path')\nconst { spawn } = require('child_process')\n\nconst ProcessLocalesPlugin = require('./ProcessLocalesPlugin')\n\nlet electronProcess = null\nlet manualRestart = null\n\nconst remoteDebugging = process.argv.indexOf('--remote-debug') !== -1\nconst web = process.argv.indexOf('--web') !== -1\n\nlet mainConfig\nlet rendererConfig\nlet preloadConfig\nlet botGuardScriptConfig\nlet webConfig\nlet SHAKA_LOCALES_TO_BE_BUNDLED\n\nif (!web) {\n  mainConfig = require('./webpack.main.config')\n  rendererConfig = require('./webpack.renderer.config')\n  preloadConfig = require('./webpack.preload.config.js')\n  botGuardScriptConfig = require('./webpack.botGuardScript.config')\n\n  SHAKA_LOCALES_TO_BE_BUNDLED = rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED\n  delete rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED\n} else {\n  webConfig = require('./webpack.web.config')\n}\n\nif (remoteDebugging) {\n  // disable dvtools open in electron\n  process.env.RENDERER_REMOTE_DEBUGGING = true\n}\n\n// Define exit code for relaunch and set it in the environment\nconst relaunchExitCode = 69\nprocess.env.FREETUBE_RELAUNCH_EXIT_CODE = relaunchExitCode\n\nconst port = 9080\n\nasync function killElectron(pid) {\n  return new Promise((resolve, reject) => {\n    if (pid) {\n      kill(pid, err => {\n        if (err) reject(err)\n\n        resolve()\n      })\n    } else {\n      resolve()\n    }\n  })\n}\n\nasync function restartElectron() {\n  console.log('\\nStarting electron...')\n\n  const { pid } = electronProcess || {}\n  await killElectron(pid)\n\n  electronProcess = spawn(electron, [\n    path.join(__dirname, '../dist/main.js'),\n    // '--enable-logging', // Enable to show logs from all electron processes\n    remoteDebugging ? '--inspect=9222' : '',\n    remoteDebugging ? '--remote-debugging-port=9223' : ''\n  ],\n    // { stdio: 'inherit' } // required for logs to actually appear in the stdout\n  )\n\n  electronProcess.on('exit', (code, _) => {\n    if (code === relaunchExitCode) {\n      electronProcess = null\n      restartElectron()\n      return\n    }\n\n    if (!manualRestart) process.exit(0)\n  })\n}\n\n/**\n * @param {import('webpack').Compiler} compiler\n * @param {WebpackDevServer} devServer\n */\nfunction setupNotifyLocaleUpdate(compiler, devServer) {\n  const notifyLocaleChange = (updatedLocales) => {\n    devServer.sendMessage(devServer.webSocketServer.clients, 'freetube-locale-update', updatedLocales)\n  }\n\n  compiler.options.plugins\n    .filter(plugin => plugin instanceof ProcessLocalesPlugin)\n    .forEach((/** @type {ProcessLocalesPlugin} */plugin) => {\n      plugin.notifyLocaleChange = notifyLocaleChange\n    })\n}\n\nfunction startBotGuardScript() {\n  webpack(botGuardScriptConfig, (err) => {\n    if (err) console.error(err)\n\n    console.log(`\\nCompiled ${botGuardScriptConfig.name} script!`)\n  })\n}\n\nfunction startMain() {\n  const compiler = webpack(mainConfig)\n  const { name } = compiler\n\n  compiler.hooks.afterEmit.tap('afterEmit', async () => {\n    console.log(`\\nCompiled ${name} script!`)\n\n    manualRestart = true\n    await restartElectron()\n    setTimeout(() => {\n      manualRestart = false\n    }, 2500)\n\n    console.log(`\\nWatching file changes for ${name} script...`)\n  })\n\n  compiler.watch({\n    aggregateTimeout: 500,\n  },\n  err => {\n    if (err) console.error(err)\n  })\n}\n\nfunction startPreload() {\n  const compiler = webpack(preloadConfig)\n  const { name } = compiler\n\n  let firstTime = true\n\n  compiler.hooks.afterEmit.tap('afterEmit', async () => {\n    console.log(`\\nCompiled ${name} script!`)\n\n    if (firstTime) {\n      firstTime = false\n    } else {\n      manualRestart = true\n      await restartElectron()\n      setTimeout(() => {\n        manualRestart = false\n      }, 2500)\n    }\n\n    console.log(`\\nWatching file changes for ${name} script...`)\n  })\n\n  compiler.watch({\n    aggregateTimeout: 500,\n  },\n  err => {\n    if (err) console.error(err)\n  })\n}\n\nfunction startRenderer(callback) {\n  const compiler = webpack(rendererConfig)\n  const { name } = compiler\n\n  compiler.hooks.afterEmit.tap('afterEmit', () => {\n    console.log(`\\nCompiled ${name} script!`)\n    console.log(`\\nWatching file changes for ${name} script...`)\n  })\n\n  const server = new WebpackDevServer({\n    client: {\n      overlay: {\n        runtimeErrors: false\n      }\n    },\n    static: [\n      {\n        directory: path.resolve(__dirname, '..', 'static'),\n        watch: {\n          ignored: [\n            /(dashFiles|storyboards)\\/*/,\n            '/**/.DS_Store',\n            '**/static/locales/*'\n          ]\n        },\n        publicPath: '/static'\n      },\n      {\n        directory: path.resolve(__dirname, '..', 'node_modules', 'shaka-player', 'ui', 'locales'),\n        publicPath: '/static/shaka-player-locales',\n        watch: {\n          // Ignore everything that isn't one of the locales that we would bundle in production mode\n          ignored: `**/!(${SHAKA_LOCALES_TO_BE_BUNDLED.join('|')}).json`\n        }\n      }\n    ],\n    port\n  }, compiler)\n\n  server.startCallback(err => {\n    if (err) console.error(err)\n\n    setupNotifyLocaleUpdate(compiler, server)\n\n    callback()\n  })\n}\n\nfunction startWeb () {\n  const compiler = webpack(webConfig)\n  const { name } = compiler\n\n  compiler.hooks.afterEmit.tap('afterEmit', () => {\n    console.log(`\\nCompiled ${name} script!`)\n    console.log(`\\nWatching file changes for ${name} script...`)\n  })\n\n  const server = new WebpackDevServer({\n    open: true,\n    static: {\n      directory: path.resolve(__dirname, '..', 'static'),\n      watch: {\n        ignored: [\n          /(dashFiles|storyboards)\\/*/,\n          '/**/.DS_Store',\n          '**/static/locales/*'\n        ]\n      }\n    },\n    port\n  }, compiler)\n\n  server.startCallback(err => {\n    if (err) console.error(err)\n\n    setupNotifyLocaleUpdate(compiler, server)\n  })\n}\nif (!web) {\n  startRenderer(() => {\n    startBotGuardScript()\n    startPreload()\n    startMain()\n  })\n} else {\n  startWeb()\n}\n"
  },
  {
    "path": "_scripts/ebuilder.config.mjs",
    "content": "import packageDetails from '../package.json' with { type: 'json' }\n\n/** @type {import('electron-builder').Configuration} */\nexport default {\n  appId: `io.freetubeapp.${packageDetails.name}`,\n  copyright: 'Copyleft © 2020-2026 freetubeapp@protonmail.com',\n  // asar: false,\n  // compression: 'store',\n  productName: packageDetails.productName,\n  directories: {\n    output: './build/',\n  },\n  protocols: [\n    {\n      name: 'FreeTube',\n      schemes: [\n        'freetube'\n      ]\n    }\n  ],\n  files: [\n    '_icons/iconColor.*',\n    'icon.svg',\n    './dist/**/*',\n    '!dist/web/*',\n    '!node_modules/**/*',\n  ],\n\n  // As we bundle all dependecies with webpack, the `node_modules` folder is excluded from packaging in the `files` array.\n  // electron-builder will however still spend time scanning the `node_modules` folder and building up a list of dependencies,\n  // returning `false` from the `beforeBuild` hook skips that.\n  beforeBuild: () => Promise.resolve(false),\n  dmg: {\n    contents: [\n      {\n        path: '/Applications',\n        type: 'link',\n        x: 410,\n        y: 230,\n      },\n      {\n        type: 'file',\n        x: 130,\n        y: 230,\n      },\n    ],\n    window: {\n      height: 380,\n      width: 540,\n    }\n  },\n  linux: {\n    category: 'Network',\n    icon: '_icons/icon.svg',\n    target: ['deb', 'zip', '7z', 'rpm', 'AppImage', 'pacman'],\n  },\n  // See the following issues for more information\n  // https://github.com/jordansissel/fpm/issues/1503\n  // https://github.com/jgraph/drawio-desktop/issues/259\n  rpm: {\n    fpm: ['--rpm-rpmbuild-define=_build_id_links none']\n  },\n  deb: {\n    depends: [\n      'libgtk-3-0',\n      'libnotify4',\n      'libnss3',\n      'libxss1',\n      'libxtst6',\n      'xdg-utils',\n      'libatspi2.0-0',\n      'libuuid1',\n      'libsecret-1-0'\n    ]\n  },\n  mac: {\n    category: 'public.app-category.utilities',\n    icon: '_icons/iconMac.icns',\n    target: ['dmg', 'zip', '7z'],\n    type: 'distribution',\n    extendInfo: {\n      CFBundleURLTypes: [\n        'freetube'\n      ],\n      CFBundleURLSchemes: [\n        'freetube'\n      ],\n\n      // Clear the default usage descriptions in the Info.plist file set by Electron that we don't need\n      // see: https://github.com/electron/electron/blob/main/shell/browser/resources/mac/Info.plist\n      NSAudioCaptureUsageDescription: undefined,\n      NSBluetoothAlwaysUsageDescription: undefined,\n      NSBluetoothPeripheralUsageDescription: undefined,\n      NSCameraUsageDescription: undefined,\n      NSMicrophoneUsageDescription: undefined,\n    }\n  },\n  win: {\n    icon: '_icons/icon.ico',\n    target: ['nsis', 'zip', '7z', 'portable'],\n  },\n  nsis: {\n    allowToChangeInstallationDirectory: true,\n    oneClick: false,\n  },\n}\n"
  },
  {
    "path": "_scripts/eslint-rules/plugin.mjs",
    "content": "import preferUseI18nPolyfillRule from './prefer-use-i18n-polyfill-rule.mjs'\n\nexport default {\n  meta: {\n    name: 'eslint-plugin-freetube',\n    version: '1.0'\n  },\n  rules: {\n    'prefer-use-i18n-polyfill': preferUseI18nPolyfillRule\n  }\n}\n"
  },
  {
    "path": "_scripts/eslint-rules/prefer-use-i18n-polyfill-rule.mjs",
    "content": "import { dirname, relative, resolve } from 'path'\n\nconst polyfillPath = resolve(import.meta.dirname, '../../src/renderer/composables/use-i18n-polyfill')\n\nfunction getRelativePolyfillPath(filePath) {\n  const relativePath = relative(dirname(filePath), polyfillPath).replaceAll('\\\\', '/')\n\n  if (relativePath[0] !== '.') {\n    return `./${relativePath}`\n  }\n\n  return relativePath\n}\n\n/** @type {import('eslint').Rule.RuleModule} */\nexport default {\n  meta: {\n    type: 'problem',\n    fixable: 'code'\n  },\n  create(context) {\n    return {\n      'ImportDeclaration[source.value=\"vue-i18n\"]'(node) {\n        const specifierIndex = node.specifiers.findIndex(specifier => specifier.type === 'ImportSpecifier' && specifier.imported.name === 'useI18n')\n\n        if (specifierIndex !== -1) {\n          context.report({\n            node: node.specifiers.length === 1 ? node : node.specifiers[specifierIndex],\n            message: \"Please use FreeTube's useI18n polyfill, as vue-i18n's useI18n composable does not work when the vue-i18n is in legacy mode, which is needed for components using the Options API.\",\n            fix: context.physicalFilename === '<text>'\n              ? undefined\n              : (fixer) => {\n                  const relativePath = getRelativePolyfillPath(context.physicalFilename)\n\n                  // If the import only imports `useI18n`, we can just update the source/from text\n                  // Else we need to create a new import for `useI18n` and remove useI18n from the original one\n                  if (node.specifiers.length === 1) {\n                    return fixer.replaceText(node.source, `'${relativePath}'`)\n                  } else {\n                    const specifier = node.specifiers[specifierIndex]\n\n                    let specifierText = 'useI18n'\n\n                    if (specifier.imported.name !== specifier.local.name) {\n                      specifierText += ` as ${specifier.local.name}`\n                    }\n\n                    return [\n                      fixer.removeRange([\n                        specifierIndex === 0 ? specifier.start : node.specifiers[specifierIndex - 1].end,\n                        specifierIndex === node.specifiers.length - 1 ? specifier.end : node.specifiers[specifierIndex + 1].start\n                      ]),\n                      fixer.insertTextAfter(node, `\\nimport { ${specifierText} } from '${relativePath}'`)\n                    ]\n                  }\n                }\n          })\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "_scripts/findMissingTemplates.mjs",
    "content": "import { readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { load as loadYaml } from 'js-yaml'\n\nconst localesPath = join(import.meta.dirname, '..', 'static', 'locales')\nconst defaultLocale = 'en-US.yaml'\n\nconst errors = [\n\n]\n\nconst defaultData = loadYaml(readFileSync(`${localesPath}/${defaultLocale}`, { encoding: 'utf-8' }))\nconst defaultKeys = Object.keys(defaultData)\n\nconst filesInLocaleDir = readdirSync(localesPath)\n\nfor (const file of filesInLocaleDir) {\n  if (file !== defaultLocale && file.endsWith('.yaml')) {\n    const fileData = loadYaml(readFileSync(`${localesPath}/${file}`, { encoding: 'utf-8' }))\n    const fileDataKeys = Object.keys(fileData)\n    addErrors(defaultData, fileData, defaultKeys, fileDataKeys, file)\n  }\n}\n\nwriteFileSync('locale-errors.json', JSON.stringify(errors, null, 2))\n\nif (errors.length > 0) {\n  console.error(errors)\n} else {\n  console.log('no issues found')\n}\n\n/**\n * @param {unknown} originalData - data from en-US converted to a JavaScript object\n * @param {unknown} newData - data from the file we are analyzing converted to a JavaScript object\n * @param {string[]} originalKeys - keys from en-US file\n * @param {string[]} newKeys - keys from the file we are currently analyzing\n * @param {string} file - the file we are currently analyzing\n */\nfunction addErrors(originalData, newData, originalKeys, newKeys, file) {\n  newKeys.forEach(newKey => {\n    if (originalKeys.includes(newKey)) {\n      if (typeof originalData[newKey] === 'object') {\n        addErrors(originalData[newKey], newData[newKey], Object.keys(originalData[newKey]), Object.keys(newData[newKey]), file)\n      } else if (isMissingInterpolation(originalData[newKey], newData[newKey], file)) {\n        errors.push({ fileName: file, error: 'value is missing a template or has an extra template', key: newKey, defaultValue: originalData[newKey], value: newData[newKey] })\n      }\n    } else {\n      // The key doesn't exist in the en-US file but exists in current yaml file.\n      // We should go through this eventually but it's not as important as invalid templates\n\n      // errors.push({ fileName: file, error: 'extra key found', key: fdk })\n    }\n  })\n}\n\n/**\n *\n * @param {String} defaultValue\n * @param {String} otherValue\n */\nfunction isMissingInterpolation(defaultValue, otherValue, filename) {\n  if (otherValue === '') {\n    // not translated yet, we don't care\n    return false\n  }\n  const defaultMatches = Array.from(new Set(defaultValue.match(/{[^}]*}/g)))\n  const otherMatches = Array.from(new Set(otherValue.match(/{[^}]*}/g)))\n\n  if (defaultMatches) {\n    if (!otherMatches) {\n      // no templates found.\n      return true\n    }\n    defaultMatches.sort()\n    otherMatches.sort()\n\n    const defaultMatchesStringified = JSON.stringify(defaultMatches)\n    const otherMatchesStringified = JSON.stringify(otherMatches)\n    // check if templates match.\n    return defaultMatchesStringified !== otherMatchesStringified\n  } else if (otherMatches) {\n    // extra template found\n    return true\n  }\n}\n"
  },
  {
    "path": "_scripts/getInstances.js",
    "content": "const fs = require('fs/promises')\nconst invidiousApiUrl = 'https://api.invidious.io/instances.json'\n\nfetch(invidiousApiUrl).then(e => e.json()).then(res => {\n  const data = res.filter((instance) => {\n    return !(instance[0].includes('.onion') ||\n      instance[0].includes('.i2p') ||\n      !instance[1].api)\n  }).map((instance) => {\n    return {\n      url: instance[1].uri.replace(/\\/$/, ''),\n      cors: instance[1].cors\n    }\n  })\n  fs.writeFile('././static/invidious-instances.json', JSON.stringify(data, null, 2))\n})\n"
  },
  {
    "path": "_scripts/getRegions.mjs",
    "content": "/**\n * This script updates the files in static/geolocations with the available locations on YouTube.\n *\n * It tries to map every active FreeTube language (static/locales/activelocales.json)\n * to it's equivalent on YouTube.\n *\n * It then uses those language mappings,\n * to scrape the location selection menu on the YouTube website, in every mapped language.\n *\n * All languages it couldn't find on YouTube, that don't have manually added mapping,\n * get logged to the console, as well as all unmapped YouTube languages.\n */\n\nimport { mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'\nimport { Innertube, Misc } from 'youtubei.js'\n\nconst STATIC_DIRECTORY = `${import.meta.dirname}/../static`\n\nconst activeLanguagesPath = `${STATIC_DIRECTORY}/locales/activeLocales.json`\n/** @type {string[]} */\nconst activeLanguages = JSON.parse(readFileSync(activeLanguagesPath, { encoding: 'utf8' }))\n\n// en-US is en on YouTube\nconst initialResponse = await scrapeLanguage('en')\n\n// Scrape language menu in en-US\n\n/** @type {string[]} */\nconst youTubeLanguages = initialResponse.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items[2].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items\n  .map(({ compactLinkRenderer }) => {\n    return compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].selectLanguageCommand.hl\n  })\n\n// map FreeTube languages to their YouTube equivalents\n\nconst foundLanguageNames = ['en-US']\nconst unusedYouTubeLanguageNames = []\nconst languagesToScrape = []\n\nfor (const language of youTubeLanguages) {\n  if (activeLanguages.includes(language)) {\n    foundLanguageNames.push(language)\n    languagesToScrape.push({\n      youTube: language,\n      freeTube: language\n    })\n  // eslint-disable-next-line @stylistic/brace-style\n  }\n  // special cases\n  else if (language === 'de') {\n    foundLanguageNames.push('de-DE')\n    languagesToScrape.push({\n      youTube: 'de',\n      freeTube: 'de-DE'\n    })\n  } else if (language === 'fr') {\n    foundLanguageNames.push('fr-FR')\n    languagesToScrape.push({\n      youTube: 'fr',\n      freeTube: 'fr-FR'\n    })\n  } else if (language === 'no') {\n    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n    // \"no\" is the macro language for \"nb\" and \"nn\"\n    foundLanguageNames.push('nb-NO', 'nn')\n    languagesToScrape.push({\n      youTube: 'no',\n      freeTube: 'nb-NO'\n    })\n    languagesToScrape.push({\n      youTube: 'no',\n      freeTube: 'nn'\n    })\n  } else if (language === 'iw') {\n    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n    // \"iw\" is the old/original code for Hebrew, these days it's \"he\"\n    foundLanguageNames.push('he')\n    languagesToScrape.push({\n      youTube: 'iw',\n      freeTube: 'he'\n    })\n  } else if (language === 'es-419') {\n    foundLanguageNames.push('es-AR', 'es-MX')\n    languagesToScrape.push({\n      youTube: 'es-419',\n      freeTube: 'es-AR'\n    })\n    languagesToScrape.push({\n      youTube: 'es-419',\n      freeTube: 'es-MX'\n    })\n  } else if (language !== 'en') {\n    unusedYouTubeLanguageNames.push(language)\n  }\n}\n\nfoundLanguageNames.push('pt-BR')\nlanguagesToScrape.push({\n  youTube: 'pt',\n  freeTube: 'pt-BR'\n})\n\nconsole.log(\"Active FreeTube languages that aren't available on YouTube:\")\nconsole.log(activeLanguages.filter(lang => !foundLanguageNames.includes(lang)).sort())\n\nconsole.log(\"YouTube languages that don't have an equivalent active FreeTube language:\")\nconsole.log(unusedYouTubeLanguageNames.sort())\n\n// Scrape the location menu in various languages and write files to the file system\n\nrmSync(`${STATIC_DIRECTORY}/geolocations`, { recursive: true })\nmkdirSync(`${STATIC_DIRECTORY}/geolocations`)\n\nprocessGeolocations('en-US', 'en', initialResponse)\n\nfor (const { youTube, freeTube } of languagesToScrape) {\n  const response = await scrapeLanguage(youTube)\n\n  processGeolocations(freeTube, youTube, response)\n}\n\n/**\n * @param {string} youTubeLanguageCode\n */\nasync function scrapeLanguage(youTubeLanguageCode) {\n  const session = await Innertube.create({\n    retrieve_player: false,\n    generate_session_locally: true,\n    lang: youTubeLanguageCode\n  })\n\n  return await session.actions.execute('/account/account_menu')\n}\n\n/**\n * @param {string} freeTubeLanguage\n * @param {string} youTubeLanguage\n * @param {import('youtubei.js').ApiResponse} response\n */\nfunction processGeolocations(freeTubeLanguage, youTubeLanguage, response) {\n  /** @type {{ name: string, code: string }[]} */\n  const geolocations = response.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items[4].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items\n    .map(({ compactLinkRenderer }) => {\n      return {\n        name: new Misc.Text(compactLinkRenderer.title).toString().trim(),\n        code: compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].selectCountryCommand.gl\n      }\n    })\n\n  const normalisedFreeTubeLanguage = freeTubeLanguage.replace('_', '-')\n\n  // give Intl.Collator 4 locales, in the hopes that it supports one of them\n  // deduplicate the list so it doesn't have to do duplicate work\n  const localeSet = new Set()\n  localeSet.add(normalisedFreeTubeLanguage)\n  localeSet.add(youTubeLanguage)\n  localeSet.add(normalisedFreeTubeLanguage.split('-')[0])\n  localeSet.add(youTubeLanguage.split('-')[0])\n\n  const locales = Array.from(localeSet)\n\n  // only sort if node supports sorting the language, otherwise hope that YouTube's sorting was correct\n  // node 20.3.1 doesn't support sorting `eu`\n  if (Intl.Collator.supportedLocalesOf(locales).length > 0) {\n    const collator = new Intl.Collator(locales)\n\n    geolocations.sort((a, b) => collator.compare(a.name, b.name))\n  }\n\n  const output = {\n    names: geolocations.map(entry => entry.name),\n    codes: geolocations.map(entry => entry.code)\n  }\n\n  writeFileSync(`${STATIC_DIRECTORY}/geolocations/${freeTubeLanguage}.json`, JSON.stringify(output))\n}\n"
  },
  {
    "path": "_scripts/getShakaLocales.js",
    "content": "const { readFileSync, readdirSync } = require('fs')\nconst { join } = require('path')\n\nfunction getPreloadedLocales() {\n  const localesFile = readFileSync(join(__dirname, '../node_modules/shaka-player/dist/locales.js'), 'utf-8')\n\n  const localesLine = localesFile.match(/^\\/\\/ LOCALES: ([\\w ,-]+)$/m)\n\n  if (!localesLine) {\n    throw new Error(\"Failed to parse shaka-player's preloaded locales\")\n  }\n\n  return localesLine[1].split(',').map(locale => locale.trim())\n}\n\nfunction getAllLocales() {\n  const filenames = readdirSync(join(__dirname, '../node_modules/shaka-player/ui/locales'))\n\n  return new Set(filenames\n    .filter(filename => filename !== 'source.json' && filename.endsWith('.json'))\n    .map(filename => filename.replace('.json', '')))\n}\n\n/**\n * Maps the shaka locales to FreeTube's active ones\n * This allows us to know which locale files are actually needed\n * and which shaka locale needs to be activated for a given FreeTube one.\n * @param {Set<string>} shakaLocales\n * @param {string[]} freeTubeLocales\n */\nfunction getMappings(shakaLocales, freeTubeLocales) {\n  /**\n   * @type {[string, string][]}\n   * Using this structure as it gets passed to `new Map()` in the player component\n   * The first element is the FreeTube locale, the second one is the shaka-player one\n   */\n  const mappings = []\n\n  for (const locale of freeTubeLocales) {\n    if (shakaLocales.has(locale)) {\n      mappings.push([\n        locale,\n        locale\n      ])\n    } else if (shakaLocales.has(locale.split('-')[0])) {\n      mappings.push([\n        locale,\n        locale.split('-')[0]\n      ])\n    }\n  }\n\n  // special cases\n\n  mappings.push(\n    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n    // \"no\" is the macro language for \"nb\" and \"nn\"\n    [\n      'nb-NO',\n      'no'\n    ],\n    [\n      'nn',\n      'no'\n    ],\n\n    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n    // \"iw\" is the old/original code for Hebrew, these days it's \"he\"\n    [\n      'he',\n      'iw'\n    ],\n\n    // not sure why we have pt, pt-PT and pt-BR in the FreeTube locales\n    // as pt and pt-PT are the same thing, but we should handle it here anyway\n    [\n      'pt',\n      'pt-PT'\n    ]\n  )\n\n  return mappings\n}\n\nfunction getShakaLocales() {\n  const shakaLocales = getAllLocales()\n\n  /** @type {string[]} */\n  const freeTubeLocales = JSON.parse(readFileSync(join(__dirname, '../static/locales/activeLocales.json'), 'utf-8'))\n\n  const mappings = getMappings(shakaLocales, freeTubeLocales)\n\n  const preloaded = getPreloadedLocales()\n\n  const shakaMappings = mappings.map(mapping => mapping[1])\n\n  // use a set to deduplicate the list\n  // we don't need to bundle any locale files that are already embedded in shaka-player/preloaded\n\n  /** @type {string[]} */\n  const toBeBundled = [...new Set(shakaMappings.filter(locale => !preloaded.includes(locale)))]\n\n  return {\n    SHAKA_LOCALE_MAPPINGS: mappings,\n    SHAKA_LOCALES_PREBUNDLED: preloaded,\n    SHAKA_LOCALES_TO_BE_BUNDLED: toBeBundled\n  }\n}\n\nmodule.exports = getShakaLocales()\n"
  },
  {
    "path": "_scripts/injectAllowedPaths.mjs",
    "content": "/**\n * Injects the paths that the renderer process is allowed to read into the main.js file,\n * by replacing __FREETUBE_ALLOWED_PATHS__ with an array of strings with the paths.\n *\n * This allows the main process to validate the paths which the renderer process accesses,\n * to ensure that it cannot access other files on the disk, without the users permission (e.g. file picker).\n */\nimport { closeSync, ftruncateSync, openSync, readFileSync, readdirSync, writeSync } from 'fs'\nimport { join, relative, resolve } from 'path'\n\nconst distDirectory = resolve(import.meta.dirname, '..', 'dist')\nconst webDirectory = join(distDirectory, 'web')\n\nconst paths = readdirSync(distDirectory, {\n  recursive: true,\n  withFileTypes: true\n})\n  .filter(dirent => {\n    // only include files not directories\n    return dirent.isFile() &&\n      // disallow the renderer process/browser windows to read the main.js file\n      dirent.name !== 'main.js' &&\n      dirent.name !== 'main.js.LICENSE.txt' &&\n      // disallow the renderer process/browser windows to read the preload.js file\n      dirent.name !== 'preload.js' &&\n      // disallow the renderer process/browser windows to read the botGuardScript.js file\n      dirent.name !== 'botGuardScript.js' &&\n      // filter out any web build files, in case the dist directory contains a web build\n      !dirent.parentPath.startsWith(webDirectory)\n  })\n  .map(dirent => {\n    const joined = join(dirent.parentPath, dirent.name)\n    return '/' + relative(distDirectory, joined).replaceAll('\\\\', '/')\n  })\n\nlet fileHandle\ntry {\n  fileHandle = openSync(join(distDirectory, 'main.js'), 'r+')\n\n  let contents = readFileSync(fileHandle, 'utf-8')\n\n  contents = contents.replace('__FREETUBE_ALLOWED_PATHS__', JSON.stringify(paths))\n\n  ftruncateSync(fileHandle)\n  writeSync(fileHandle, contents, 0, 'utf-8')\n} finally {\n  if (typeof fileHandle !== 'undefined') {\n    closeSync(fileHandle)\n  }\n}\n"
  },
  {
    "path": "_scripts/mime-db-shrinking-loader.js",
    "content": "/**\n * electron-context-menu only needs mime-db for its save as feature.\n * As we only activate save image and save as image features, we can remove all other mimetypes,\n * as they will never get used.\n * Which results in quite a significant reduction in file size.\n * @param {string} source\n */\nmodule.exports = function (source) {\n  const original = JSON.parse(source)\n\n  // Only the extensions field is needed, see: https://github.com/kevva/ext-list/blob/v2.2.2/index.js\n\n  return JSON.stringify({\n    'image/apng': { extensions: original['image/apng'].extensions },\n    'image/avif': { extensions: original['image/avif'].extensions },\n    'image/gif': { extensions: original['image/gif'].extensions },\n    'image/jpeg': { extensions: original['image/jpeg'].extensions },\n    'image/png': { extensions: original['image/png'].extensions },\n    'image/svg+xml': { extensions: original['image/svg+xml'].extensions },\n    'image/webp': { extensions: original['image/webp'].extensions }\n  })\n}\n"
  },
  {
    "path": "_scripts/patch-shaka-player-loader.js",
    "content": "/**\n * fixes shaka-player referencing the Roboto font on google fonts in its CSS\n * by updating the CSS to point to the local Roboto font\n * @param {string} source\n */\nmodule.exports = function (source) {\n  return source.replace(/@font-face{font-family:Roboto;[^}]+}/, '')\n}\n"
  },
  {
    "path": "_scripts/sigFrameConfig.js",
    "content": "const { hash } = require('crypto')\nconst { join } = require('path')\nconst { readFileSync } = require('fs')\n\nconst path = join(__dirname, '../src/renderer/sigFrameScript.js')\nconst rawScript = readFileSync(path, 'utf8')\n\nconst script = require('terser').minify_sync({ [path]: rawScript }).code\n\nmodule.exports.sigFrameTemplateParameters = {\n  sigFrameSrc: `data:text/html,${encodeURIComponent(`<!doctype html><script>${script}</script>`)}`,\n  sigFrameCspHash: `sha512-${hash('sha512', script, 'base64')}`\n}\n"
  },
  {
    "path": "_scripts/webpack.botGuardScript.config.js",
    "content": "const path = require('path')\n\n/** @type {import('webpack').Configuration} */\nmodule.exports = {\n  name: 'botGuardScript',\n  // Always use production mode, as we use the output as a function body and the debug output doesn't work for that\n  mode: 'production',\n  devtool: false,\n  target: 'web',\n  entry: {\n    botGuardScript: path.join(__dirname, '../src/botGuardScript.js'),\n  },\n  output: {\n    filename: '[name].js',\n    path: path.join(__dirname, '../dist'),\n    library: {\n      type: 'modern-module'\n    }\n  },\n  experiments: {\n    outputModule: true\n  }\n}\n"
  },
  {
    "path": "_scripts/webpack.main.config.js",
    "content": "const path = require('path')\nconst webpack = require('webpack')\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\nconst JsonMinimizerPlugin = require('json-minimizer-webpack-plugin')\n\nconst isDevMode = process.env.NODE_ENV === 'development'\n\n/** @type {import('webpack').Configuration} */\nconst config = {\n  name: 'main',\n  mode: process.env.NODE_ENV,\n  devtool: isDevMode ? 'eval-cheap-module-source-map' : false,\n  entry: {\n    main: path.join(__dirname, '../src/main/index.js'),\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        use: 'babel-loader',\n        exclude: /node_modules/,\n      },\n      {\n        resource: path.resolve(__dirname, '../node_modules/mime-db/db.json'),\n        use: path.join(__dirname, 'mime-db-shrinking-loader.js')\n      }\n    ],\n    generator: {\n      json: {\n        JSONParse: false\n      }\n    }\n  },\n  // webpack defaults to only optimising the production builds, so having this here is fine\n  optimization: {\n    minimizer: [\n      '...', // extend webpack's list instead of overwriting it\n      new JsonMinimizerPlugin({\n        exclude: /\\/locales\\/.*\\.json/\n      })\n    ]\n  },\n  node: {\n    __dirname: isDevMode,\n    __filename: isDevMode\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      'process.platform': `'${process.platform}'`,\n      'process.env.IS_ELECTRON_MAIN': true\n    })\n  ],\n  output: {\n    filename: '[name].js',\n    libraryTarget: 'commonjs2',\n    path: path.join(__dirname, '../dist'),\n  },\n  target: 'electron-main',\n}\n\nif (!isDevMode) {\n  config.plugins.push(\n    new CopyWebpackPlugin({\n      patterns: [\n        {\n          from: path.join(__dirname, '../static'),\n          to: path.join(__dirname, '../dist/static'),\n          globOptions: {\n            dot: true,\n            ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/manifest.json', '**/dashFiles/**', '**/storyboards/**'],\n          },\n        },\n      ]\n    })\n  )\n}\n\nmodule.exports = config\n"
  },
  {
    "path": "_scripts/webpack.preload.config.js",
    "content": "const path = require('path')\n\nconst isDevMode = process.env.NODE_ENV === 'development'\n\n/** @type {import('webpack').Configuration} */\nconst config = {\n  name: 'preload',\n  mode: process.env.NODE_ENV,\n  devtool: isDevMode ? 'eval-cheap-module-source-map' : false,\n  entry: {\n    preload: path.join(__dirname, '../src/preload/main.js'),\n  },\n  infrastructureLogging: {\n    // Only warnings and errors\n    // level: 'none' disable logging\n    // Please read https://webpack.js.org/configuration/other-options/#infrastructurelogginglevel\n    level: isDevMode ? 'info' : 'none'\n  },\n  output: {\n    path: path.join(__dirname, '../dist'),\n    filename: '[name].js'\n  },\n  externals: [\n    'electron/renderer'\n  ],\n  externalsType: 'commonjs',\n  node: {\n    __dirname: false,\n    __filename: false\n  },\n  target: 'electron-preload',\n}\n\nmodule.exports = config\n"
  },
  {
    "path": "_scripts/webpack.renderer.config.js",
    "content": "const path = require('path')\nconst { readFileSync, readdirSync } = require('fs')\nconst webpack = require('webpack')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst { VueLoaderPlugin } = require('vue-loader')\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin')\nconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin')\nconst ProcessLocalesPlugin = require('./ProcessLocalesPlugin')\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\nconst {\n  SHAKA_LOCALE_MAPPINGS,\n  SHAKA_LOCALES_PREBUNDLED,\n  SHAKA_LOCALES_TO_BE_BUNDLED\n} = require('./getShakaLocales')\nconst { sigFrameTemplateParameters } = require('./sigFrameConfig')\n\nconst isDevMode = process.env.NODE_ENV === 'development'\n\nconst { version: swiperVersion } = JSON.parse(readFileSync(path.join(__dirname, '../node_modules/swiper/package.json')))\n\nconst processLocalesPlugin = new ProcessLocalesPlugin({\n  compress: !isDevMode,\n  hotReload: isDevMode,\n  inputDir: path.join(__dirname, '../static/locales'),\n  outputDir: 'static/locales',\n})\n\n/** @type {import('webpack').Configuration} */\nconst config = {\n  name: 'renderer',\n  mode: process.env.NODE_ENV,\n  devtool: isDevMode ? 'eval-cheap-module-source-map' : false,\n  entry: {\n    renderer: path.join(__dirname, '../src/renderer/main.js'),\n  },\n  infrastructureLogging: {\n    // Only warnings and errors\n    // level: 'none' disable logging\n    // Please read https://webpack.js.org/configuration/other-options/#infrastructurelogginglevel\n    level: isDevMode ? 'info' : 'none'\n  },\n  output: {\n    scriptType: 'text/javascript',\n    path: path.join(__dirname, '../dist'),\n    filename: '[name].js',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        use: 'babel-loader',\n        exclude: /node_modules/,\n      },\n      {\n        test: /\\.vue$/,\n        loader: 'vue-loader',\n        options: {\n          compilerOptions: {\n            isCustomElement: (tag) => tag === 'swiper-container' || tag === 'swiper-slide'\n          }\n        }\n      },\n      {\n        test: /\\.scss$/,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader,\n          },\n          {\n            loader: 'css-loader',\n            options: {\n              esModule: false\n            }\n          },\n          {\n            loader: 'sass-loader',\n            options: {\n              implementation: require('sass')\n            }\n          },\n        ],\n      },\n      {\n        test: /\\.css$/,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader\n          },\n          {\n            loader: 'css-loader',\n            options: {\n              esModule: false\n            }\n          }\n        ],\n        rules: [\n          {\n            resource: path.resolve(__dirname, '../node_modules/shaka-player/dist/controls.css'),\n            use: path.join(__dirname, 'patch-shaka-player-loader.js')\n          }\n        ],\n      },\n      {\n        test: /\\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\\?.*)?$/,\n        type: 'asset/resource',\n        generator: {\n          filename: 'imgs/[name][ext]'\n        }\n      },\n      {\n        test: /\\.(woff2?|eot|ttf|otf)(\\?.*)?$/,\n        type: 'asset/resource',\n        generator: {\n          filename: 'fonts/[name][ext]'\n        }\n      },\n    ],\n    generator: {\n      json: {\n        JSONParse: false\n      }\n    }\n  },\n  // webpack defaults to only optimising the production builds, so having this here is fine\n  optimization: {\n    minimizer: [\n      '...', // extend webpack's list instead of overwriting it\n      new CssMinimizerPlugin()\n    ]\n  },\n  node: {\n    __dirname: false,\n    __filename: false\n  },\n  plugins: [\n    processLocalesPlugin,\n    new webpack.DefinePlugin({\n      'process.platform': `'${process.platform}'`,\n      'process.env.IS_ELECTRON': true,\n      'process.env.IS_ELECTRON_MAIN': false,\n      'process.env.SUPPORTS_LOCAL_API': true,\n      __VUE_OPTIONS_API__: 'true',\n      __VUE_PROD_DEVTOOLS__: 'false',\n      __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',\n      __VUE_I18N_LEGACY_API__: 'true',\n      __VUE_I18N_FULL_INSTALL__: 'false',\n      __INTLIFY_PROD_DEVTOOLS__: 'false',\n      'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames),\n      'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))),\n      'process.env.SWIPER_VERSION': `'${swiperVersion}'`,\n      'process.env.SHAKA_LOCALE_MAPPINGS': JSON.stringify(SHAKA_LOCALE_MAPPINGS),\n      'process.env.SHAKA_LOCALES_PREBUNDLED': JSON.stringify(SHAKA_LOCALES_PREBUNDLED)\n    }),\n    new HtmlWebpackPlugin({\n      filename: 'index.html',\n      template: path.resolve(__dirname, '../src/index.ejs'),\n      templateParameters: sigFrameTemplateParameters\n    }),\n    new VueLoaderPlugin(),\n    new MiniCssExtractPlugin({\n      filename: isDevMode ? '[name].css' : '[name].[contenthash].css',\n      chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css',\n    }),\n    new CopyWebpackPlugin({\n      patterns: [\n        {\n          from: path.join(__dirname, '../node_modules/swiper/modules/{a11y,navigation,pagination}-element.css').replaceAll('\\\\', '/'),\n          to: `swiper-${swiperVersion}.css`,\n          context: path.join(__dirname, '../node_modules/swiper/modules'),\n          transformAll: (assets) => {\n            return Buffer.concat(assets.map(asset => asset.data))\n          }\n        },\n        // Don't need to copy them in dev mode,\n        // as we configure WebpackDevServer to serve them\n        ...(isDevMode\n          ? []\n          : [\n              {\n                from: path.join(__dirname, '../node_modules/shaka-player/ui/locales', `{${SHAKA_LOCALES_TO_BE_BUNDLED.join(',')}}.json`).replaceAll('\\\\', '/'),\n                to: path.join(__dirname, '../dist/static/shaka-player-locales'),\n                context: path.join(__dirname, '../node_modules/shaka-player/ui/locales'),\n                transform: {\n                  transformer: (input) => {\n                    return JSON.stringify(JSON.parse(input.toString('utf-8')))\n                  }\n                }\n              }\n            ])\n      ]\n    })\n  ],\n  resolve: {\n    alias: {\n      DB_HANDLERS_ELECTRON_RENDERER_OR_WEB$: path.resolve(__dirname, '../src/datastores/handlers/electron.js'),\n\n      'youtubei.js$': 'youtubei.js/web',\n\n      // change to \"shaka-player.ui-es2021.debug.js\" to get debug logs (update jsconfig to get updated types)\n      'shaka-player$': 'shaka-player/dist/shaka-player.ui-es2021.js',\n\n      // Make @fortawesome/vue-fontawesome use the trimmed down API instead of the original @fortawesome/fontawesome-svg-core\n      '@fortawesome/fontawesome-svg-core$': path.resolve(__dirname, '../src/renderer/fontawesome-minimal.js'),\n\n      // Fix dompurify not being tree-shaking friendly\n      dompurify$: path.resolve(__dirname, '_undefinedDefaultExport.mjs')\n    },\n    extensions: ['.js', '.vue']\n  },\n  target: 'web',\n}\n\nif (isDevMode) {\n  // hack to pass it through to the dev-runner.js script\n  // gets removed there before the config object is passed to webpack\n  config.SHAKA_LOCALES_TO_BE_BUNDLED = SHAKA_LOCALES_TO_BE_BUNDLED\n}\n\nmodule.exports = config\n"
  },
  {
    "path": "_scripts/webpack.web.config.js",
    "content": "const path = require('path')\nconst fs = require('fs')\nconst webpack = require('webpack')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst { VueLoaderPlugin } = require('vue-loader')\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin')\nconst JsonMinimizerPlugin = require('json-minimizer-webpack-plugin')\nconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin')\nconst ProcessLocalesPlugin = require('./ProcessLocalesPlugin')\nconst {\n  SHAKA_LOCALE_MAPPINGS,\n  SHAKA_LOCALES_PREBUNDLED,\n  SHAKA_LOCALES_TO_BE_BUNDLED\n} = require('./getShakaLocales')\n\nconst isDevMode = process.env.NODE_ENV === 'development'\n\nconst { version: swiperVersion } = JSON.parse(fs.readFileSync(path.join(__dirname, '../node_modules/swiper/package.json')))\n\n/** @type {import('webpack').Configuration} */\nconst config = {\n  name: 'web',\n  mode: process.env.NODE_ENV,\n  devtool: isDevMode ? 'eval-cheap-module-source-map' : false,\n  entry: {\n    web: path.join(__dirname, '../src/renderer/main.js'),\n  },\n  output: {\n    path: path.join(__dirname, '../dist/web'),\n    filename: '[name].js',\n  },\n  externals: {\n    'youtubei.js': '{}',\n    googlevideo: '{}'\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        use: 'babel-loader',\n        exclude: /node_modules/,\n      },\n      {\n        test: /\\.vue$/,\n        loader: 'vue-loader',\n        options: {\n          compilerOptions: {\n            isCustomElement: (tag) => tag === 'swiper-container' || tag === 'swiper-slide',\n          }\n        }\n      },\n      {\n        test: /\\.scss$/,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader,\n          },\n          {\n            loader: 'css-loader',\n            options: {\n              esModule: false\n            }\n          },\n          {\n            loader: 'sass-loader',\n            options: {\n              implementation: require('sass')\n            }\n          },\n        ],\n      },\n      {\n        test: /\\.css$/,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader\n          },\n          {\n            loader: 'css-loader',\n            options: {\n              esModule: false\n            }\n          }\n        ],\n        rules: [\n          {\n            resource: path.resolve(__dirname, '../node_modules/shaka-player/dist/controls.css'),\n            use: path.join(__dirname, 'patch-shaka-player-loader.js')\n          }\n        ],\n      },\n      {\n        test: /\\.html$/,\n        use: 'vue-html-loader',\n      },\n      {\n        test: /\\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\\?.*)?$/,\n        type: 'asset/resource',\n        generator: {\n          filename: 'imgs/[name][ext]'\n        }\n      },\n      {\n        test: /\\.(woff2?|eot|ttf|otf)(\\?.*)?$/,\n        type: 'asset/resource',\n        generator: {\n          filename: 'fonts/[name][ext]'\n        }\n      },\n    ],\n    generator: {\n      json: {\n        JSONParse: false\n      }\n    }\n  },\n  // webpack defaults to only optimising the production builds, so having this here is fine\n  optimization: {\n    minimizer: [\n      '...', // extend webpack's list instead of overwriting it\n      new JsonMinimizerPlugin({\n        exclude: /\\/locales\\/.*\\.json/\n      }),\n      new CssMinimizerPlugin()\n    ]\n  },\n  node: {\n    __dirname: false,\n    __filename: false\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      'process.platform': 'undefined',\n      'process.env.IS_ELECTRON': false,\n      'process.env.IS_ELECTRON_MAIN': false,\n      'process.env.SUPPORTS_LOCAL_API': false,\n      __VUE_OPTIONS_API__: 'true',\n      __VUE_PROD_DEVTOOLS__: 'false',\n      __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',\n      __VUE_I18N_LEGACY_API__: 'true',\n      __VUE_I18N_FULL_INSTALL__: 'false',\n      __INTLIFY_PROD_DEVTOOLS__: 'false',\n      'process.env.SWIPER_VERSION': `'${swiperVersion}'`\n    }),\n    new webpack.ProvidePlugin({\n      process: 'process/browser.js'\n    }),\n    new HtmlWebpackPlugin({\n      excludeChunks: ['processTaskWorker'],\n      filename: 'index.html',\n      template: path.resolve(__dirname, '../src/index.ejs')\n    }),\n    new VueLoaderPlugin(),\n    new MiniCssExtractPlugin({\n      filename: isDevMode ? '[name].css' : '[name].[contenthash].css',\n      chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css',\n    }),\n    new CopyWebpackPlugin({\n      patterns: [\n        {\n          from: path.join(__dirname, '../node_modules/swiper/modules/{a11y,navigation,pagination}-element.css').replaceAll('\\\\', '/'),\n          to: `swiper-${swiperVersion}.css`,\n          context: path.join(__dirname, '../node_modules/swiper/modules'),\n          transformAll: (assets) => {\n            return Buffer.concat(assets.map(asset => asset.data))\n          }\n        }\n      ]\n    })\n  ],\n  resolve: {\n    alias: {\n      DB_HANDLERS_ELECTRON_RENDERER_OR_WEB$: path.resolve(__dirname, '../src/datastores/handlers/web.js'),\n\n      // change to \"shaka-player.ui-es2021.debug.js\" to get debug logs (update jsconfig to get updated types)\n      'shaka-player$': 'shaka-player/dist/shaka-player.ui-es2021.js',\n\n      // Make @fortawesome/vue-fontawesome use the trimmed down API instead of the original @fortawesome/fontawesome-svg-core\n      '@fortawesome/fontawesome-svg-core$': path.resolve(__dirname, '../src/renderer/fontawesome-minimal.js')\n    },\n    extensions: ['.js', '.vue']\n  },\n  target: 'web',\n}\n\nconst processLocalesPlugin = new ProcessLocalesPlugin({\n  compress: false,\n  hotReload: isDevMode,\n  inputDir: path.join(__dirname, '../static/locales'),\n  outputDir: 'static/locales',\n})\n\nconfig.plugins.push(\n  processLocalesPlugin,\n  new webpack.DefinePlugin({\n    'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames),\n    'process.env.GEOLOCATION_NAMES': JSON.stringify(fs.readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))),\n    'process.env.SHAKA_LOCALE_MAPPINGS': JSON.stringify(SHAKA_LOCALE_MAPPINGS),\n    'process.env.SHAKA_LOCALES_PREBUNDLED': JSON.stringify(SHAKA_LOCALES_PREBUNDLED)\n  }),\n  new CopyWebpackPlugin({\n    patterns: [\n      {\n        from: path.join(__dirname, '../static/pwabuilder-sw.js'),\n        to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'),\n      },\n      {\n        from: path.join(__dirname, '../static'),\n        to: path.join(__dirname, '../dist/web/static'),\n        globOptions: {\n          dot: true,\n          ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'],\n        },\n      },\n      {\n        from: path.join(__dirname, '../node_modules/shaka-player/ui/locales', `{${SHAKA_LOCALES_TO_BE_BUNDLED.join(',')}}.json`).replaceAll('\\\\', '/'),\n        to: path.join(__dirname, '../dist/web/static/shaka-player-locales'),\n        context: path.join(__dirname, '../node_modules/shaka-player/ui/locales')\n      }\n    ]\n  })\n)\n\nmodule.exports = config\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "import eslintPluginVue from 'eslint-plugin-vue'\nimport vuejsAccessibility from 'eslint-plugin-vuejs-accessibility'\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn'\nimport intlifyVueI18N from '@intlify/eslint-plugin-vue-i18n'\nimport globals from 'globals'\nimport vueEslintParser from 'vue-eslint-parser'\nimport js from '@eslint/js'\nimport eslintPluginJsonc from 'eslint-plugin-jsonc'\nimport eslintPluginYml from 'eslint-plugin-yml'\nimport jsdoc from 'eslint-plugin-jsdoc'\n\nimport stylistic from '@stylistic/eslint-plugin'\nimport eslintPluginImportX from 'eslint-plugin-import-x'\nimport eslintPluginN from 'eslint-plugin-n'\nimport eslintPluginPromise from 'eslint-plugin-promise'\n\nimport freetube from './_scripts/eslint-rules/plugin.mjs'\n\nimport activeLocales from './static/locales/activeLocales.json' with { type: 'json' }\n\nexport default [\n  {\n    ignores: [\n      'build/',\n      'dist/',\n      'eslint.config.mjs',\n      // The JSON files inside this directory are auto-generated, so they don't follow the code style rules\n      'static/geolocations/'\n    ]\n  },\n  {\n    name: 'base',\n\n    languageOptions: {\n      ecmaVersion: 2022,\n      sourceType: 'module',\n      globals: {\n        ...globals.es2022,\n        ...globals.node,\n        document: 'readonly',\n        navigator: 'readonly',\n        window: 'readonly',\n      },\n    },\n\n    plugins: {\n      'import-x': eslintPluginImportX,\n      n: eslintPluginN,\n      promise: eslintPluginPromise,\n    },\n\n    rules: {\n      'no-var': 'warn',\n      'object-shorthand': ['warn', 'properties'],\n\n      'accessor-pairs': ['error', { setWithoutGet: true, enforceForClassMembers: true }],\n      'array-callback-return': ['error', {\n        allowImplicit: false,\n        checkForEach: false,\n      }],\n      camelcase: ['error', {\n        allow: ['^UNSAFE_'],\n        properties: 'never',\n        ignoreGlobals: true,\n      }],\n      curly: ['error', 'multi-line'],\n      'default-case-last': 'error',\n      eqeqeq: ['error', 'always', { null: 'ignore' }],\n      'new-cap': ['error', { newIsCap: true, capIsNew: false, properties: true }],\n      'no-array-constructor': 'error',\n      'no-caller': 'error',\n      'no-constant-condition': ['error', { checkLoops: false }],\n      'no-empty': ['error', { allowEmptyCatch: true }],\n      'no-eval': 'error',\n      'no-extend-native': 'error',\n      'no-extra-bind': 'error',\n      'no-implied-eval': 'error',\n      'no-iterator': 'error',\n      'no-labels': ['error', { allowLoop: false, allowSwitch: false }],\n      'no-lone-blocks': 'error',\n      'no-multi-str': 'error',\n      'no-new': 'error',\n      'no-new-func': 'error',\n      'no-object-constructor': 'error',\n      'no-new-wrappers': 'error',\n      'no-octal-escape': 'error',\n      'no-proto': 'error',\n      'no-redeclare': ['error', { builtinGlobals: false }],\n      'no-return-assign': ['error', 'except-parens'],\n      'no-self-compare': 'error',\n      'no-sequences': 'error',\n      'no-template-curly-in-string': 'error',\n      'no-throw-literal': 'error',\n      'no-undef-init': 'error',\n      'no-unmodified-loop-condition': 'error',\n      'no-unneeded-ternary': ['error', { defaultAssignment: false }],\n      'no-unreachable-loop': 'error',\n      'no-unused-expressions': ['error', {\n        allowShortCircuit: true,\n        allowTernary: true,\n        allowTaggedTemplates: true,\n      }],\n      'no-unused-vars': ['error', {\n        args: 'none',\n        caughtErrors: 'none',\n        ignoreRestSiblings: true,\n        vars: 'all',\n      }],\n      'no-use-before-define': ['error', { functions: false, classes: false, variables: false }],\n      'no-useless-call': 'error',\n      'no-useless-computed-key': 'error',\n      'no-useless-constructor': 'error',\n      'no-useless-rename': 'error',\n      'no-useless-return': 'error',\n      'no-void': 'error',\n      'one-var': ['error', { initialized: 'never' }],\n      'prefer-const': ['error', { destructuring: 'all' }],\n      'prefer-promise-reject-errors': 'error',\n      'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],\n      'symbol-description': 'error',\n      'unicode-bom': ['error', 'never'],\n      'use-isnan': ['error', {\n        enforceForSwitchCase: true,\n        enforceForIndexOf: true,\n      }],\n      'valid-typeof': ['error', { requireStringLiterals: true }],\n      yoda: ['error', 'never'],\n\n      'import-x/export': 'error',\n      'import-x/first': 'error',\n      'import-x/no-absolute-path': ['error', { esmodule: true, commonjs: true, amd: false }],\n      'import-x/no-duplicates': 'error',\n      'import-x/no-named-default': 'error',\n      'import-x/no-webpack-loader-syntax': 'error',\n\n      'n/handle-callback-err': ['error', '^(err|error)$'],\n      'n/no-callback-literal': 'error',\n      'n/no-deprecated-api': 'warn',\n      'n/no-exports-assign': 'error',\n      'n/no-new-require': 'error',\n      'n/no-path-concat': 'error',\n      'n/process-exit-as-throw': 'error',\n\n      'promise/param-names': 'error',\n    },\n  },\n  {\n    name: 'style',\n\n    plugins: {\n      '@stylistic': stylistic,\n    },\n    rules: {\n      '@stylistic/array-bracket-spacing': ['error', 'never'],\n      '@stylistic/arrow-spacing': ['error', { before: true, after: true }],\n      '@stylistic/block-spacing': ['error', 'always'],\n      '@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }],\n      '@stylistic/comma-dangle': ['warn', {\n        arrays: 'ignore',\n        enums: 'ignore',\n        exports: 'ignore',\n        imports: 'ignore',\n        objects: 'ignore',\n      }],\n      '@stylistic/comma-spacing': ['error', { before: false, after: true }],\n      '@stylistic/comma-style': ['error', 'last'],\n      '@stylistic/computed-property-spacing': ['error', 'never', { enforceForClassMembers: true }],\n      '@stylistic/dot-location': ['error', 'property'],\n      '@stylistic/eol-last': 'error',\n      '@stylistic/function-call-spacing': ['error', 'never'],\n      '@stylistic/generator-star-spacing': ['error', { before: true, after: true }],\n      '@stylistic/indent': ['error', 2, {\n        SwitchCase: 1,\n        VariableDeclarator: 1,\n        outerIIFEBody: 1,\n        MemberExpression: 1,\n        FunctionDeclaration: { parameters: 1, body: 1 },\n        FunctionExpression: { parameters: 1, body: 1 },\n        CallExpression: { arguments: 1 },\n        ArrayExpression: 1,\n        ObjectExpression: 1,\n        ImportDeclaration: 1,\n        flatTernaryExpressions: false,\n        ignoreComments: false,\n        ignoredNodes: ['TemplateLiteral *'],\n        offsetTernaryExpressions: true,\n      }],\n      '@stylistic/key-spacing': ['error', { beforeColon: false, afterColon: true }],\n      '@stylistic/keyword-spacing': ['error', { before: true, after: true }],\n      '@stylistic/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],\n      '@stylistic/multiline-ternary': ['error', 'always-multiline'],\n      '@stylistic/new-parens': 'error',\n      '@stylistic/no-extra-parens': ['error', 'functions'],\n      '@stylistic/no-floating-decimal': 'error',\n      '@stylistic/no-mixed-operators': ['error', {\n        groups: [\n          ['==', '!=', '===', '!==', '>', '>=', '<', '<='],\n          ['&&', '||'],\n          ['in', 'instanceof'],\n        ],\n        allowSamePrecedence: true,\n      }],\n      '@stylistic/no-mixed-spaces-and-tabs': 'error',\n      '@stylistic/no-multi-spaces': ['error', { ignoreEOLComments: true }],\n      '@stylistic/no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }],\n      '@stylistic/no-tabs': 'error',\n      '@stylistic/no-trailing-spaces': 'error',\n      '@stylistic/no-whitespace-before-property': 'error',\n      '@stylistic/object-curly-newline': ['error', { multiline: true, consistent: true }],\n      '@stylistic/object-curly-spacing': ['error', 'always'],\n      '@stylistic/object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }],\n      '@stylistic/operator-linebreak': ['error', 'after', { overrides: { '?': 'before', ':': 'before', '|>': 'before' } }],\n      '@stylistic/padded-blocks': ['error', { blocks: 'never', switches: 'never', classes: 'never' }],\n      '@stylistic/quote-props': ['error', 'as-needed'],\n      '@stylistic/quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: 'never' }],\n      '@stylistic/rest-spread-spacing': ['error', 'never'],\n      '@stylistic/semi': ['error', 'never'],\n      '@stylistic/semi-spacing': ['error', { before: false, after: true }],\n      '@stylistic/space-before-blocks': ['error', 'always'],\n      '@stylistic/space-before-function-paren': ['error', 'always'],\n      '@stylistic/space-in-parens': ['error', 'never'],\n      '@stylistic/space-infix-ops': 'error',\n      '@stylistic/space-unary-ops': ['error', { words: true, nonwords: false }],\n      '@stylistic/spaced-comment': ['error', 'always', {\n        line: { markers: ['*package', '!', '/', ',', '='] },\n        block: { balanced: true, markers: ['*package', '!', ',', ':', '::', 'flow-include'], exceptions: ['*'] },\n      }],\n      '@stylistic/template-curly-spacing': ['error', 'never'],\n      '@stylistic/template-tag-spacing': ['error', 'never'],\n      '@stylistic/wrap-iife': ['error', 'any', { functionPrototypeMethods: true }],\n      '@stylistic/yield-star-spacing': ['error', 'both'],\n    },\n  },\n\n  js.configs.recommended,\n  ...eslintPluginVue.configs['flat/recommended'],\n  ...vuejsAccessibility.configs[\"flat/recommended\"],\n  ...intlifyVueI18N.configs.recommended,\n  {\n    files: [\n      '**/*.{js,vue}',\n    ],\n    ignores: [\n      '_scripts/',\n    ],\n    plugins: {\n      unicorn: eslintPluginUnicorn,\n      jsdoc,\n      freetube,\n    },\n\n    languageOptions: {\n      globals: {\n        ...globals.browser,\n        ...globals.node,\n      },\n\n      parser: vueEslintParser,\n      ecmaVersion: 2022,\n      sourceType: 'module',\n    },\n\n    settings: {\n      'vue-i18n': {\n        localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,\n        messageSyntaxVersion: '^11.0.0',\n      },\n    },\n\n    rules: {\n      '@stylistic/space-before-function-paren': 'off',\n      '@stylistic/comma-dangle': ['error', 'only-multiline'],\n\n      // Ban v-html as it inserts HTML via innerHTML without sanitizing it\n      // if inserting raw HTML is unavoidable the custom v-safer-html directive should be used\n      // which sanitizes the HTML before inserting it into the DOM\n      'vue/no-v-html': 'error',\n\n      'no-console': ['error', {\n        allow: ['warn', 'error'],\n      }],\n\n      'no-unused-vars': 'warn',\n      'no-undef': 'warn',\n      'object-shorthand': 'off',\n      'vue/multi-word-component-names': 'off',\n\n      'vuejs-accessibility/label-has-for': ['error', {\n        required: {\n          some: ['nesting', 'id'],\n        },\n      }],\n\n      'vuejs-accessibility/no-static-element-interactions': 'off',\n      'unicorn/better-regex': 'error',\n      'unicorn/prefer-single-call': 'error',\n      'unicorn/prefer-keyboard-event-key': 'error',\n      'unicorn/prefer-regexp-test': 'error',\n      'unicorn/prefer-string-replace-all': 'error',\n      'unicorn/prefer-optional-catch-binding': 'error',\n      'unicorn/prefer-date-now': 'error',\n      'unicorn/prefer-array-index-of': 'error',\n      '@intlify/vue-i18n/no-dynamic-keys': 'error',\n      '@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',\n\n      '@intlify/vue-i18n/no-raw-text': ['error', {\n        attributes: {\n          '/.+/': [\n            'title',\n            'aria-label',\n            'aria-placeholder',\n            'aria-roledescription',\n            'aria-valuetext',\n            'tooltip',\n            'message',\n          ],\n\n          input: ['placeholder', 'value'],\n          img: ['alt'],\n        },\n\n        ignoreText: ['-', '•', '/', 'YouTube', 'Invidious', 'FreeTube'],\n      }],\n\n      'vue/no-unused-emit-declarations': 'error',\n      'vue/prefer-use-template-ref': 'error',\n\n      'jsdoc/check-alignment': 'error',\n      'jsdoc/check-property-names': 'error',\n      'jsdoc/check-param-names': 'error',\n      'jsdoc/check-syntax': 'error',\n      'jsdoc/check-template-names': 'error',\n      'jsdoc/check-types': 'error',\n      'jsdoc/no-bad-blocks': 'error',\n      'jsdoc/no-multi-asterisks': 'error',\n\n      'freetube/prefer-use-i18n-polyfill': 'error',\n    },\n  },\n\n  {\n    files: ['src/main/index.js'],\n    languageOptions: {\n      globals: {\n        __FREETUBE_ALLOWED_PATHS__: 'readable'\n      }\n    }\n  },\n  {\n    files: ['src/renderer/directives/vSaferHtml.js'],\n    languageOptions: {\n      globals: {\n        // Fix Sanitizer not being listed in `globals` yet, remove it when it gets added in the future\n        Sanitizer: 'readable'\n      }\n    }\n  },\n\n  ...eslintPluginJsonc.configs.base,\n  {\n    files: ['**/*.json'],\n    ignores: [\n      '_scripts/',\n    ],\n\n    rules: {\n      '@stylistic/no-tabs': 'off',\n      '@stylistic/comma-spacing': 'off',\n      '@stylistic/eol-last': 'off',\n      'no-irregular-whitespace': 'off',\n    },\n\n    settings: {\n      'vue-i18n': {\n        localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,\n        messageSyntaxVersion: '^11.0.0',\n      },\n    },\n  },\n\n  ...eslintPluginYml.configs.recommended,\n  {\n    files: ['**/*.{yml,yaml}'],\n    ignores: [\n      '.github/',\n      '_scripts/'\n    ],\n\n    rules: {\n      'yml/no-irregular-whitespace': 'off',\n      '@stylistic/spaced-comment': 'off',\n    },\n\n    settings: {\n      'vue-i18n': {\n        localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,\n        messageSyntaxVersion: '^11.0.0',\n      },\n    },\n  },\n  {\n    files: ['.github/**/*.{yml,yaml}'],\n\n    rules: {\n      'yml/no-empty-mapping-value': 'off',\n      'yml/no-irregular-whitespace': 'off',\n    },\n\n    settings: {\n      'vue-i18n': {\n        localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,\n        messageSyntaxVersion: '^11.0.0',\n      },\n    },\n  },\n  {\n    files: ['_scripts/*.js'],\n    languageOptions: {\n      globals: globals.node,\n      ecmaVersion: 'latest',\n      sourceType: 'commonjs'\n    },\n\n    plugins: {\n      unicorn: eslintPluginUnicorn,\n    },\n\n    rules: {\n      '@stylistic/space-before-function-paren': 'off',\n      '@stylistic/comma-dangle': ['error', 'only-multiline'],\n      'no-console': 'off',\n      'unicorn/better-regex': 'error',\n      'unicorn/prefer-optional-catch-binding': 'error',\n      'unicorn/prefer-date-now': 'error',\n      'unicorn/prefer-array-index-of': 'error',\n    }\n  },\n  {\n    files: ['_scripts/**/*.mjs'],\n    languageOptions: {\n      globals: globals.node,\n      ecmaVersion: 'latest',\n      sourceType: 'module',\n    },\n\n    plugins: {\n      unicorn: eslintPluginUnicorn,\n    },\n\n    rules: {\n      'no-console': 'off',\n      '@stylistic/space-before-function-paren': 'off',\n      '@stylistic/comma-dangle': ['error', 'only-multiline'],\n      'unicorn/better-regex': 'error',\n      'unicorn/prefer-optional-catch-binding': 'error',\n      'unicorn/prefer-date-now': 'error',\n      'unicorn/prefer-array-index-of': 'error',\n    }\n  }\n]\n"
  },
  {
    "path": "jsconfig.json",
    "content": "{\n  \"vueCompilerOptions\": {\n    \"target\": 3.5\n  },\n  \"compilerOptions\": {\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"strictNullChecks\": true,\n    \"baseUrl\": \"./\",\n    \"paths\": {\n      \"DB_HANDLERS_ELECTRON_RENDERER_OR_WEB\": [\n        \"src/datastores/handlers/electron\",\n        \"src/datastores/handlers/web\"\n      ],\n      \"shaka-player\": [\n        \"./node_modules/shaka-player/dist/shaka-player.ui-es2021\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "lefthook-local.yml.example",
    "content": "# See following doc for details\n# https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md#rc\n\n# You can choose whatever name/path you want for `~/.lefthookrc`.\n# You can share it between projects where you use lefthook.\n# Make sure the path is absolute.\nrc: ~/.lefthookrc\n"
  },
  {
    "path": "lefthook.yml",
    "content": "# Refer for explanation to following link:\n# https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md\npre-commit:\n  parallel: true\n  commands:\n    eslint:\n      # Only runs when any file with filename\n      # matching the glob is being committed\n      glob: \"*.{js,vue}\"\n      run: yarn run eslint --no-color {staged_files}\n      skip:\n        - rebase\n    stylelint:\n      glob: \"*.{css,scss}\"\n      run: yarn stylelint --no-color --allow-empty-input {staged_files}\n      skip:\n        - rebase\n\n# EXAMPLE USAGE\n#\n# pre-push:\n#   commands:\n#     packages-audit:\n#       tags: frontend security\n#       run: yarn audit\n#     gems-audit:\n#       tags: backend security\n#       run: bundle audit\n#\n# pre-commit:\n#   parallel: true\n#   commands:\n#     eslint:\n#       glob: \"*.{js,ts}\"\n#       run: yarn eslint {staged_files}\n#     rubocop:\n#       tags: backend style\n#       glob: \"*.rb\"\n#       exclude: \"application.rb|routes.rb\"\n#       run: bundle exec rubocop --force-exclusion {all_files}\n#     govet:\n#       tags: backend style\n#       files: git ls-files -m\n#       glob: \"*.go\"\n#       run: go vet {files}\n#   scripts:\n#     \"hello.js\":\n#       runner: node\n#     \"any.go\":\n#       runner: go run\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"freetube\",\n  \"productName\": \"FreeTube\",\n  \"description\": \"A private YouTube client\",\n  \"version\": \"0.23.15\",\n  \"license\": \"AGPL-3.0-or-later\",\n  \"main\": \"./dist/main.js\",\n  \"private\": true,\n  \"author\": {\n    \"name\": \"FreeTube Team\",\n    \"email\": \"FreeTubeApp@protonmail.com\",\n    \"url\": \"https://github.com/FreeTubeApp/FreeTube\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/FreeTubeApp/FreeTube.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/FreeTubeApp/FreeTube/issues\"\n  },\n  \"scripts\": {\n    \"build\": \"run-s pack build-release\",\n    \"build:arm64\": \"run-s pack build-release:arm64\",\n    \"build:arm32\": \"run-s pack build-release:arm32\",\n    \"build-release\": \"node _scripts/build.mjs\",\n    \"build-release:arm64\": \"node _scripts/build.mjs arm64\",\n    \"build-release:arm32\": \"node _scripts/build.mjs arm32\",\n    \"clean\": \"node _scripts/clean.mjs\",\n    \"debug\": \"node _scripts/dev-runner.js --remote-debug\",\n    \"dev\": \"node _scripts/dev-runner.js\",\n    \"dev:web\": \"node _scripts/dev-runner.js --web\",\n    \"get-instances\": \"node _scripts/getInstances.js\",\n    \"get-regions\": \"node _scripts/getRegions.mjs\",\n    \"lint-all\": \"run-p lint lint-json\",\n    \"lint\": \"run-p eslint-lint lint-style\",\n    \"lint-fix\": \"run-p eslint-lint-fix lint-style-fix\",\n    \"eslint-lint\": \"eslint --config eslint.config.mjs \\\"src/**/*.js\\\" \\\"src/renderer/**/*.vue\\\" \\\"static/*.js\\\" \\\"_scripts/*.js\\\" \\\"_scripts/**/*.mjs\\\"\",\n    \"eslint-lint-fix\": \"eslint --config eslint.config.mjs --fix \\\"src/**/*.js\\\" \\\"src/renderer/**/*.vue\\\" \\\"static/*.js\\\" \\\"_scripts/*.js\\\" \\\"_scripts/**/*.mjs\\\"\",\n    \"lint-json\": \"eslint --config eslint.config.mjs \\\"static/**/*.json\\\"\",\n    \"lint-style\": \"stylelint \\\"src/**/*.{css,scss}\\\"\",\n    \"lint-style-fix\": \"stylelint --fix \\\"src/**/*.{css,scss}\\\"\",\n    \"lint-yml\": \"eslint --config eslint.config.mjs \\\"**/*.yml\\\" \\\"**/*.yaml\\\"\",\n    \"pack\": \"run-p pack:main pack:renderer pack:preload pack:botGuardScript && node _scripts/injectAllowedPaths.mjs\",\n    \"pack:main\": \"webpack --mode=production --config-node-env=production --config _scripts/webpack.main.config.js\",\n    \"pack:renderer\": \"webpack --mode=production --config-node-env=production --config _scripts/webpack.renderer.config.js\",\n    \"pack:preload\": \"webpack --mode=production --config-node-env=production --config _scripts/webpack.preload.config.js\",\n    \"pack:web\": \"webpack --mode=production --config-node-env=production --config _scripts/webpack.web.config.js\",\n    \"pack:botGuardScript\": \"webpack --config _scripts/webpack.botGuardScript.config.js\",\n    \"checkforbadtemplates\": \"node _scripts/findMissingTemplates.mjs\",\n    \"ci\": \"yarn install --silent --frozen-lockfile --network-concurrency 1\"\n  },\n  \"dependencies\": {\n    \"@fortawesome/fontawesome-svg-core\": \"^7.2.0\",\n    \"@fortawesome/free-brands-svg-icons\": \"^7.2.0\",\n    \"@fortawesome/free-regular-svg-icons\": \"^7.2.0\",\n    \"@fortawesome/free-solid-svg-icons\": \"^7.2.0\",\n    \"@fortawesome/vue-fontawesome\": \"^3.1.3\",\n    \"@seald-io/nedb\": \"^4.1.2\",\n    \"autolinker\": \"^4.1.5\",\n    \"bgutils-js\": \"^3.2.0\",\n    \"dompurify\": \"^3.3.3\",\n    \"electron-context-menu\": \"^4.1.1\",\n    \"googlevideo\": \"^4.0.4\",\n    \"marked\": \"^17.0.4\",\n    \"process\": \"^0.11.10\",\n    \"shaka-player\": \"^5.0.6\",\n    \"swiper\": \"^12.1.2\",\n    \"vue\": \"^3.5.30\",\n    \"vue-i18n\": \"^11.3.0\",\n    \"vue-observe-visibility\": \"^2.0.0-alpha.1\",\n    \"vue-router\": \"^5.0.3\",\n    \"vuex\": \"^4.1.0\",\n    \"youtubei.js\": \"^17.0.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@double-great/stylelint-a11y\": \"^3.4.6\",\n    \"@eslint/js\": \"^10.0.1\",\n    \"@intlify/eslint-plugin-vue-i18n\": \"^4.3.0\",\n    \"@stylistic/eslint-plugin\": \"^5.10.0\",\n    \"babel-loader\": \"^10.1.1\",\n    \"copy-webpack-plugin\": \"^14.0.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"css-minimizer-webpack-plugin\": \"^8.0.0\",\n    \"electron\": \"^41.0.2\",\n    \"electron-builder\": \"^26.8.1\",\n    \"eslint\": \"^10.0.3\",\n    \"eslint-plugin-import-x\": \"^4.16.2\",\n    \"eslint-plugin-jsdoc\": \"^62.8.0\",\n    \"eslint-plugin-jsonc\": \"^3.1.2\",\n    \"eslint-plugin-n\": \"^17.24.0\",\n    \"eslint-plugin-promise\": \"^7.2.1\",\n    \"eslint-plugin-unicorn\": \"^63.0.0\",\n    \"eslint-plugin-vue\": \"^10.8.0\",\n    \"eslint-plugin-vuejs-accessibility\": \"^2.5.0\",\n    \"eslint-plugin-yml\": \"^3.3.1\",\n    \"globals\": \"^17.4.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"js-yaml\": \"^4.1.1\",\n    \"json-minimizer-webpack-plugin\": \"^5.0.1\",\n    \"lefthook\": \"^2.1.4\",\n    \"mini-css-extract-plugin\": \"^2.10.1\",\n    \"npm-run-all2\": \"^8.0.4\",\n    \"postcss\": \"^8.5.8\",\n    \"postcss-scss\": \"^4.0.9\",\n    \"sass\": \"^1.98.0\",\n    \"sass-loader\": \"^16.0.7\",\n    \"stylelint\": \"^17.4.0\",\n    \"stylelint-config-sass-guidelines\": \"^13.0.0\",\n    \"stylelint-config-standard\": \"^40.0.0\",\n    \"stylelint-high-performance-animation\": \"^2.0.0\",\n    \"stylelint-use-logical-spec\": \"^5.0.1\",\n    \"tree-kill\": \"1.2.2\",\n    \"vue-eslint-parser\": \"^10.2.0\",\n    \"vue-loader\": \"^17.4.2\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.1\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "src/botGuardScript.js",
    "content": "import { BG, buildURL, GOOG_API_KEY } from 'bgutils-js'\n\n// This script has it's own webpack config, as it gets passed as a string to Electron's evaluateJavaScript function\n// in src/main/poTokenGenerator.js\n\n/**\n * Based on: https://github.com/LuanRT/BgUtils/blob/main/examples/node/innertube-challenge-fetcher-example.ts\n * @param {string} videoId\n * @param {import('youtubei.js').Session['context']} context\n */\nexport default async function (videoId, context) {\n  const requestKey = 'O43z0dpjhgX20SCx4KAo'\n\n  const challengeResponse = await fetch(\n    'https://www.youtube.com/youtubei/v1/att/get?prettyPrint=false&alt=json',\n    {\n      method: 'POST',\n      headers: {\n        Accept: '*/*',\n        'Content-Type': 'application/json',\n        'X-Goog-Visitor-Id': context.client.visitorData,\n        'X-Youtube-Client-Version': context.client.clientVersion,\n        'X-Youtube-Client-Name': '1'\n      },\n      body: JSON.stringify({\n        engagementType: 'ENGAGEMENT_TYPE_UNBOUND',\n        context\n      }),\n    }\n  )\n\n  if (!challengeResponse.ok) {\n    throw new Error(`Request to ${challengeResponse.url} failed with status ${challengeResponse.status}\\n${await challengeResponse.text()}`)\n  }\n\n  const challengeData = await challengeResponse.json()\n\n  if (!challengeData.bgChallenge) {\n    throw new Error('Failed to get BotGuard challenge')\n  }\n\n  let interpreterUrl = challengeData.bgChallenge.interpreterUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue\n\n  if (interpreterUrl.startsWith('//')) {\n    interpreterUrl = `https:${interpreterUrl}`\n  }\n\n  const bgScriptResponse = await fetch(interpreterUrl)\n  const interpreterJavascript = await bgScriptResponse.text()\n\n  if (interpreterJavascript) {\n    // eslint-disable-next-line no-new-func\n    new Function(interpreterJavascript)()\n  } else {\n    throw new Error('Could not load VM.')\n  }\n\n  const botGuard = await BG.BotGuardClient.create({\n    program: challengeData.bgChallenge.program,\n    globalName: challengeData.bgChallenge.globalName,\n    globalObj: window\n  })\n\n  const webPoSignalOutput = []\n  const botGuardResponse = await botGuard.snapshot({ webPoSignalOutput }, 10_000)\n\n  const integrityTokenResponse = await fetch(buildURL('GenerateIT', true), {\n    method: 'POST',\n    headers: {\n      'content-type': 'application/json+protobuf',\n      'x-goog-api-key': GOOG_API_KEY,\n      'x-user-agent': 'grpc-web-javascript/0.1',\n    },\n    body: JSON.stringify([requestKey, botGuardResponse])\n  })\n\n  const response = await integrityTokenResponse.json()\n\n  if (typeof response[0] !== 'string') {\n    throw new Error('Could not get integrity token')\n  }\n\n  const integrityTokenBasedMinter = await BG.WebPoMinter.create({ integrityToken: response[0] }, webPoSignalOutput)\n\n  return await integrityTokenBasedMinter.mintAsWebsafeString(videoId)\n}\n"
  },
  {
    "path": "src/constants.js",
    "content": "// IPC Channels\nconst IpcChannels = {\n  ENABLE_PROXY: 'enable-proxy',\n  DISABLE_PROXY: 'disable-proxy',\n  GET_SYSTEM_LOCALE: 'get-system-locale',\n  GET_NAVIGATION_HISTORY: 'get-navigation-history',\n  STOP_POWER_SAVE_BLOCKER: 'stop-power-save-blocker',\n  START_POWER_SAVE_BLOCKER: 'start-power-save-blocker',\n  CREATE_NEW_WINDOW: 'create-new-window',\n  NATIVE_THEME_UPDATE: 'native-theme-update',\n  APP_READY: 'app-ready',\n  RELAUNCH_REQUEST: 'relaunch-request',\n  SET_WINDOW_TITLE: 'set-window-title',\n\n  SEARCH_INPUT_HANDLING_READY: 'search-input-handling-ready',\n  UPDATE_SEARCH_INPUT_TEXT: 'update-search-input-text',\n\n  OPEN_URL: 'open-url',\n  CHANGE_VIEW: 'change-view',\n\n  DB_SETTINGS: 'db-settings',\n  DB_HISTORY: 'db-history',\n  DB_PROFILES: 'db-profiles',\n  DB_PLAYLISTS: 'db-playlists',\n  DB_SEARCH_HISTORY: 'db-search-history',\n  DB_SUBSCRIPTION_CACHE: 'db-subscription-cache',\n\n  SYNC_SETTINGS: 'sync-settings',\n  SYNC_HISTORY: 'sync-history',\n  SYNC_SEARCH_HISTORY: 'sync-search-history',\n  SYNC_PROFILES: 'sync-profiles',\n  SYNC_PLAYLISTS: 'sync-playlists',\n  SYNC_SUBSCRIPTION_CACHE: 'sync-subscription-cache',\n\n  GET_REPLACE_HTTP_CACHE: 'get-replace-http-cache',\n  TOGGLE_REPLACE_HTTP_CACHE: 'toggle-replace-http-cache',\n\n  PLAYER_CACHE_GET: 'player-cache-get',\n  PLAYER_CACHE_SET: 'player-cache-set',\n\n  SET_INVIDIOUS_AUTHORIZATION: 'set-invidious-authorization',\n\n  GENERATE_PO_TOKEN: 'generate-po-token',\n\n  CHOOSE_DEFAULT_FOLDER: 'choose-default-folder',\n  WRITE_TO_DEFAULT_FOLDER: 'write-to-default-folder',\n\n  OPEN_IN_EXTERNAL_PLAYER: 'open-in-external-player',\n  OPEN_IN_EXTERNAL_PLAYER_RESULT: 'open-in-external-player-result'\n}\n\nconst DBActions = {\n  // The constants in the GENERAL group are usally intermingeled with the ones in other groups, so they need unique values.\n  // The other groups however are usually not mixed (e.g. HISTORY and PROFILES),\n  // so they can have similar values (as long as they don't overlap with the GENERAL group).\n  GENERAL: {\n    CREATE: 0,\n    FIND: 1,\n    UPSERT: 2,\n    DELETE: 3,\n    DELETE_MULTIPLE: 4,\n    DELETE_ALL: 5,\n    OVERWRITE: 6\n  },\n\n  HISTORY: {\n    UPDATE_WATCH_PROGRESS: 20,\n    UPDATE_PLAYLIST: 21,\n  },\n\n  PROFILES: {\n    ADD_CHANNEL: 20,\n    REMOVE_CHANNEL: 21\n  },\n\n  PLAYLISTS: {\n    UPSERT_VIDEO: 20,\n    UPSERT_VIDEOS: 21,\n    DELETE_VIDEO_ID: 22,\n    DELETE_VIDEO_IDS: 23,\n    DELETE_ALL_VIDEOS: 24,\n  },\n\n  SUBSCRIPTION_CACHE: {\n    UPDATE_VIDEOS_BY_CHANNEL: 20,\n    UPDATE_LIVE_STREAMS_BY_CHANNEL: 21,\n    UPDATE_SHORTS_BY_CHANNEL: 22,\n    UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: 23,\n    UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 24,\n  },\n}\n\nconst SyncEvents = {\n  // The constants in the GENERAL group are usally intermingeled with the ones in other groups, so they need unique values.\n  // The other groups however are usually not mixed (e.g. HISTORY and PROFILES),\n  // so they can have similar values (as long as they don't overlap with the GENERAL group).\n  GENERAL: {\n    CREATE: 0,\n    UPSERT: 1,\n    DELETE: 2,\n    DELETE_MULTIPLE: 3,\n    DELETE_ALL: 4,\n    OVERWRITE: 5,\n  },\n\n  HISTORY: {\n    UPDATE_WATCH_PROGRESS: 20,\n    UPDATE_PLAYLIST: 21,\n  },\n\n  PROFILES: {\n    ADD_CHANNEL: 20,\n    REMOVE_CHANNEL: 21\n  },\n\n  PLAYLISTS: {\n    UPSERT_VIDEO: 20,\n    UPSERT_VIDEOS: 21,\n    DELETE_VIDEO: 22,\n    DELETE_VIDEOS: 23,\n  },\n\n  SUBSCRIPTION_CACHE: {\n    UPDATE_VIDEOS_BY_CHANNEL: 20,\n    UPDATE_LIVE_STREAMS_BY_CHANNEL: 21,\n    UPDATE_SHORTS_BY_CHANNEL: 22,\n    UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: 23,\n    UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 24,\n  },\n}\n\n/*\n  DEV NOTE: Duplicate any and all changes made here to our [official documentation site here](https://github.com/FreeTubeApp/FreeTube-Docs/blob/master/usage/keyboard-shortcuts.md)\n  to have them reflect on the [keyboard shortcut reference webpage](https://docs.freetubeapp.io/usage/keyboard-shortcuts).\n  Please also update the [keyboard shortcut modal](src/renderer/components/FtKeyboardShortcutPrompt/FtKeyboardShortcutPrompt.vue)\n*/\nconst KeyboardShortcuts = {\n  APP: {\n    GENERAL: {\n      SHOW_SHORTCUTS: 'shift+?',\n      HISTORY_BACKWARD: 'alt+arrowleft',\n      HISTORY_FORWARD: 'alt+arrowright',\n      HISTORY_BACKWARD_ALT_MAC: 'cmd+[',\n      HISTORY_FORWARD_ALT_MAC: 'cmd+]',\n      FULLSCREEN: 'f11',\n      NAVIGATE_TO_SETTINGS: 'ctrl+,',\n      NAVIGATE_TO_HISTORY: 'ctrl+H',\n      NAVIGATE_TO_HISTORY_MAC: 'cmd+Y',\n      NEW_WINDOW: 'ctrl+N',\n      MINIMIZE_WINDOW: 'ctrl+M',\n      CLOSE_WINDOW: 'ctrl+W',\n      TOGGLE_DEVTOOLS: 'ctrl+shift+I',\n      FOCUS_SEARCH: 'alt+D',\n      SEARCH_IN_NEW_WINDOW: 'shift+enter',\n      RESET_ZOOM: 'ctrl+0',\n      ZOOM_IN: 'ctrl+plus',\n      ZOOM_OUT: 'ctrl+-'\n\n    },\n    SITUATIONAL: {\n      REFRESH: 'r',\n      FOCUS_SECONDARY_SEARCH: 'ctrl+F'\n    },\n  },\n  VIDEO_PLAYER: {\n    GENERAL: {\n      CAPTIONS: 'c',\n      THEATRE_MODE: 't',\n      FULLSCREEN: 'f',\n      FULLWINDOW: 's',\n      PICTURE_IN_PICTURE: 'i',\n      MUTE: 'm',\n      VOLUME_UP: 'arrowup',\n      VOLUME_DOWN: 'arrowdown',\n      STATS: 'd',\n      TAKE_SCREENSHOT: 'u',\n    },\n    PLAYBACK: {\n      PLAY: 'k',\n      LARGE_REWIND: 'j',\n      LARGE_FAST_FORWARD: 'l',\n      SMALL_REWIND: 'arrowleft',\n      SMALL_FAST_FORWARD: 'arrowright',\n      DECREASE_VIDEO_SPEED: 'o',\n      DECREASE_VIDEO_SPEED_ALT: '<',\n      INCREASE_VIDEO_SPEED: 'p',\n      INCREASE_VIDEO_SPEED_ALT: '>',\n      SKIP_N_TENTHS: '0..9',\n      LAST_CHAPTER: 'ctrl+arrowleft',\n      NEXT_CHAPTER: 'ctrl+arrowright',\n      LAST_FRAME: ',',\n      NEXT_FRAME: '.',\n      HOME: 'home',\n      END: 'end',\n      SKIP_TO_NEXT: 'shift+n',\n      SKIP_TO_PREV: 'shift+p'\n    }\n  },\n}\n\n/**\n * Material Design Symbols used by FreeTube's custom player components\n *\n * This only has the value of the `d` attribute from the `<path>` element, the rest of the SVG is generated at runtime.\n *\n * Fetched with\n * https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsrounded/<icon>/default/24px.svg\n * https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsrounded/<icon>/fill1/24px.svg\n */\nconst PlayerIcons = {\n  CLOSE_FULLSCREEN_FILLED: 'M400-344 164-108q-11 11-28 11t-28-11q-11-11-11-28t11-28l236-236H200q-17 0-28.5-11.5T160-440q0-17 11.5-28.5T200-480h240q17 0 28.5 11.5T480-440v240q0 17-11.5 28.5T440-160q-17 0-28.5-11.5T400-200v-144Zm216-216h144q17 0 28.5 11.5T800-520q0 17-11.5 28.5T760-480H520q-17 0-28.5-11.5T480-520v-240q0-17 11.5-28.5T520-800q17 0 28.5 11.5T560-760v144l236-236q11-11 28-11t28 11q11 11 11 28t-11 28L616-560Z',\n  DONE_FILLED: 'm382-354 339-339q12-12 28-12t28 12q12 12 12 28.5T777-636L410-268q-12 12-28 12t-28-12L182-440q-12-12-11.5-28.5T183-497q12-12 28.5-12t28.5 12l142 143Z',\n  INSERT_CHART_DEFAULT: 'M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Zm120 200q-17 0-28.5 11.5T280-520v200q0 17 11.5 28.5T320-280q17 0 28.5-11.5T360-320v-200q0-17-11.5-28.5T320-560Zm160-120q-17 0-28.5 11.5T440-640v320q0 17 11.5 28.5T480-280q17 0 28.5-11.5T520-320v-320q0-17-11.5-28.5T480-680Zm160 240q-17 0-28.5 11.5T600-400v80q0 17 11.5 28.5T640-280q17 0 28.5-11.5T680-320v-80q0-17-11.5-28.5T640-440Z',\n  INSERT_CHART_FILLED: 'M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-440q-17 0-28.5 11.5T280-520v200q0 17 11.5 28.5T320-280q17 0 28.5-11.5T360-320v-200q0-17-11.5-28.5T320-560Zm160-120q-17 0-28.5 11.5T440-640v320q0 17 11.5 28.5T480-280q17 0 28.5-11.5T520-320v-320q0-17-11.5-28.5T480-680Zm160 240q-17 0-28.5 11.5T600-400v80q0 17 11.5 28.5T640-280q17 0 28.5-11.5T680-320v-80q0-17-11.5-28.5T640-440Z',\n  VARIABLES_DEFAULT: 'M120-320v-320q0-17 11.5-28.5T160-680h640q17 0 28.5 11.5T840-640v320q0 17-11.5 28.5T800-280H160q-17 0-28.5-11.5T120-320Zm80-40h560v-240H200v240Zm0 0v-240 240Z',\n  OPEN_IN_FULL_FILLED: 'M160-120q-17 0-28.5-11.5T120-160v-240q0-17 11.5-28.5T160-440q17 0 28.5 11.5T200-400v144l504-504H560q-17 0-28.5-11.5T520-800q0-17 11.5-28.5T560-840h240q17 0 28.5 11.5T840-800v240q0 17-11.5 28.5T800-520q-17 0-28.5-11.5T760-560v-144L256-200h144q17 0 28.5 11.5T440-160q0 17-11.5 28.5T400-120H160Z',\n  PAUSE_CIRCLE_FILLED: 'M400-320q17 0 28.5-11.5T440-360v-240q0-17-11.5-28.5T400-640q-17 0-28.5 11.5T360-600v240q0 17 11.5 28.5T400-320Zm160 0q17 0 28.5-11.5T600-360v-240q0-17-11.5-28.5T560-640q-17 0-28.5 11.5T520-600v240q0 17 11.5 28.5T560-320ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z',\n  PHOTO_CAMERA_FILLED: 'M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l50-54q11-12 26.5-19t32.5-7h170q17 0 32.5 7t26.5 19l50 54h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Z',\n  PLAY_CIRCLE_FILLED: 'm426-330 195-125q14-9 14-25t-14-25L426-630q-15-10-30.5-1.5T380-605v250q0 18 15.5 26.5T426-330Zm54 250q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z',\n  RECORD_VOICE_OVER_FILLED: 'M920-600q0 69-24.5 131.5T829-355q-12 14-30 15t-32-13q-13-13-12-31t12-33q30-38 46.5-85t16.5-98q0-51-16.5-97T767-781q-12-15-12.5-33t12.5-32q13-14 31.5-13.5T829-845q42 51 66.5 113.5T920-600Zm-182 0q0 32-10 61.5T700-484q-11 15-29.5 15.5T638-482q-13-13-13.5-31.5T633-549q6-11 9.5-24t3.5-27q0-14-3.5-27t-9.5-25q-9-17-8.5-35t13.5-31q14-14 32.5-13.5T700-716q18 25 28 54.5t10 61.5ZM360-440q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM40-200v-32q0-33 17-62t47-44q51-26 115-44t141-18q77 0 141 18t115 44q30 15 47 44t17 62v32q0 33-23.5 56.5T600-120H120q-33 0-56.5-23.5T40-200Z',\n  TUNE_FILLED: 'M480-120q-17 0-28.5-11.5T440-160v-160q0-17 11.5-28.5T480-360q17 0 28.5 11.5T520-320v40h280q17 0 28.5 11.5T840-240q0 17-11.5 28.5T800-200H520v40q0 17-11.5 28.5T480-120Zm-320-80q-17 0-28.5-11.5T120-240q0-17 11.5-28.5T160-280h160q17 0 28.5 11.5T360-240q0 17-11.5 28.5T320-200H160Zm160-160q-17 0-28.5-11.5T280-400v-40H160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520h120v-40q0-17 11.5-28.5T320-600q17 0 28.5 11.5T360-560v160q0 17-11.5 28.5T320-360Zm160-80q-17 0-28.5-11.5T440-480q0-17 11.5-28.5T480-520h320q17 0 28.5 11.5T840-480q0 17-11.5 28.5T800-440H480Zm160-160q-17 0-28.5-11.5T600-640v-160q0-17 11.5-28.5T640-840q17 0 28.5 11.5T680-800v40h120q17 0 28.5 11.5T840-720q0 17-11.5 28.5T800-680H680v40q0 17-11.5 28.5T640-600Zm-480-80q-17 0-28.5-11.5T120-720q0-17 11.5-28.5T160-760h320q17 0 28.5 11.5T520-720q0 17-11.5 28.5T480-680H160Z',\n  RECTANGLE_DEFAULT: 'M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z',\n  SKIP_NEXT_FILLED: 'M660-280v-400q0-17 11.5-28.5T700-720q17 0 28.5 11.5T740-680v400q0 17-11.5 28.5T700-240q-17 0-28.5-11.5T660-280Zm-440-35v-330q0-18 12-29t28-11q5 0 11 1t11 5l248 166q9 6 13.5 14.5T548-480q0 10-4.5 18.5T530-447L282-281q-5 4-11 5t-11 1q-16 0-28-11t-12-29Z',\n  SKIP_PREVIOUS_FILLED: 'M220-280v-400q0-17 11.5-28.5T260-720q17 0 28.5 11.5T300-680v400q0 17-11.5 28.5T260-240q-17 0-28.5-11.5T220-280Zm458-1L430-447q-9-6-13.5-14.5T412-480q0-10 4.5-18.5T430-513l248-166q5-4 11-5t11-1q16 0 28 11t12 29v330q0 18-12 29t-28 11q-5 0-11-1t-11-5Z'\n}\n\nconst UnsupportedPlayerActions = /** @type {const} */({\n  STARTING_VIDEO_AT_OFFSET: 1,\n  PLAYBACK_RATE: 2,\n  OPENING_PLAYLISTS: 3,\n  PLAYLIST_SPECIFIC_VIDEO: 4,\n  PLAYLIST_REVERSE: 5,\n  PLAYLIST_SHUFFLE: 6,\n  PLAYLIST_LOOP: 7,\n})\n\n/**\n * @typedef {UnsupportedPlayerActions[(keyof typeof UnsupportedPlayerActions)]} UnsupportedPlayerAction\n */\n\n// Utils\nconst MAIN_PROFILE_ID = 'allChannels'\n\n// Width threshold in px at which we switch to using a more heavily altered view for mobile users\nconst MOBILE_WIDTH_THRESHOLD = 680\n\n// Height threshold in px at which we switch to using a more heavily altered playlist view for mobile users\nconst PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD = 500\n\n// YouTube search character limit is 100 characters\nconst SEARCH_CHAR_LIMIT = 100\n\n// max # of results we show for search suggestions\nconst SEARCH_RESULTS_DISPLAY_LIMIT = 14\n\n// max # of search history results we show when mixed with YT search suggestions\nconst MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT = 4\n\n// Displayed on the about page and used in the main.js file to only allow bitcoin URLs with this wallet address to be opened\nconst ABOUT_BITCOIN_ADDRESS = '1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS'\n\nexport {\n  IpcChannels,\n  DBActions,\n  SyncEvents,\n  KeyboardShortcuts,\n  PlayerIcons,\n  UnsupportedPlayerActions,\n  MAIN_PROFILE_ID,\n  MOBILE_WIDTH_THRESHOLD,\n  PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD,\n  SEARCH_CHAR_LIMIT,\n  SEARCH_RESULTS_DISPLAY_LIMIT,\n  MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT,\n  ABOUT_BITCOIN_ADDRESS,\n}\n"
  },
  {
    "path": "src/data/.gitkeep",
    "content": ""
  },
  {
    "path": "src/datastores/handlers/base.js",
    "content": "import * as db from '../index'\n\nclass Settings {\n  static async find() {\n    const currentLocale = await db.settings.findOneAsync({ _id: 'currentLocale' })\n\n    // In FreeTube 0.21.3 and earlier the locales 'en-GB', 'es-AR' and 'nb-NO' had underscores instead of a hyphens\n    // This is a one time migration for users that are using one of those locales\n    if (currentLocale?.value.includes('_')) {\n      await this.upsert('currentLocale', currentLocale.value.replace('_', '-'))\n    }\n\n    // In FreeTube 0.22.0 and earlier the external player arguments were displayed in a text box,\n    // with the user manually entering `;` to separate the different arguments.\n    // This is a one time migration that converts the old string to a JSON array\n    const externalPlayerCustomArgs = await db.settings.findOneAsync({ _id: 'externalPlayerCustomArgs' })\n\n    if (externalPlayerCustomArgs && !externalPlayerCustomArgs.value.startsWith('[')) {\n      let newValue = '[]'\n\n      if (externalPlayerCustomArgs.value.length > 0) {\n        newValue = JSON.stringify(externalPlayerCustomArgs.value.split(';'))\n      }\n\n      await this.upsert('externalPlayerCustomArgs', newValue)\n    }\n\n    // In FreeTube 0.23.0, the \"Enable Theatre Mode by Default\" setting was incoporated as an option\n    // of the \"Default Viewing Mode\" setting. This is a one time migration to preserve users'\n    // Theater Mode preference through this change.\n    const defaultTheatreMode = await db.settings.findOneAsync({ _id: 'defaultTheatreMode' })\n\n    if (defaultTheatreMode) {\n      if (defaultTheatreMode.value) {\n        await this.upsert('defaultViewingMode', 'theatre')\n      }\n\n      await db.settings.removeAsync({ _id: 'defaultTheatreMode' })\n    }\n\n    const saveWatchedProgress = await db.settings.findOneAsync({ _id: 'saveWatchedProgress' })\n    const watchedProgressSavingMode = await db.settings.findOneAsync({ _id: 'watchedProgressSavingMode' })\n    if (saveWatchedProgress && !watchedProgressSavingMode) {\n      if (!saveWatchedProgress.value) {\n        await this.upsert('watchedProgressSavingMode', 'never')\n      }\n\n      await db.settings.removeAsync({ _id: 'saveWatchedProgress' })\n    }\n\n    return db.settings.findAsync({ _id: { $ne: 'bounds' } })\n  }\n\n  static upsert(_id, value) {\n    return db.settings.updateAsync({ _id }, { _id, value }, { upsert: true })\n  }\n\n  // ******************** //\n  // Unique Electron main process handlers\n  static _findAppReadyRelatedSettings() {\n    return db.settings.findAsync({\n      _id: {\n        $in: [\n          'disableSmoothScrolling',\n          'useProxy',\n          'proxyProtocol',\n          'proxyHostname',\n          'proxyPort',\n          'backendFallback',\n          'backendPreference',\n          'hideToTrayOnMinimize'\n        ]\n      }\n    })\n  }\n\n  static _findOne(_id) {\n    return db.settings.findOneAsync({ _id })\n  }\n\n  static _findSidenavSettings() {\n    return {\n      hideTrendingVideos: db.settings.findOneAsync({ _id: 'hideTrendingVideos' }),\n      hidePopularVideos: db.settings.findOneAsync({ _id: 'hidePopularVideos' }),\n      hidePlaylists: db.settings.findOneAsync({ _id: 'hidePlaylists' }),\n    }\n  }\n\n  static _updateBounds(value) {\n    return db.settings.updateAsync({ _id: 'bounds' }, { _id: 'bounds', value }, { upsert: true })\n  }\n  // ******************** //\n}\n\nclass History {\n  static find() {\n    return db.history.findAsync({}).sort({ timeWatched: -1 })\n  }\n\n  static upsert(record) {\n    return db.history.updateAsync({ videoId: record.videoId }, record, { upsert: true })\n  }\n\n  static async overwrite(records) {\n    await db.history.removeAsync({}, { multi: true })\n\n    await db.history.insertAsync(records)\n  }\n\n  static updateWatchProgress(videoId, watchProgress) {\n    return db.history.updateAsync({ videoId }, { $set: { watchProgress } }, { upsert: true })\n  }\n\n  static updateLastViewedPlaylist(videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId) {\n    return db.history.updateAsync({ videoId }, { $set: { lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId } }, { upsert: true })\n  }\n\n  static delete(videoId) {\n    return db.history.removeAsync({ videoId })\n  }\n\n  static deleteAll() {\n    return db.history.removeAsync({}, { multi: true })\n  }\n}\n\nclass Profiles {\n  static create(profile) {\n    return db.profiles.insertAsync(profile)\n  }\n\n  static find() {\n    return db.profiles.findAsync({})\n  }\n\n  static upsert(profile) {\n    return db.profiles.updateAsync({ _id: profile._id }, profile, { upsert: true })\n  }\n\n  static addChannelToProfiles(channel, profileIds) {\n    if (profileIds.length === 1) {\n      return db.profiles.updateAsync(\n        { _id: profileIds[0] },\n        { $push: { subscriptions: channel } }\n      )\n    } else {\n      return db.profiles.updateAsync(\n        { _id: { $in: profileIds } },\n        { $push: { subscriptions: channel } },\n        { multi: true }\n      )\n    }\n  }\n\n  static removeChannelFromProfiles(channelId, profileIds) {\n    if (profileIds.length === 1) {\n      return db.profiles.updateAsync(\n        { _id: profileIds[0] },\n        { $pull: { subscriptions: { id: channelId } } }\n      )\n    } else {\n      return db.profiles.updateAsync(\n        { _id: { $in: profileIds } },\n        { $pull: { subscriptions: { id: channelId } } },\n        { multi: true }\n      )\n    }\n  }\n\n  static delete(id) {\n    return db.profiles.removeAsync({ _id: id })\n  }\n}\n\nclass Playlists {\n  static create(playlists) {\n    return db.playlists.insertAsync(playlists)\n  }\n\n  static find() {\n    return db.playlists.findAsync({})\n  }\n\n  static upsert(playlist) {\n    return db.playlists.updateAsync({ _id: playlist._id }, { $set: playlist }, { upsert: true })\n  }\n\n  static upsertVideoByPlaylistId(_id, lastUpdatedAt, videoData) {\n    return db.playlists.updateAsync(\n      { _id },\n      {\n        $push: { videos: videoData },\n        $set: { lastUpdatedAt }\n      },\n      { upsert: true }\n    )\n  }\n\n  static upsertVideosByPlaylistId(_id, lastUpdatedAt, videos) {\n    return db.playlists.updateAsync(\n      { _id },\n      {\n        $push: { videos: { $each: videos } },\n        $set: { lastUpdatedAt }\n      },\n      { upsert: true }\n    )\n  }\n\n  static delete(_id) {\n    return db.playlists.removeAsync({ _id, protected: { $ne: true } })\n  }\n\n  static deleteVideoIdByPlaylistId(_id, lastUpdatedAt, videoId, playlistItemId) {\n    if (playlistItemId != null) {\n      return db.playlists.updateAsync(\n        { _id },\n        {\n          $pull: { videos: { playlistItemId } },\n          $set: { lastUpdatedAt }\n        },\n        { upsert: true }\n      )\n    } else if (videoId != null) {\n      return db.playlists.updateAsync(\n        { _id },\n        {\n          $pull: { videos: { videoId } },\n          $set: { lastUpdatedAt }\n        },\n        { upsert: true }\n      )\n    } else {\n      throw new Error(`Both videoId & playlistItemId are absent, _id: ${_id}`)\n    }\n  }\n\n  static deleteVideoIdsByPlaylistId(_id, lastUpdatedAt, playlistItemIds) {\n    return db.playlists.updateAsync(\n      { _id },\n      {\n        $pull: { videos: { playlistItemId: { $in: playlistItemIds } } },\n        $set: { lastUpdatedAt }\n      },\n      { upsert: true }\n    )\n  }\n\n  static deleteAllVideosByPlaylistId(_id) {\n    return db.playlists.updateAsync(\n      { _id },\n      { $set: { videos: [] } },\n      { upsert: true }\n    )\n  }\n\n  static deleteMultiple(ids) {\n    return db.playlists.removeAsync({ _id: { $in: ids }, protected: { $ne: true } })\n  }\n\n  static deleteAll() {\n    return db.playlists.removeAsync({}, { multi: true })\n  }\n}\n\nclass SearchHistory {\n  static find() {\n    return db.searchHistory.findAsync({}).sort({ lastUpdatedAt: -1 })\n  }\n\n  static upsert(searchHistoryEntry) {\n    return db.searchHistory.updateAsync({ _id: searchHistoryEntry._id }, searchHistoryEntry, { upsert: true })\n  }\n\n  static async overwrite(records) {\n    await db.searchHistory.removeAsync({}, { multi: true })\n\n    await db.searchHistory.insertAsync(records)\n  }\n\n  static delete(_id) {\n    return db.searchHistory.removeAsync({ _id: _id })\n  }\n\n  static deleteAll() {\n    return db.searchHistory.removeAsync({}, { multi: true })\n  }\n}\n\nclass SubscriptionCache {\n  static find() {\n    return db.subscriptionCache.findAsync({})\n  }\n\n  static updateVideosByChannelId(channelId, entries, timestamp) {\n    return db.subscriptionCache.updateAsync(\n      { _id: channelId },\n      { $set: { videos: entries, videosTimestamp: timestamp } },\n      { upsert: true }\n    )\n  }\n\n  static updateLiveStreamsByChannelId(channelId, entries, timestamp) {\n    return db.subscriptionCache.updateAsync(\n      { _id: channelId },\n      { $set: { liveStreams: entries, liveStreamsTimestamp: timestamp } },\n      { upsert: true }\n    )\n  }\n\n  static updateShortsByChannelId(channelId, entries, timestamp) {\n    return db.subscriptionCache.updateAsync(\n      { _id: channelId },\n      { $set: { shorts: entries, shortsTimestamp: timestamp } },\n      { upsert: true }\n    )\n  }\n\n  static async updateShortsWithChannelPageShortsByChannelId(channelId, entries) {\n    const doc = await db.subscriptionCache.findOneAsync({ _id: channelId }, { shorts: 1 })\n\n    if (!Array.isArray(doc?.shorts)) {\n      return\n    }\n\n    let hasUpdates = false\n\n    doc.shorts.forEach(cachedVideo => {\n      const channelVideo = entries.find(short => cachedVideo.videoId === short.videoId)\n      if (!channelVideo) { return }\n\n      hasUpdates = true\n\n      // authorId probably never changes, so we don't need to update that\n      cachedVideo.title = channelVideo.title\n      cachedVideo.author = channelVideo.author\n\n      // as the channel shorts page only has compact view counts for numbers above 1000 e.g. 12k\n      // and the RSS feeds include an exact value, we only want to overwrite it when the number is larger than the cached value\n      // 12345 vs 12000 => 12345\n      // 12345 vs 15000 => 15000\n      if (channelVideo.viewCount > cachedVideo.viewCount) {\n        cachedVideo.viewCount = channelVideo.viewCount\n      }\n    })\n\n    if (hasUpdates) {\n      await db.subscriptionCache.updateAsync(\n        { _id: channelId },\n        { $set: { shorts: doc.shorts } }\n      )\n    }\n  }\n\n  static updateCommunityPostsByChannelId(channelId, entries, timestamp) {\n    return db.subscriptionCache.updateAsync(\n      { _id: channelId },\n      { $set: { communityPosts: entries, communityPostsTimestamp: timestamp } },\n      { upsert: true }\n    )\n  }\n\n  static deleteMultipleChannels(channelIds) {\n    return db.subscriptionCache.removeAsync({ _id: { $in: channelIds } }, { multi: true })\n  }\n\n  static deleteAll() {\n    return db.subscriptionCache.removeAsync({}, { multi: true })\n  }\n}\n\nfunction loadDatastores() {\n  return Promise.allSettled([\n    db.settings.loadDatabaseAsync(),\n    db.history.loadDatabaseAsync(),\n    db.profiles.loadDatabaseAsync(),\n    db.playlists.loadDatabaseAsync(),\n    db.searchHistory.loadDatabaseAsync(),\n    db.subscriptionCache.loadDatabaseAsync(),\n  ])\n}\n\nfunction compactAllDatastores() {\n  return Promise.allSettled([\n    db.settings.compactDatafileAsync(),\n    db.history.compactDatafileAsync(),\n    db.profiles.compactDatafileAsync(),\n    db.playlists.compactDatafileAsync(),\n    db.searchHistory.compactDatafileAsync(),\n    db.subscriptionCache.compactDatafileAsync(),\n  ])\n}\n\nexport {\n  Settings as settings,\n  History as history,\n  Profiles as profiles,\n  Playlists as playlists,\n  SearchHistory as searchHistory,\n  SubscriptionCache as subscriptionCache,\n\n  loadDatastores,\n  compactAllDatastores,\n}\n"
  },
  {
    "path": "src/datastores/handlers/electron.js",
    "content": "import { DBActions } from '../../constants'\n\nclass Settings {\n  static find() {\n    return window.ftElectron.dbSettings(DBActions.GENERAL.FIND)\n  }\n\n  static upsert(_id, value) {\n    return window.ftElectron.dbSettings(DBActions.GENERAL.UPSERT, { _id, value })\n  }\n}\n\nclass History {\n  static find() {\n    return window.ftElectron.dbHistory(DBActions.GENERAL.FIND)\n  }\n\n  static upsert(record) {\n    return window.ftElectron.dbHistory(DBActions.GENERAL.UPSERT, record)\n  }\n\n  static overwrite(records) {\n    return window.ftElectron.dbHistory(DBActions.GENERAL.OVERWRITE, records)\n  }\n\n  static updateWatchProgress(videoId, watchProgress) {\n    return window.ftElectron.dbHistory(\n      DBActions.HISTORY.UPDATE_WATCH_PROGRESS,\n      { videoId, watchProgress }\n    )\n  }\n\n  static updateLastViewedPlaylist(videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId) {\n    return window.ftElectron.dbHistory(\n      DBActions.HISTORY.UPDATE_PLAYLIST,\n      { videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId }\n    )\n  }\n\n  static delete(videoId) {\n    return window.ftElectron.dbHistory(DBActions.GENERAL.DELETE, videoId)\n  }\n\n  static deleteAll() {\n    return window.ftElectron.dbHistory(DBActions.GENERAL.DELETE_ALL)\n  }\n}\n\nclass Profiles {\n  static create(profile) {\n    return window.ftElectron.dbProfiles(DBActions.GENERAL.CREATE, profile)\n  }\n\n  static find() {\n    return window.ftElectron.dbProfiles(DBActions.GENERAL.FIND)\n  }\n\n  static upsert(profile) {\n    return window.ftElectron.dbProfiles(DBActions.GENERAL.UPSERT, profile)\n  }\n\n  static addChannelToProfiles(channel, profileIds) {\n    return window.ftElectron.dbProfiles(DBActions.PROFILES.ADD_CHANNEL, { channel, profileIds })\n  }\n\n  static removeChannelFromProfiles(channelId, profileIds) {\n    return window.ftElectron.dbProfiles(DBActions.PROFILES.REMOVE_CHANNEL, { channelId, profileIds })\n  }\n\n  static delete(id) {\n    return window.ftElectron.dbProfiles(DBActions.GENERAL.DELETE, id)\n  }\n}\n\nclass Playlists {\n  static create(playlists) {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.CREATE, playlists)\n  }\n\n  static find() {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.FIND)\n  }\n\n  static upsert(playlist) {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.UPSERT, playlist)\n  }\n\n  static upsertVideoByPlaylistId(_id, lastUpdatedAt, videoData) {\n    return window.ftElectron.dbPlaylists(\n      DBActions.PLAYLISTS.UPSERT_VIDEO,\n      { _id, lastUpdatedAt, videoData }\n    )\n  }\n\n  static upsertVideosByPlaylistId(_id, lastUpdatedAt, videos) {\n    return window.ftElectron.dbPlaylists(\n      DBActions.PLAYLISTS.UPSERT_VIDEOS,\n      { _id, lastUpdatedAt, videos }\n    )\n  }\n\n  static delete(_id) {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.DELETE, _id)\n  }\n\n  static deleteVideoIdByPlaylistId(_id, lastUpdatedAt, videoId, playlistItemId) {\n    return window.ftElectron.dbPlaylists(\n      DBActions.PLAYLISTS.DELETE_VIDEO_ID,\n      { _id, lastUpdatedAt, videoId, playlistItemId }\n    )\n  }\n\n  static deleteVideoIdsByPlaylistId(_id, lastUpdatedAt, playlistItemIds) {\n    return window.ftElectron.dbPlaylists(\n      DBActions.PLAYLISTS.DELETE_VIDEO_IDS,\n      { _id, lastUpdatedAt, playlistItemIds }\n    )\n  }\n\n  static deleteAllVideosByPlaylistId(_id) {\n    return window.ftElectron.dbPlaylists(DBActions.PLAYLISTS.DELETE_ALL_VIDEOS, _id)\n  }\n\n  static deleteMultiple(ids) {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.DELETE_MULTIPLE, ids)\n  }\n\n  static deleteAll() {\n    return window.ftElectron.dbPlaylists(DBActions.GENERAL.DELETE_ALL)\n  }\n}\n\nclass SearchHistory {\n  static find() {\n    return window.ftElectron.dbSearchHistory(DBActions.GENERAL.FIND)\n  }\n\n  static upsert(searchHistoryEntry) {\n    return window.ftElectron.dbSearchHistory(DBActions.GENERAL.UPSERT, searchHistoryEntry)\n  }\n\n  static overwrite(records) {\n    return window.ftElectron.dbSearchHistory(DBActions.GENERAL.OVERWRITE, records)\n  }\n\n  static delete(_id) {\n    return window.ftElectron.dbSearchHistory(DBActions.GENERAL.DELETE, _id)\n  }\n\n  static deleteAll() {\n    return window.ftElectron.dbSearchHistory(DBActions.GENERAL.DELETE_ALL)\n  }\n}\n\nclass SubscriptionCache {\n  static find() {\n    return window.ftElectron.dbSubscriptionCache(DBActions.GENERAL.FIND)\n  }\n\n  static updateVideosByChannelId(channelId, entries, timestamp) {\n    return window.ftElectron.dbSubscriptionCache(\n      DBActions.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL,\n      { channelId, entries, timestamp }\n    )\n  }\n\n  static updateLiveStreamsByChannelId(channelId, entries, timestamp) {\n    return window.ftElectron.dbSubscriptionCache(\n      DBActions.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL,\n      { channelId, entries, timestamp }\n    )\n  }\n\n  static updateShortsByChannelId(channelId, entries, timestamp) {\n    return window.ftElectron.dbSubscriptionCache(\n      DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL,\n      { channelId, entries, timestamp }\n    )\n  }\n\n  static updateShortsWithChannelPageShortsByChannelId(channelId, entries) {\n    return window.ftElectron.dbSubscriptionCache(\n      DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL,\n      { channelId, entries }\n    )\n  }\n\n  static updateCommunityPostsByChannelId(channelId, entries, timestamp) {\n    return window.ftElectron.dbSubscriptionCache(\n      DBActions.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL,\n      { channelId, entries, timestamp }\n    )\n  }\n\n  static deleteMultipleChannels(channelIds) {\n    return window.ftElectron.dbSubscriptionCache(DBActions.GENERAL.DELETE_MULTIPLE, channelIds)\n  }\n\n  static deleteAll() {\n    return window.ftElectron.dbSubscriptionCache(DBActions.GENERAL.DELETE_ALL)\n  }\n}\n\nexport {\n  Settings as settings,\n  History as history,\n  Profiles as profiles,\n  Playlists as playlists,\n  SearchHistory as searchHistory,\n  SubscriptionCache as subscriptionCache,\n}\n"
  },
  {
    "path": "src/datastores/handlers/index.js",
    "content": "export {\n  settings as DBSettingHandlers,\n  history as DBHistoryHandlers,\n  profiles as DBProfileHandlers,\n  playlists as DBPlaylistHandlers,\n  searchHistory as DBSearchHistoryHandlers,\n  subscriptionCache as DBSubscriptionCacheHandlers,\n} from 'DB_HANDLERS_ELECTRON_RENDERER_OR_WEB'\n"
  },
  {
    "path": "src/datastores/handlers/web.js",
    "content": "import * as baseHandlers from './base'\n\n// TODO: Syncing\n// Syncing on the web would involve a different implementation\n// to the electron one (obviously)\n// One idea would be to use a watcher-like mechanism on\n// localStorage or IndexedDB to inform other tabs on the changes\n// that have occurred in other tabs\n//\n// NOTE: NeDB uses `localForage` on the browser\n// https://www.npmjs.com/package/localforage\n\nclass Settings {\n  static find() {\n    return baseHandlers.settings.find()\n  }\n\n  static upsert(_id, value) {\n    return baseHandlers.settings.upsert(_id, value)\n  }\n}\n\n// For the settings we use the wrapper class to hide some methods only needed in the Electron main process\nexport { Settings as settings }\n\n// These classes don't require any changes from the base classes, so can be exported as-is.\nexport { history, profiles, playlists, searchHistory, subscriptionCache } from './base'\n"
  },
  {
    "path": "src/datastores/index.js",
    "content": "import Datastore from '@seald-io/nedb'\n\nlet dbPath = null\n\nif (process.env.IS_ELECTRON_MAIN) {\n  const { app } = require('electron')\n  const { join } = require('path')\n  // this code only runs in the electron main process, so hopefully using sync fs code here should be fine 😬\n  const { statSync, realpathSync } = require('fs')\n  const userDataPath = app.getPath('userData') // This is based on the user's OS\n  dbPath = (dbName) => {\n    let path = join(userDataPath, `${dbName}.db`)\n\n    // returns undefined if the path doesn't exist\n    if (statSync(path, { throwIfNoEntry: false })?.isSymbolicLink) {\n      path = realpathSync(path)\n    }\n\n    return path\n  }\n} else {\n  dbPath = (dbName) => `${dbName}.db`\n}\n\n/**\n * @param {string} name\n */\nfunction createDatastore(name) {\n  return new Datastore({\n    filename: dbPath(name),\n    autoload: !process.env.IS_ELECTRON_MAIN,\n    // Automatically clean up corrupted data, instead of crashing\n    corruptAlertThreshold: 1\n  })\n}\n\nexport const settings = createDatastore('settings')\nexport const profiles = createDatastore('profiles')\nexport const playlists = createDatastore('playlists')\nexport const history = createDatastore('history')\nexport const searchHistory = createDatastore('search-history')\nexport const subscriptionCache = createDatastore('subscription-cache')\n"
  },
  {
    "path": "src/index.ejs",
    "content": "<!DOCTYPE html>\n<html>\n\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\"\n          content=\"width=device-width, initial-scale=1.0\" />\n    <% if (!process.env.IS_ELECTRON) { %>\n    <link rel=\"manifest\" href=\"static/manifest.json\" />\n    <% } %>\n    <title></title>\n  </head>\n\n  <body>\n    <div id=\"app\"></div>\n    <% if (process.env.IS_ELECTRON) { %>\n    <iframe\n      id=\"sigFrame\"\n      src=\"<%= sigFrameSrc %>\"\n      csp=\"default-src 'none'; script-src '<%= sigFrameCspHash %>' 'unsafe-eval'\"\n      sandbox=\"allow-scripts\"\n      height=\"1\"\n      width=\"1\"\n      style=\"display: none; pointer-events: none\"\n      tabindex=\"-1\"\n    ></iframe>\n    <% } else { %>\n    <script>\n    // This is the service worker with the Advanced caching\n\n    // Add this below content to your HTML page, or add the js file to your page at the very top to register service worker\n\n    // Check compatibility for the browser we're running this in\n    if (\"serviceWorker\" in navigator) {\n      if (navigator.serviceWorker.controller) {\n        console.log(\"[PWA Builder] active service worker found, no need to register\");\n      } else {\n        // Register the service worker\n        navigator.serviceWorker\n          .register(\"pwabuilder-sw.js\", {\n            scope: \"./\"\n          })\n          .then(function (reg) {\n            console.log(\"[PWA Builder] Service worker has been registered for scope: \" + reg.scope);\n          });\n      }\n    }\n    </script>\n    <% } %>\n    <!-- webpack builds are automatically injected -->\n  </body>\n\n</html>\n"
  },
  {
    "path": "src/main/ImageCache.js",
    "content": "// cleanup expired images once every 5 mins\nconst CLEANUP_INTERVAL = 300_000\n\n// images expire after 2 hours if no expiry information is found in the http headers\nconst FALLBACK_MAX_AGE = 7200\n\nexport class ImageCache {\n  constructor() {\n    this._cache = new Map()\n\n    setInterval(this._cleanup.bind(this), CLEANUP_INTERVAL)\n  }\n\n  add(url, mimeType, data, expiry) {\n    this._cache.set(url, { mimeType, data, expiry })\n  }\n\n  has(url) {\n    return this._cache.has(url)\n  }\n\n  get(url) {\n    const entry = this._cache.get(url)\n\n    if (!entry) {\n      // this should never happen as the `has` method should be used to check for the existence first\n      throw new Error(`No image cache entry for ${url}`)\n    }\n\n    return {\n      data: entry.data,\n      mimeType: entry.mimeType\n    }\n  }\n\n  _cleanup() {\n    // seconds since 1970-01-01 00:00:00\n    const now = Math.trunc(Date.now() / 1000)\n\n    for (const [key, entry] of this._cache.entries()) {\n      if (entry.expiry <= now) {\n        this._cache.delete(key)\n      }\n    }\n  }\n}\n\n/**\n * Extracts the cache expiry timestamp of image from HTTP headers\n * @param {Record<string, string>} headers\n * @returns a timestamp in seconds\n */\nexport function extractExpiryTimestamp(headers) {\n  const maxAgeRegex = /max-age=(\\d+)/\n\n  const cacheControl = headers['cache-control']\n  if (cacheControl && maxAgeRegex.test(cacheControl)) {\n    let maxAge = parseInt(cacheControl.match(maxAgeRegex)[1])\n\n    if (headers.age) {\n      maxAge -= parseInt(headers.age)\n    }\n\n    // we don't need millisecond precision, so we can store it as seconds to use less memory\n    return Math.trunc(Date.now() / 1000) + maxAge\n  } else if (headers.expires) {\n    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires\n\n    return Math.trunc(Date.parse(headers.expires) / 1000)\n  } else {\n    return Math.trunc(Date.now() / 1000) + FALLBACK_MAX_AGE\n  }\n}\n"
  },
  {
    "path": "src/main/externalPlayer.js",
    "content": "import { spawn } from 'node:child_process'\nimport { join } from 'node:path'\nimport { readFile } from 'node:fs/promises'\nimport { settings } from '../datastores/handlers/base'\nimport { isFreeTubeUrl } from './utils'\nimport { IpcChannels, UnsupportedPlayerActions } from '../constants'\n\n/**\n * @typedef ExternalPlayerPayload\n * @property {string | undefined | null} [videoId]\n * @property {string | undefined | null} [playlistId]\n * @property {number | undefined | null} [startTime]\n * @property {number | undefined | null} [playbackRate]\n * @property {number | undefined | null} [playlistIndex]\n * @property {boolean | undefined | null} [playlistReverse]\n * @property {boolean | undefined | null} [playlistShuffle]\n * @property {boolean | undefined | null} [playlistLoop]\n */\n\n/**\n * @typedef CmdArgs\n * @property {string} defaultExecutable\n * @property {string[] | null} defaultCustomArguments\n * @property {string} videoUrl\n * @property {string | null} playlistUrl\n * @property {string | null} startOffset\n * @property {string | null} playbackRate\n * @property {string | null} playlistIndex\n * @property {string | null} playlistReverse\n * @property {string | null} playlistShuffle\n * @property {string | null} playlistLoop\n */\n\nconst ID_REGEX = /^[\\w-]+$/\n\n/** @type {Map<string, CmdArgs>} */\nconst externalPlayerCmdArgs = new Map()\n\n/**\n * @param {import('electron').IpcMainEvent} event\n * @param {ExternalPlayerPayload} payload\n */\nexport async function handleOpenInExternalPlayer(event, payload) {\n  if (!isFreeTubeUrl(event.senderFrame.url) || !event.sender.isFocused()) {\n    return\n  }\n\n  const hasValidVideoId = typeof payload.videoId === 'string' && payload.videoId.length === 11 && ID_REGEX.test(payload.videoId)\n  const hasValidPlaylistId = typeof payload.playlistId === 'string' && payload.playlistId.length > 2 && ID_REGEX.test(payload.playlistId)\n\n  if (!hasValidVideoId && !hasValidPlaylistId) {\n    return\n  }\n\n  /** @type {string} */\n  const externalPlayer = (await settings._findOne('externalPlayer'))?.value || ''\n\n  // External player setting not set or set to \"none\"\n  if (externalPlayer === '') {\n    return\n  }\n\n  if (externalPlayerCmdArgs.size === 0) {\n    await loadExternalPlayerData()\n  }\n\n  const cmdArgs = externalPlayerCmdArgs.get(externalPlayer)\n\n  if (cmdArgs === undefined) {\n    return\n  }\n\n  const args = []\n  /** @type {import('../constants').UnsupportedPlayerAction[]} */\n  const unsupportedActions = []\n\n  /** @type {boolean} */\n  const ignoreWarnings = (await settings._findOne('externalPlayerIgnoreWarnings'))?.value || false\n\n  /** @type {boolean} */\n  const ignoreDefaultArgs = (await settings._findOne('externalPlayerIgnoreDefaultArgs'))?.value || false\n\n  /** @type {string[] | string} */\n  const customArgs = (await settings._findOne('externalPlayerCustomArgs'))?.value || '[]'\n\n  if (typeof customArgs === 'string' && customArgs !== '[]') {\n    args.push(...JSON.parse(customArgs))\n  } else if (!ignoreDefaultArgs && Array.isArray(cmdArgs.defaultCustomArguments)) {\n    args.push(...cmdArgs.defaultCustomArguments)\n  }\n\n  if (ignoreDefaultArgs) {\n    if (hasValidVideoId) {\n      args.push(`${cmdArgs.videoUrl}https://www.youtube.com/watch?v=${payload.videoId}`)\n    }\n  } else {\n    if (typeof payload.startTime === 'number' && payload.startTime > 0) {\n      if (typeof cmdArgs.startOffset === 'string') {\n        if (cmdArgs.defaultExecutable.startsWith('mpc')) {\n          // For mpc-hc and mpc-be, which require startOffset to be in milliseconds\n          args.push(cmdArgs.startOffset, 1000 * Math.trunc(payload.startTime))\n        } else if (cmdArgs.startOffset.endsWith('=')) {\n          // For players using `=` in arguments\n          // e.g. vlc --start-time=xxxxx\n          args.push(`${cmdArgs.startOffset}${payload.startTime}`)\n        } else {\n          // For players using space in arguments\n          // e.g. smplayer -start xxxxx\n          args.push(cmdArgs.startOffset, Math.trunc(payload.startTime))\n        }\n      } else if (!ignoreWarnings) {\n        unsupportedActions.push(UnsupportedPlayerActions.STARTING_VIDEO_AT_OFFSET)\n      }\n    }\n\n    if (typeof payload.playbackRate === 'number' && payload.playbackRate > 0) {\n      if (typeof cmdArgs.playbackRate === 'string') {\n        args.push(`${cmdArgs.playbackRate}${payload.playbackRate}`)\n      } else if (!ignoreWarnings) {\n        unsupportedActions.push(UnsupportedPlayerActions.PLAYBACK_RATE)\n      }\n    }\n\n    // Check whether the video is in a playlist\n    if (hasValidPlaylistId && typeof cmdArgs.playlistUrl === 'string') {\n      if (typeof payload.playlistIndex === 'number' && payload.playlistIndex >= 0) {\n        if (typeof cmdArgs.playlistIndex === 'string') {\n          args.push(`${cmdArgs.playlistIndex}${payload.playlistIndex}`)\n        } else if (!ignoreWarnings) {\n          unsupportedActions.push(UnsupportedPlayerActions.PLAYLIST_SPECIFIC_VIDEO)\n        }\n      }\n\n      if (payload.playlistReverse) {\n        if (typeof cmdArgs.playlistReverse === 'string') {\n          args.push(cmdArgs.playlistReverse)\n        } else if (!ignoreWarnings) {\n          unsupportedActions.push(UnsupportedPlayerActions.PLAYLIST_REVERSE)\n        }\n      }\n\n      if (payload.playlistShuffle) {\n        if (typeof cmdArgs.playlistShuffle === 'string') {\n          args.push(cmdArgs.playlistShuffle)\n        } else if (!ignoreWarnings) {\n          unsupportedActions.push(UnsupportedPlayerActions.PLAYLIST_SHUFFLE)\n        }\n      }\n\n      if (payload.playlistLoop) {\n        if (typeof cmdArgs.playlistLoop === 'string') {\n          args.push(cmdArgs.playlistLoop)\n        } else if (!ignoreWarnings) {\n          unsupportedActions.push(UnsupportedPlayerActions.PLAYLIST_LOOP)\n        }\n      }\n\n      // If the player supports opening playlists but not indexes, send only the video URL if an index is specified\n      if (cmdArgs.playlistIndex == null && typeof payload.playlistIndex === 'number') {\n        args.push(`${cmdArgs.videoUrl}https://youtube.com/watch?v=${payload.videoId}`)\n      } else {\n        args.push(`${cmdArgs.playlistUrl}https://youtube.com/playlist?list=${payload.playlistId}`)\n      }\n    } else {\n      if (hasValidPlaylistId && !ignoreWarnings) {\n        unsupportedActions.push(UnsupportedPlayerActions.OPENING_PLAYLISTS)\n      }\n\n      if (hasValidVideoId) {\n        args.push(`${cmdArgs.videoUrl}https://www.youtube.com/watch?v=${payload.videoId}`)\n      }\n    }\n  }\n\n  event.reply(\n    IpcChannels.OPEN_IN_EXTERNAL_PLAYER_RESULT,\n    externalPlayer,\n    unsupportedActions,\n    hasValidPlaylistId\n  )\n\n  /** @type {string} */\n  const externalPlayerExecutable = (await settings._findOne('externalPlayerExecutable'))?.value || ''\n\n  const executable = externalPlayerExecutable.length > 0 ? externalPlayerExecutable : cmdArgs.defaultExecutable\n\n  const child = spawn(executable, args, { detached: true, stdio: 'ignore' })\n  child.unref()\n}\n\nasync function loadExternalPlayerData() {\n  const path = process.env.NODE_ENV === 'development'\n    ? '../../static/external-player-map.json'\n    : 'static/external-player-map.json'\n\n  const json = JSON.parse(await readFile(join(__dirname, path)))\n\n  for (const entry of json) {\n    if (entry.value.length > 0) {\n      externalPlayerCmdArgs.set(entry.value, entry.cmdArguments)\n    }\n  }\n}\n"
  },
  {
    "path": "src/main/index.js",
    "content": "import {\n  app, BrowserWindow, dialog, Menu, ipcMain,\n  powerSaveBlocker, screen, session, shell,\n  nativeTheme, net, protocol, clipboard,\n  Tray\n} from 'electron'\nimport path from 'path'\nimport cp from 'child_process'\n\nimport {\n  IpcChannels,\n  DBActions,\n  SyncEvents,\n  ABOUT_BITCOIN_ADDRESS,\n  KeyboardShortcuts,\n  SEARCH_CHAR_LIMIT,\n} from '../constants'\nimport * as baseHandlers from '../datastores/handlers/base'\nimport { extractExpiryTimestamp, ImageCache } from './ImageCache'\nimport { constants as fsConstants, existsSync } from 'fs'\nimport asyncFs from 'fs/promises'\nimport { promisify } from 'util'\nimport { brotliDecompress } from 'zlib'\n\nimport contextMenu from 'electron-context-menu'\n\nimport packageDetails from '../../package.json'\nimport { handleOpenInExternalPlayer } from './externalPlayer'\nimport { generatePoToken } from './poTokenGenerator'\nimport { isFreeTubeUrl } from './utils'\n\nconst brotliDecompressAsync = promisify(brotliDecompress)\n\nif (process.argv.includes('--version')) {\n  console.log(`v${packageDetails.version} Beta`) // eslint-disable-line no-console\n  app.exit()\n} else if (process.argv.includes('--help') || process.argv.includes('-h')) {\n  printHelp()\n  app.exit()\n} else {\n  // Only allow single instance of the application\n  // Exit if we didn't get the lock, because another instance already has it\n  if (process.env.NODE_ENV !== 'development' && !app.requestSingleInstanceLock()) {\n    app.exit()\n  } else {\n    baseHandlers.loadDatastores()\n    runApp()\n  }\n}\n\nfunction printHelp() {\n  // eslint-disable-next-line no-console\n  console.log(`\\\nusage: ${process.argv0} [options...] [url]\nOptions:\n  --help, -h           show this message, then exit\n  --version            print the current version, then exit\n  --new-window         reuse an existing instance if possible`)\n}\n\nfunction runApp() {\n  /** @type {Set<string>} */\n  const ALLOWED_RENDERER_FILES = process.env.NODE_ENV === 'production'\n    // __FREETUBE_ALLOWED_PATHS__ is replaced by the injectAllowedPaths.mjs script\n    ? new Set(__FREETUBE_ALLOWED_PATHS__)\n    : new Set()\n\n  if (process.env.NODE_ENV === 'production') {\n    protocol.registerSchemesAsPrivileged([{\n      scheme: 'app',\n      privileges: {\n        standard: true,\n        secure: true,\n        supportFetchAPI: true\n      }\n    }])\n  }\n\n  const ROOT_APP_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:9080' : 'app://bundle/index.html'\n\n  let backendPreference = 'local'\n  let backendFallback = true\n\n  contextMenu({\n    showSearchWithGoogle: false,\n    showSaveImageAs: true,\n    showCopyImageAddress: true,\n    showSelectAll: false,\n    showCopyLink: false,\n    prepend: (defaultActions, parameters, browserWindow) => [\n      {\n        label: 'Open in a New Window',\n        // Only show the option for in-app URLs and not external ones\n        visible: parameters.linkURL.split('#')[0] === browserWindow.webContents.getURL().split('#')[0],\n        click: () => {\n          createWindow({ replaceMainWindow: false, windowStartupUrl: parameters.linkURL, showWindowNow: true })\n        }\n      },\n      // Only show select all in text fields\n      {\n        label: 'Select All',\n        enabled: parameters.editFlags.canSelectAll,\n        visible: parameters.isEditable,\n        click: () => {\n          browserWindow.webContents.selectAll()\n        }\n      }\n    ],\n    // only show the copy link entry for external links and the /playlist, /channel and /watch in-app URLs\n    // the /playlist, /channel and /watch in-app URLs get transformed to their equivalent YouTube or Invidious URLs\n    append: (defaultActions, parameters, browserWindow) => {\n      let visible = false\n      const urlParts = parameters.linkURL.split('#')\n      const isInAppUrl = urlParts[0] === browserWindow.webContents.getURL().split('#')[0]\n\n      if (parameters.linkURL.length > 0) {\n        if (isInAppUrl) {\n          const path = urlParts[1]\n\n          if (path) {\n            visible = ['/channel', '/watch', '/hashtag', '/post'].some(p => path.startsWith(p)) ||\n              // Only show copy link entry for non user playlists\n              (path.startsWith('/playlist') && !/playlistType=user/.test(path))\n          }\n        } else {\n          visible = true\n        }\n      }\n\n      const copy = (url) => {\n        if (parameters.linkText) {\n          clipboard.write({\n            bookmark: parameters.linkText,\n            text: url\n          })\n        } else {\n          clipboard.writeText(url)\n        }\n      }\n\n      const transformURL = (toYouTube) => {\n        let origin\n\n        if (toYouTube) {\n          origin = 'https://www.youtube.com'\n        } else {\n          origin = 'https://redirect.invidious.io'\n        }\n\n        const [path, query] = urlParts[1].split('?')\n        const [route, id] = path.split('/').filter(p => p)\n\n        switch (route) {\n          case 'playlist':\n            return `${origin}/playlist?list=${id}`\n          case 'channel':\n            return `${origin}/channel/${id}`\n          case 'hashtag':\n            return `${origin}/hashtag/${id}`\n          case 'watch': {\n            let url\n\n            if (toYouTube) {\n              url = new URL(`https://youtu.be/${id}`)\n            } else {\n              url = new URL(`https://redirect.invidious.io/watch?v=${id}`)\n            }\n\n            if (query) {\n              const params = new URLSearchParams(query)\n              const newParams = new URLSearchParams(url.search)\n              let hasParams = false\n\n              if (params.has('playlistId') && params.get('playlistType') !== 'user') {\n                newParams.set('list', params.get('playlistId'))\n                hasParams = true\n              }\n\n              if (params.has('timestamp')) {\n                newParams.set('t', params.get('timestamp'))\n                hasParams = true\n              }\n\n              if (hasParams) {\n                url.search = newParams.toString()\n              }\n            }\n\n            return url.toString()\n          }\n          case 'post': {\n            if (query) {\n              const authorId = new URLSearchParams(query).get('authorId')\n\n              if (authorId) {\n                if (toYouTube) {\n                  return `${origin}/channel/${authorId}/community?lb=${id}`\n                } else {\n                  return `${origin}/post/${id}?ucid=${authorId}`\n                }\n              }\n            }\n\n            return `${origin}/post/${id}`\n          }\n        }\n      }\n\n      const textShortEnoughForSearch = parameters.selectionText.trim().length <= SEARCH_CHAR_LIMIT\n\n      return [\n        {\n          label: 'Copy Lin&k',\n          visible: visible && !isInAppUrl,\n          click: () => {\n            copy(parameters.linkURL)\n          }\n        },\n        {\n          label: 'Copy YouTube Link',\n          visible: visible && isInAppUrl,\n          click: () => {\n            copy(transformURL(true))\n          }\n        },\n        {\n          label: 'Copy Invidious Link',\n          visible: visible && isInAppUrl && (backendPreference === 'invidious' || backendFallback),\n          click: () => {\n            copy(transformURL(false))\n          }\n        },\n        // Only show search in new window for\n        // Static text or link\n        // NOT internal link\n        // NOT link with no customized link text\n        // NOT link for timestamp\n        {\n          label: textShortEnoughForSearch ? 'Search “{selection}” in a New Window' : `“{selection}” is too long for search (> ${SEARCH_CHAR_LIMIT} chars)`,\n          enabled: textShortEnoughForSearch,\n          visible: (\n            !isInAppUrl &&\n            !parameters.isEditable &&\n            (parameters.linkURL != null && !parameters.linkURL.includes(parameters.selectionText) && !(/(\\d{1,2}:)*\\d{1,2}:\\d{2}/.test(parameters.linkText))) &&\n            parameters.selectionText.trim().length > 0\n          ),\n          click: () => {\n            const queryText = parameters.selectionText.trim()\n            createWindow({\n              replaceMainWindow: false,\n              windowStartupUrl: `${ROOT_APP_URL}#/search/${encodeURIComponent(queryText)}`,\n              searchQueryText: queryText,\n              showWindowNow: true,\n            })\n          }\n        },\n      ]\n    },\n  })\n\n  if (process.platform === 'win32') {\n    app.setUserTasks([\n      {\n        program: process.execPath,\n        arguments: '--new-window',\n        iconPath: process.execPath,\n        iconIndex: 0,\n        title: 'New Window',\n        description: 'Open New Window'\n      }\n    ])\n  }\n\n  // disable electron warning\n  process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'\n  const isDebug = process.argv.includes('--debug')\n\n  let mainWindow\n  let startupUrl\n  let tray = null\n  let trayOnMinimize = false\n  let trayWindows = []\n  const trayMaximizedWindows = {}\n\n  const userDataPath = app.getPath('userData')\n\n  // command line switches need to be added before the app ready event first\n  // that means we can't use the normal settings system as that is asynchronous,\n  // doing it synchronously ensures that we add it before the event fires\n  const REPLACE_HTTP_CACHE_PATH = `${userDataPath}/experiment-replace-http-cache`\n  const replaceHttpCache = existsSync(REPLACE_HTTP_CACHE_PATH)\n  if (replaceHttpCache) {\n    // the http cache causes excessive disk usage during video playback\n    // we've got a custom image cache to make up for disabling the http cache\n    // experimental as it increases RAM use in favour of reduced disk use\n    app.commandLine.appendSwitch('disable-http-cache')\n  }\n\n  const PLAYER_CACHE_PATH = `${userDataPath}/player_cache`\n\n  // See: https://stackoverflow.com/questions/45570589/electron-protocol-handler-not-working-on-windows\n  // remove so we can register each time as we run the app.\n  app.removeAsDefaultProtocolClient('freetube')\n\n  // If we are running a non-packaged version of the app && on windows\n  if (process.env.NODE_ENV === 'development' && process.platform === 'win32') {\n    // Set the path of electron.exe and your app.\n    // These two additional parameters are only available on windows.\n    app.setAsDefaultProtocolClient('freetube', process.execPath, [path.resolve(process.argv[1])])\n  } else {\n    app.setAsDefaultProtocolClient('freetube')\n  }\n\n  if (process.env.NODE_ENV !== 'development') {\n    app.on('second-instance', async (_, commandLine, __) => {\n      // Someone tried to run a second instance\n      if (typeof commandLine !== 'undefined') {\n        const newStartupUrl = getLinkUrl(commandLine)\n\n        if (!(mainWindow && mainWindow.webContents)) {\n          startupUrl = newStartupUrl\n          if (app.isReady()) await createWindow()\n          return\n        }\n\n        if (commandLine.includes('--new-window')) {\n          // The user wants to create a new window in the existing instance\n          if (newStartupUrl) startupUrl = newStartupUrl\n          await createWindow({\n            showWindowNow: true,\n            replaceMainWindow: true,\n          })\n          return\n        }\n\n        const openDeepLinksInNewWindow = (await baseHandlers.settings._findOne('openDeepLinksInNewWindow'))?.value\n        if (!openDeepLinksInNewWindow) {\n          // Just focus the main window (instead of starting a new instance)\n          if (mainWindow.isMinimized()) {\n            if (process.platform !== 'darwin' && trayOnMinimize) {\n              trayClick(mainWindow)\n            } else {\n              mainWindow.restore()\n            }\n          }\n          mainWindow.focus()\n          if (newStartupUrl) mainWindow.webContents.send(IpcChannels.OPEN_URL, newStartupUrl)\n          return\n        }\n\n        const newWindow = await createWindow({\n          replaceMainWindow: false,\n          showWindowNow: true,\n        })\n\n        /**\n         * @param {import('electron').IpcMainEvent} event\n         */\n        const readyHandler = (event) => {\n          if (isFreeTubeUrl(event.senderFrame.url)) {\n            newWindow.webContents.ipc.off(IpcChannels.APP_READY, readyHandler)\n\n            event.reply(IpcChannels.OPEN_URL, newStartupUrl)\n          }\n        }\n\n        newWindow.webContents.ipc.on(IpcChannels.APP_READY, readyHandler)\n      }\n    })\n  }\n\n  let proxyUrl\n\n  app.on('ready', async (_, __) => {\n    if (process.platform === 'darwin') {\n      const dockMenu = Menu.buildFromTemplate([\n        {\n          label: 'New Window',\n          click: () => {\n            createWindow({\n              replaceMainWindow: false,\n              showWindowNow: true\n            })\n          }\n        }\n      ])\n      app.dock.setMenu(dockMenu)\n    }\n\n    if (process.env.NODE_ENV === 'production') {\n      protocol.handle('app', async (request) => {\n        if (request.method !== 'GET') {\n          return new Response(null, {\n            status: 405,\n            headers: {\n              Allow: 'GET'\n            }\n          })\n        }\n\n        const { host, pathname } = new URL(request.url)\n\n        if (host !== 'bundle' || !ALLOWED_RENDERER_FILES.has(pathname)) {\n          return new Response(null, {\n            status: 400\n          })\n        }\n\n        const contents = await asyncFs.readFile(path.join(__dirname, pathname))\n\n        if (pathname.endsWith('.json.br')) {\n          const decompressed = await brotliDecompressAsync(contents)\n\n          return new Response(decompressed.buffer, {\n            status: 200,\n            headers: {\n              'Content-Type': 'application/json',\n              'Content-Encoding': 'br'\n            }\n          })\n        } else {\n          return new Response(contents.buffer, {\n            status: 200,\n            headers: {\n              'Content-Type': contentTypeFromFileExtension(pathname.split('.').at(-1))\n            }\n          })\n        }\n      })\n    }\n\n    // Electron defaults to approving all permission checks and permission requests.\n    // FreeTube only needs a few permissions, so we reject requests for other permissions\n    // and reject all requests on non-FreeTube URLs.\n    //\n    // FreeTube needs the following permissions:\n    // - \"fullscreen\": So that the video player can enter full screen\n    // - \"clipboard-sanitized-write\": To allow the user to copy video URLs and error messages\n    // - \"fileSystem\" Needed for the Web File System API (e.g. importing and exporting data)\n\n    session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {\n      if (!isFreeTubeUrl(requestingOrigin)) {\n        return false\n      }\n\n      return (\n        permission === 'fullscreen' ||\n        permission === 'clipboard-sanitized-write' ||\n        (permission === 'fileSystem' && !details.isDirectory)\n      )\n    })\n\n    session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => {\n      if (!isFreeTubeUrl(webContents.getURL())) {\n        // eslint-disable-next-line n/no-callback-literal\n        callback(false)\n        return\n      }\n\n      callback(\n        permission === 'fullscreen' ||\n        permission === 'clipboard-sanitized-write' ||\n        (permission === 'fileSystem' && !details.isDirectory)\n      )\n    })\n\n    session.defaultSession.on('file-system-access-restricted', (event, details, callback) => {\n      if (!isFreeTubeUrl(details.origin)) {\n        // eslint-disable-next-line n/no-callback-literal\n        callback('deny')\n        return\n      }\n\n      // eslint-disable-next-line n/no-callback-literal\n      callback(details.isDirectory ? 'deny' : 'allow')\n    })\n\n    let docArray\n    try {\n      docArray = await baseHandlers.settings._findAppReadyRelatedSettings()\n    } catch (err) {\n      console.error(err)\n      app.exit()\n      return\n    }\n\n    let disableSmoothScrolling = false\n    let useProxy = false\n    let proxyProtocol = 'socks5'\n    let proxyHostname = '127.0.0.1'\n    let proxyPort = '9050'\n\n    if (docArray?.length > 0) {\n      docArray.forEach((doc) => {\n        switch (doc._id) {\n          case 'disableSmoothScrolling':\n            disableSmoothScrolling = doc.value\n            break\n          case 'useProxy':\n            useProxy = doc.value\n            break\n          case 'proxyProtocol':\n            proxyProtocol = doc.value\n            break\n          case 'proxyHostname':\n            proxyHostname = doc.value\n            break\n          case 'proxyPort':\n            proxyPort = doc.value\n            break\n          case 'backendFallback':\n            backendFallback = doc.value\n            break\n          case 'backendPreference':\n            backendPreference = doc.value\n            break\n          case 'hideToTrayOnMinimize':\n            if (process.platform !== 'darwin') {\n              trayOnMinimize = doc.value\n            }\n            break\n        }\n      })\n    }\n\n    if (disableSmoothScrolling) {\n      app.commandLine.appendSwitch('disable-smooth-scrolling')\n    } else {\n      app.commandLine.appendSwitch('enable-smooth-scrolling')\n    }\n\n    if (useProxy) {\n      proxyUrl = `${proxyProtocol}://${proxyHostname}:${proxyPort}`\n\n      session.defaultSession.setProxy({\n        proxyRules: proxyUrl\n      })\n    }\n\n    const fixedUserAgent = session.defaultSession.getUserAgent()\n      .split(' ')\n      .filter(part => !part.includes('Electron') && !part.includes(packageDetails.productName))\n      .join(' ')\n    session.defaultSession.setUserAgent(fixedUserAgent)\n\n    // Set CONSENT cookie on reasonable domains\n    const consentCookieDomains = [\n      'https://www.youtube.com',\n      'https://youtube.com'\n    ]\n    consentCookieDomains.forEach(url => {\n      session.defaultSession.cookies.set({\n        url: url,\n        name: 'CONSENT',\n        value: 'YES+',\n        sameSite: 'no_restriction'\n      })\n    })\n\n    session.defaultSession.cookies.set({\n      url: 'https://www.youtube.com',\n      name: 'SOCS',\n      value: 'CAI',\n      sameSite: 'no_restriction',\n    })\n\n    const onBeforeSendHeadersRequestFilter = {\n      urls: ['https://*/*', 'http://*/*'],\n      types: ['xhr', 'media', 'image']\n    }\n    session.defaultSession.webRequest.onBeforeSendHeaders(onBeforeSendHeadersRequestFilter, ({ requestHeaders, url, webContents }, callback) => {\n      const urlObj = new URL(url)\n\n      if (url.startsWith('https://www.youtube.com/youtubei/')) {\n        // make InnerTube requests work with the fetch function\n        // InnerTube rejects requests if the referer isn't YouTube or empty\n        requestHeaders.Referer = 'https://www.youtube.com/'\n        requestHeaders.Origin = 'https://www.youtube.com'\n\n        requestHeaders['Sec-Fetch-Site'] = 'same-origin'\n        requestHeaders['Sec-Fetch-Mode'] = 'same-origin'\n        requestHeaders['X-Youtube-Bootstrap-Logged-In'] = 'false'\n      } else if (url === 'https://www.youtube.com/sw.js_data' || url.startsWith('https://www.youtube.com/api/timedtext')) {\n        requestHeaders.Referer = 'https://www.youtube.com/sw.js'\n        requestHeaders['Sec-Fetch-Site'] = 'same-origin'\n        requestHeaders['Sec-Fetch-Mode'] = 'same-origin'\n      } else if (\n        urlObj.origin.endsWith('.googleusercontent.com') ||\n        urlObj.origin.endsWith('.ggpht.com') ||\n        urlObj.origin.endsWith('.ytimg.com')\n      ) {\n        requestHeaders.Referer = 'https://www.youtube.com/'\n        requestHeaders.Origin = 'https://www.youtube.com'\n      } else if (urlObj.origin.endsWith('.googlevideo.com') && urlObj.pathname === '/videoplayback') {\n        requestHeaders.Referer = 'https://www.youtube.com/'\n        requestHeaders.Origin = 'https://www.youtube.com'\n\n        // YouTube doesn't send the Content-Type header for the media requests, so we shouldn't either\n        delete requestHeaders['Content-Type']\n      } else if (urlObj.origin === 'https://ipwho.is') {\n        // Fix the CORS error with the proxy test button\n        requestHeaders = {}\n      } else if (webContents) {\n        const invidiousAuthorization = invidiousAuthorizations.get(webContents.id)\n\n        if (invidiousAuthorization && url.startsWith(invidiousAuthorization.url)) {\n          requestHeaders.Authorization = invidiousAuthorization.authorization\n        }\n      }\n\n      callback({ requestHeaders })\n    })\n\n    // when we create a real session on the watch page, youtube returns tracking cookies, which we definitely don't want\n    const trackingCookieRequestFilter = { urls: ['https://www.youtube.com/sw.js_data', 'https://www.youtube.com/iframe_api'] }\n\n    session.defaultSession.webRequest.onHeadersReceived(trackingCookieRequestFilter, ({ responseHeaders }, callback) => {\n      if (responseHeaders) {\n        delete responseHeaders['set-cookie']\n      }\n\n      callback({ responseHeaders })\n    })\n\n    if (replaceHttpCache) {\n      // in-memory image cache\n\n      const imageCache = new ImageCache()\n\n      protocol.handle('imagecache', (request) => {\n        const [requestUrl, rawWebContentsId] = request.url.split('#')\n\n        return new Promise((resolve, reject) => {\n          const url = decodeURIComponent(requestUrl.substring(13))\n          if (imageCache.has(url)) {\n            const cached = imageCache.get(url)\n\n            resolve(new Response(cached.data, {\n              headers: { 'content-type': cached.mimeType }\n            }))\n            return\n          }\n\n          let headers\n\n          if (rawWebContentsId) {\n            const invidiousAuthorization = invidiousAuthorizations.get(parseInt(rawWebContentsId))\n\n            if (invidiousAuthorization && url.startsWith(invidiousAuthorization.url)) {\n              headers = {\n                Authorization: invidiousAuthorization.authorization\n              }\n            }\n          }\n\n          const newRequest = net.request({\n            method: request.method,\n            url,\n            headers\n          })\n\n          // Electron doesn't allow certain headers to be set:\n          // https://www.electronjs.org/docs/latest/api/client-request#requestsetheadername-value\n          // also blacklist Origin and Referrer as we don't want to let YouTube know about them\n          const blacklistedHeaders = ['content-length', 'host', 'trailer', 'te', 'upgrade', 'cookie2', 'keep-alive', 'transfer-encoding', 'origin', 'referrer']\n\n          for (const header of Object.keys(request.headers)) {\n            if (!blacklistedHeaders.includes(header.toLowerCase())) {\n              newRequest.setHeader(header, request.headers[header])\n            }\n          }\n\n          newRequest.on('response', (response) => {\n            const chunks = []\n            response.on('data', (chunk) => {\n              chunks.push(chunk)\n            })\n\n            response.on('end', () => {\n              const data = Buffer.concat(chunks)\n\n              const expiryTimestamp = extractExpiryTimestamp(response.headers)\n              const mimeType = response.headers['content-type']\n\n              imageCache.add(url, mimeType, data, expiryTimestamp)\n\n              resolve(new Response(data, {\n                headers: { 'content-type': mimeType }\n              }))\n            })\n\n            response.on('error', (error) => {\n              console.error('image cache error', error)\n              reject(error)\n            })\n          })\n\n          newRequest.on('error', (err) => {\n            console.error(err)\n          })\n\n          newRequest.end()\n        })\n      })\n\n      const imageRequestFilter = { urls: ['https://*/*', 'http://*/*'], types: ['image'] }\n      session.defaultSession.webRequest.onBeforeRequest(imageRequestFilter, (details, callback) => {\n        // the requests made by the imagecache:// handler to fetch the image,\n        // are allowed through, as their resourceType is 'other'\n\n        let redirectURL = `imagecache://${encodeURIComponent(details.url)}`\n\n        if (details.webContents) {\n          redirectURL += `#${details.webContents.id}`\n        }\n\n        callback({\n          redirectURL\n        })\n      })\n\n      // --- end of `if experimentsDisableDiskCache` ---\n    }\n\n    await createWindow()\n\n    if (isDebug) {\n      mainWindow.webContents.openDevTools()\n    }\n  })\n\n  app.on('login', async (event, webContents, request, authInfo, callback) => {\n    if (authInfo.isProxy) {\n      event.preventDefault()\n      const proxyUsername = (await baseHandlers.settings._findOne('proxyUsername'))?.value\n      const proxyPassword = (await baseHandlers.settings._findOne('proxyPassword'))?.value\n      callback(proxyUsername, proxyPassword)\n    }\n  })\n\n  function trayClick(window, close = false) {\n    if (!close) {\n      if (window.id in trayMaximizedWindows) {\n        window.maximize()\n      } else {\n        window.show()\n\n        // Calling hide() inside minimize is broken for some Linux distros (window minimizes again when trying to drag,\n        // resize or maximize it, among other shenanigans). It seems to work as intended with this workaround.\n        if (process.platform === 'linux') {\n          window.hide()\n          window.show()\n        }\n      }\n\n      if (trayWindows.length === BrowserWindow.getAllWindows().length) { mainWindow = window }\n    } else if (trayWindows.length > 0) {\n      window.close()\n    }\n\n    trayWindows.splice(trayWindows.findIndex(item => item.id === window.id), 1)\n\n    if (trayWindows.length > 0) {\n      createTrayContextMenu()\n    } else {\n      destroyTray()\n    }\n  }\n\n  function createTrayContextMenu() {\n    const menuItems = []\n    trayWindows.forEach(window => {\n      menuItems.push({\n        label: window.title,\n        submenu: [\n          {\n            label: 'Show',\n            click: () => trayClick(window)\n          },\n          {\n            label: 'Close',\n            click: () => trayClick(window, true)\n          }\n        ]\n      })\n    })\n\n    menuItems.push(\n      {\n        type: 'separator'\n      },\n      ...defaultTrayMenu()\n    )\n\n    const menu = Menu.buildFromTemplate(menuItems)\n    tray.setContextMenu(menu)\n  }\n\n  function defaultTrayMenu() {\n    return [\n      {\n        label: 'New Window',\n        click: () => createWindow({\n          showWindowNow: true,\n          replaceMainWindow: trayWindows.some(item => item.id === mainWindow.id)\n        })\n      },\n      {\n        label: 'Show All Windows',\n        click: () => {\n          // Use while loop instead of for loop as trayClick modifies the trayWindows array\n          while (trayWindows.length > 0) {\n            trayClick(trayWindows[0])\n          }\n        }\n      },\n      {\n        label: 'Quit',\n        click: handleQuit\n      }\n    ]\n  }\n\n  function destroyTray() {\n    if (!tray) return\n\n    if (process.platform !== 'linux') {\n      tray.destroy()\n      tray = null\n    } else {\n      const menu = Menu.buildFromTemplate(defaultTrayMenu())\n      tray.setContextMenu(menu)\n    }\n  }\n\n  function showHiddenWindows() {\n    trayWindows.forEach(window => {\n      window.minimize()\n    })\n\n    destroyTray()\n    trayWindows = []\n  }\n\n  /**\n   * @param {string} extension\n   */\n  function contentTypeFromFileExtension(extension) {\n    switch (extension) {\n      case 'html':\n        return 'text/html'\n      case 'css':\n        return 'text/css'\n      case 'js':\n        return 'text/javascript'\n      case 'ttf':\n        return 'font/ttf'\n      case 'woff2':\n        return 'font/woff2'\n      case 'svg':\n        return 'image/svg+xml'\n      case 'png':\n        return 'image/png'\n      case 'json':\n        return 'application/json'\n      case 'txt':\n        return 'text/plain'\n      default:\n        return 'application/octet-stream'\n    }\n  }\n\n  const htmlFullscreenWindowIds = new Set()\n\n  async function createWindow(\n    {\n      replaceMainWindow = true,\n      windowStartupUrl = null,\n      showWindowNow = false,\n      searchQueryText = null\n    } = { }) {\n    // Syncing new window background to theme choice.\n    const windowBackground = await baseHandlers.settings._findOne('baseTheme').then((setting) => {\n      if (!setting) {\n        return nativeTheme.shouldUseDarkColors ? '#212121' : '#f1f1f1'\n      }\n\n      // Determine window color to be shown (shown most prominently during initial app load)\n      // Uses the --bg-color for each corresponding theme\n      switch (setting.value) {\n        case 'dark':\n          return '#212121'\n        case 'light':\n          return '#f1f1f1'\n        case 'black':\n          return '#000000'\n        case 'dracula':\n          return '#282a36'\n        case 'catppuccin-mocha':\n          return '#1e1e2e'\n        case 'pastel-pink':\n          return '#ffd1dc'\n        case 'hot-pink':\n          return '#de1c85'\n        case 'nordic':\n          return '#2b2f3a'\n        case 'solarized-dark':\n          return '#002B36'\n        case 'solarized-light':\n          return '#fdf6e3'\n        case 'gruvbox-dark':\n          return '#282828'\n        case 'gruvbox-light':\n          return '#fbf1c7'\n        case 'catppuccin-frappe':\n          return '#303446'\n        case 'everforest-dark-hard':\n          return '#272e33'\n        case 'everforest-dark-medium':\n          return '#2d353b'\n        case 'everforest-dark-low':\n          return '#333c43'\n        case 'everforest-light-hard':\n          return '#fffbef'\n        case 'everforest-light-medium':\n          return '#fdf6e3'\n        case 'everforest-light-low':\n          return '#f3ead3'\n        case 'catppuccin-latte':\n          return '#eff1f5'\n        case 'system':\n        default:\n          return nativeTheme.shouldUseDarkColors ? '#212121' : '#f1f1f1'\n      }\n    }).catch((error) => {\n      console.error(error)\n      // Default to nativeTheme settings if nothing is found.\n      return nativeTheme.shouldUseDarkColors ? '#212121' : '#f1f1f1'\n    })\n\n    let savedBounds, savedMaximized, savedFullScreen\n\n    const boundsDoc = await baseHandlers.settings._findOne('bounds')\n    if (typeof boundsDoc?.value === 'object') {\n      const { maximized, fullScreen, ...bounds } = boundsDoc.value\n      const windowVisible = screen.getAllDisplays().some(display => {\n        const { x, y, width, height } = display.bounds\n        return !(bounds.x > x + width || bounds.x + bounds.width < x || bounds.y > y + height || bounds.y + bounds.height < y)\n      })\n\n      if (windowVisible) {\n        savedBounds = bounds\n      }\n\n      savedMaximized = maximized\n      savedFullScreen = fullScreen\n    }\n\n    const newWindow = new BrowserWindow({\n      // It will be shown later when ready via `ready-to-show` event\n      show: showWindowNow,\n      backgroundColor: windowBackground,\n      darkTheme: nativeTheme.shouldUseDarkColors,\n      icon: process.env.NODE_ENV === 'development'\n        ? path.join(__dirname, '../../_icons/iconColor.png')\n        : path.join(__dirname, '../_icons/iconColor.png'),\n      autoHideMenuBar: true,\n      // useContentSize: true,\n      webPreferences: {\n        webSecurity: false,\n        backgroundThrottling: false,\n        preload: process.env.NODE_ENV === 'development'\n          ? path.resolve(__dirname, '../../dist/preload.js')\n          : path.resolve(__dirname, 'preload.js')\n      },\n      minWidth: 340,\n      minHeight: 380,\n      ...savedBounds\n        ? {\n            x: savedBounds.x,\n            y: savedBounds.y,\n            width: savedBounds.width,\n            height: savedBounds.height\n          }\n        : {\n            width: 1200,\n            height: 800\n          }\n    })\n\n    // region Ensure child windows use same options since electron 14\n\n    // https://github.com/electron/electron/blob/14-x-y/docs/api/window-open.md#native-window-example\n    newWindow.webContents.setWindowOpenHandler((details) => {\n      const url = URL.parse(details.url)\n\n      // Only handle valid URLs that came from a FreeTube page\n      if (url !== null && isFreeTubeUrl(newWindow.webContents.getURL())) {\n        if (isFreeTubeUrl(url)) {\n          createWindow({\n            replaceMainWindow: false,\n            showWindowNow: true,\n            windowStartupUrl: details.url\n          })\n        } else if (\n          url.protocol === 'http:' || url.protocol === 'https:' ||\n\n          // Email address on the about page and Autolinker detects and links email addresses\n          url.protocol === 'mailto:' ||\n\n          // Autolinker detects and links phone numbers\n          url.protocol === 'tel:' ||\n\n          // Donation links on the about page\n          (url.protocol === 'bitcoin:' && url.pathname === ABOUT_BITCOIN_ADDRESS)\n        ) {\n          shell.openExternal(details.url)\n        }\n      }\n\n      return { action: 'deny' }\n    })\n\n    // endregion Ensure child windows use same options since electron 14\n\n    if (process.platform !== 'darwin') {\n      function manageTray(window, removeWindow = false) {\n        if (tray) {\n          if (!removeWindow) {\n            trayWindows.push(window)\n            createTrayContextMenu()\n          } else if (trayWindows.some(item => item.id === window.id)) {\n            trayClick(window)\n          }\n        } else {\n          const icon = process.env.NODE_ENV === 'development'\n            ? path.join(__dirname, '..', '..', '_icons', 'iconColor.png')\n            : path.join(__dirname, '..', '_icons', 'iconColor.png')\n\n          tray = new Tray(icon)\n\n          tray.setIgnoreDoubleClickEvents(true)\n          tray.setToolTip('FreeTube')\n\n          trayWindows = [window]\n          createTrayContextMenu()\n\n          if (process.platform !== 'linux') {\n            tray.on('click', (event) => {\n              if (trayWindows.length === 1) { trayClick(trayWindows[0]) }\n            })\n          }\n        }\n      }\n\n      newWindow.on('minimize', () => {\n        if (trayOnMinimize) {\n          // Workaround for https://github.com/electron/electron/issues/49253\n          if (process.platform === 'linux') {\n            setTimeout(() => {\n              newWindow.restore()\n              newWindow.hide()\n            }, 100)\n          } else {\n            newWindow.hide()\n          }\n\n          manageTray(newWindow)\n\n          if (newWindow === mainWindow) {\n            // A timer is needed because getFocusedWindow doesn't update until the minimize event ends\n            setTimeout(() => {\n              const newMainWindow = BrowserWindow.getFocusedWindow() || BrowserWindow.getAllWindows().find(window => window.isVisible())\n              if (newMainWindow) { mainWindow = newMainWindow }\n            }, 100)\n          }\n        }\n      })\n\n      newWindow.on('maximize', () => {\n        if (trayOnMinimize) { trayMaximizedWindows[newWindow.id] = true }\n      })\n\n      newWindow.on('unmaximize', () => {\n        if (trayOnMinimize) { delete trayMaximizedWindows[newWindow.id] }\n      })\n    }\n\n    if (replaceMainWindow) {\n      mainWindow = newWindow\n    }\n\n    if (savedMaximized) {\n      newWindow.maximize()\n    }\n\n    if (savedFullScreen) {\n      newWindow.setFullScreen(true)\n    }\n\n    // If called multiple times\n    // Duplicate menu items will be added\n    if (replaceMainWindow) {\n      setMenu()\n    }\n\n    // load root file/url\n    if (windowStartupUrl != null) {\n      newWindow.loadURL(windowStartupUrl)\n    } else {\n      newWindow.loadURL(ROOT_APP_URL)\n    }\n\n    if (typeof searchQueryText === 'string' && searchQueryText.length > 0) {\n      /**\n       * @param {import('electron').IpcMainEvent} event\n       */\n      const searchInputReadyHandler = (event) => {\n        if (isFreeTubeUrl(event.senderFrame.url)) {\n          newWindow.webContents.ipc.off(IpcChannels.SEARCH_INPUT_HANDLING_READY, searchInputReadyHandler)\n\n          event.reply(IpcChannels.UPDATE_SEARCH_INPUT_TEXT, searchQueryText)\n        }\n      }\n\n      newWindow.webContents.ipc.on(IpcChannels.SEARCH_INPUT_HANDLING_READY, searchInputReadyHandler)\n    }\n\n    const showWindow = () => {\n      if (newWindow.isVisible()) {\n        // only open the dev tools if they aren't already open\n        if (process.env.NODE_ENV === 'development' && !newWindow.webContents.isDevToolsOpened()) {\n          newWindow.webContents.openDevTools({ activate: false })\n        }\n        return\n      }\n\n      if (process.platform !== 'darwin' && trayOnMinimize && trayWindows.length > 0) {\n        trayClick(newWindow)\n      } else {\n        newWindow.show()\n        newWindow.focus()\n      }\n\n      if (process.env.NODE_ENV === 'development') {\n        newWindow.webContents.openDevTools({ activate: false })\n      }\n    }\n\n    // The `ready-to-show` event doesn't always fire on wayland.\n    // Use the `did-finish-load` event on the web contents instead as that is similar enough\n    // https://github.com/electron/electron/issues/48859\n\n    if (process.platform === 'linux' && app.commandLine.getSwitchValue('ozone-platform') === 'wayland') {\n      newWindow.webContents.once('did-finish-load', showWindow)\n    } else {\n      // Show when loaded\n      newWindow.once('ready-to-show', showWindow)\n    }\n\n    newWindow.on('enter-html-full-screen', () => {\n      htmlFullscreenWindowIds.add(newWindow.id)\n    })\n\n    newWindow.on('leave-html-full-screen', () => {\n      htmlFullscreenWindowIds.delete(newWindow.id)\n    })\n\n    newWindow.once('close', async () => {\n      // returns true if the element existed in the set\n      const htmlFullscreen = htmlFullscreenWindowIds.delete(newWindow.id)\n\n      if (BrowserWindow.getAllWindows().length !== 1) {\n        return\n      }\n\n      const value = {\n        ...newWindow.getNormalBounds(),\n        maximized: newWindow.isMaximized(),\n\n        // Don't save the full screen state if it was triggered by an HTML API e.g. the video player\n        fullScreen: newWindow.isFullScreen() && !htmlFullscreen\n      }\n\n      await baseHandlers.settings._updateBounds(value)\n    })\n\n    newWindow.once('closed', () => {\n      const allWindows = BrowserWindow.getAllWindows()\n      if (allWindows.length !== 0 && newWindow === mainWindow) {\n        // Replace mainWindow to avoid accessing `mainWindow.webContents`\n        // Which raises \"Object has been destroyed\" error\n        mainWindow = allWindows[0]\n      }\n\n      stopPowerSaveBlockerForWindow(newWindow)\n    })\n\n    return newWindow\n  }\n\n  ipcMain.on(IpcChannels.APP_READY, (event) => {\n    if (isFreeTubeUrl(event.senderFrame.url)) {\n      if (startupUrl) {\n        mainWindow.webContents.send(IpcChannels.OPEN_URL, startupUrl)\n      }\n      startupUrl = null\n    }\n  })\n\n  ipcMain.on(IpcChannels.SET_WINDOW_TITLE, (event, title) => {\n    if (isFreeTubeUrl(event.senderFrame.url) && typeof title === 'string') {\n      BrowserWindow.fromWebContents(event.sender)?.setTitle(title)\n    }\n  })\n\n  function relaunch() {\n    if (process.env.NODE_ENV === 'development') {\n      app.exit(parseInt(process.env.FREETUBE_RELAUNCH_EXIT_CODE))\n      return\n    }\n\n    // The AppImage and Windows portable formats must be accounted for\n    // because `process.execPath` points at the temporarily extracted\n    // executables, not the executables themselves\n    //\n    // It's possible to detect these formats and identify their\n    // executables' paths by checking the environmental variables\n    const { env: { APPIMAGE, PORTABLE_EXECUTABLE_FILE } } = process\n\n    if (!APPIMAGE) {\n      // If it's a Windows portable, PORTABLE_EXECUTABLE_FILE will\n      // hold a value.\n      // Otherwise, `process.execPath` should be used instead.\n      app.relaunch({\n        args: process.argv.slice(1),\n        execPath: PORTABLE_EXECUTABLE_FILE || process.execPath\n      })\n    } else {\n      // If it's an AppImage, things must be done the \"hard way\"\n      // `app.relaunch` doesn't work because of FUSE limitations\n      // Spawn a new process using the APPIMAGE env variable\n      const subprocess = cp.spawn(APPIMAGE, { detached: true, stdio: 'ignore' })\n      subprocess.unref()\n    }\n\n    app.quit()\n  }\n\n  ipcMain.once(IpcChannels.RELAUNCH_REQUEST, () => {\n    relaunch()\n  })\n\n  nativeTheme.on('updated', () => {\n    const allWindows = BrowserWindow.getAllWindows()\n\n    allWindows.forEach((window) => {\n      if (isFreeTubeUrl(window.webContents.getURL())) {\n        window.webContents.send(IpcChannels.NATIVE_THEME_UPDATE, nativeTheme.shouldUseDarkColors)\n      }\n    })\n  })\n\n  ipcMain.handle(IpcChannels.GENERATE_PO_TOKEN, (event, videoId, context) => {\n    if (isFreeTubeUrl(event.senderFrame.url)) {\n      return generatePoToken(videoId, context, proxyUrl)\n    }\n  })\n\n  ipcMain.on(IpcChannels.ENABLE_PROXY, (event, url) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    session.defaultSession.setProxy({\n      proxyRules: url\n    })\n    proxyUrl = url\n    session.defaultSession.closeAllConnections()\n  })\n\n  ipcMain.on(IpcChannels.DISABLE_PROXY, (event) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    session.defaultSession.setProxy({})\n    proxyUrl = undefined\n    session.defaultSession.closeAllConnections()\n  })\n\n  // #region navigation history\n\n  const NAV_HISTORY_DISPLAY_LIMIT = 15\n  // Math.trunc but with a bitwise OR so that it can be calcuated at build time and the number inlined\n  const HALF_OF_NAV_HISTORY_DISPLAY_LIMIT = (NAV_HISTORY_DISPLAY_LIMIT / 2) | 0\n\n  ipcMain.handle(IpcChannels.GET_NAVIGATION_HISTORY, ({ senderFrame, sender }) => {\n    if (!isFreeTubeUrl(senderFrame.url)) {\n      return\n    }\n\n    const activeIndex = sender.navigationHistory.getActiveIndex()\n    const length = sender.navigationHistory.length()\n\n    let end\n\n    if (activeIndex < HALF_OF_NAV_HISTORY_DISPLAY_LIMIT) {\n      end = Math.min(length - 1, NAV_HISTORY_DISPLAY_LIMIT - 1)\n    } else if (length - activeIndex < HALF_OF_NAV_HISTORY_DISPLAY_LIMIT + 1) {\n      end = length - 1\n    } else {\n      end = activeIndex + HALF_OF_NAV_HISTORY_DISPLAY_LIMIT\n    }\n\n    const dropdownOptions = []\n\n    for (let index = end; index >= Math.max(0, end + 1 - NAV_HISTORY_DISPLAY_LIMIT); --index) {\n      const routeLabel = sender.navigationHistory.getEntryAtIndex(index)?.title\n\n      dropdownOptions.push({\n        label: routeLabel,\n        value: index - activeIndex,\n        active: index === activeIndex\n      })\n    }\n\n    return dropdownOptions\n  })\n\n  // #endregion navigation history\n\n  ipcMain.handle(IpcChannels.GET_SYSTEM_LOCALE, (event) => {\n    if (isFreeTubeUrl(event.senderFrame.url)) {\n      // we should switch to getPreferredSystemLanguages at some point and iterate through until we find a supported locale\n      return app.getSystemLocale()\n    }\n  })\n\n  /**\n   * @param {import('electron').WebContents} webContents\n   * @param {string | undefined} [currentPath]\n   */\n  async function chooseDefaultFolder(webContents, currentPath) {\n    if (typeof currentPath !== 'string' || currentPath.length === 0) {\n      currentPath = app.getPath('pictures')\n    }\n\n    const dialogOptions = {\n      defaultPath: currentPath,\n      properties: ['openDirectory']\n    }\n\n    let result\n\n    const window = BrowserWindow.fromWebContents(webContents)\n    if (window) {\n      result = await dialog.showOpenDialog(window, dialogOptions)\n    } else {\n      result = await dialog.showOpenDialog(dialogOptions)\n    }\n\n    if (result.canceled) {\n      return\n    }\n\n    const settingId = 'screenshotFolderPath'\n\n    await baseHandlers.settings.upsert(settingId, result.filePaths[0])\n\n    const syncPayload = {\n      event: SyncEvents.GENERAL.UPSERT,\n      data: {\n        _id: settingId,\n        value: result.filePaths[0]\n      }\n    }\n\n    BrowserWindow.getAllWindows().forEach((window) => {\n      if (isFreeTubeUrl(window.webContents.getURL())) {\n        window.webContents.send(IpcChannels.SYNC_SETTINGS, syncPayload)\n      }\n    })\n\n    return result.filePaths[0]\n  }\n\n  ipcMain.on(IpcChannels.CHOOSE_DEFAULT_FOLDER, async (event) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    const currentPath = (await baseHandlers.settings._findOne('screenshotFolderPath'))?.value\n\n    await chooseDefaultFolder(event.sender, currentPath)\n  })\n\n  ipcMain.handle(IpcChannels.WRITE_TO_DEFAULT_FOLDER, async (event, filename, arrayBuffer) => {\n    if (\n      !isFreeTubeUrl(event.senderFrame.url) ||\n      typeof filename !== 'string' ||\n      !(arrayBuffer instanceof ArrayBuffer)) {\n      return\n    }\n\n    const folderPath = (await baseHandlers.settings._findOne('screenshotFolderPath'))?.value\n\n    let directory\n    if (typeof folderPath === 'string' && folderPath.length > 0) {\n      try {\n        await asyncFs.access(path.normalize(folderPath), fsConstants.W_OK)\n        directory = folderPath\n      } catch {}\n    }\n\n    // if setting is not set or we do not have write access to the folder\n    // prompt the user for a folder\n    // not having write access can happen if the user copies their settings to different machines\n    // or if they revoke a previously permitted folder in flatseal\n    if (directory === undefined) {\n      directory = await chooseDefaultFolder(event.sender)\n\n      if (typeof directory !== 'string' || directory.length === 0) {\n        return false\n      }\n    }\n\n    directory = path.normalize(directory)\n\n    const filePath = path.resolve(directory, filename)\n\n    // Ensure that we are only writing inside of the expected directory\n    if (path.dirname(filePath) !== directory) {\n      throw new Error('Invalid save location')\n    }\n\n    try {\n      await asyncFs.mkdir(directory, { recursive: true })\n\n      await asyncFs.writeFile(filePath, new DataView(arrayBuffer))\n    } catch (error) {\n      console.error('WRITE_TO_DEFAULT_FOLDER failed', error)\n      // throw a new error so that we don't expose the real error to the renderer\n      // eslint-disable-next-line preserve-caught-error\n      throw new Error('Failed to save')\n    }\n\n    return true\n  })\n\n  /** @type {Map<number, number>} */\n  const activePowerSaveBlockers = new Map()\n\n  /**\n   * @param {BrowserWindow} window\n   */\n  function stopPowerSaveBlockerForWindow(window) {\n    const powerSaveBlockerId = activePowerSaveBlockers.get(window.id)\n\n    if (typeof powerSaveBlockerId === 'number') {\n      powerSaveBlocker.stop(powerSaveBlockerId)\n\n      activePowerSaveBlockers.delete(window.id)\n    }\n  }\n\n  ipcMain.on(IpcChannels.STOP_POWER_SAVE_BLOCKER, (event) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    const browserWindow = BrowserWindow.fromWebContents(event.sender)\n\n    if (browserWindow) {\n      stopPowerSaveBlockerForWindow(browserWindow)\n    }\n  })\n\n  ipcMain.on(IpcChannels.START_POWER_SAVE_BLOCKER, (event) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    const browserWindow = BrowserWindow.fromWebContents(event.sender)\n\n    if (browserWindow && !activePowerSaveBlockers.has(browserWindow.id)) {\n      const powerSaveBlockerId = powerSaveBlocker.start('prevent-display-sleep')\n\n      activePowerSaveBlockers.set(browserWindow.id, powerSaveBlockerId)\n    }\n  })\n\n  ipcMain.on(IpcChannels.CREATE_NEW_WINDOW, (event, path, query, searchQueryText) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    if (\n      typeof path !== 'string' ||\n      (query != null && typeof query !== 'object') ||\n      (searchQueryText != null && typeof searchQueryText !== 'string')\n    ) {\n      return\n    }\n\n    if (path.charAt(0) !== '/') {\n      path = `/${path}`\n    }\n\n    let windowStartupUrl = `${ROOT_APP_URL}#${path}`\n\n    if (query) {\n      windowStartupUrl += '?' + new URLSearchParams(query).toString()\n    }\n\n    createWindow({\n      replaceMainWindow: false,\n      showWindowNow: true,\n      windowStartupUrl,\n      searchQueryText\n    })\n  })\n\n  ipcMain.on(IpcChannels.OPEN_IN_EXTERNAL_PLAYER, handleOpenInExternalPlayer)\n\n  ipcMain.handle(IpcChannels.GET_REPLACE_HTTP_CACHE, (event) => {\n    if (isFreeTubeUrl(event.senderFrame.url)) {\n      return replaceHttpCache\n    }\n  })\n\n  ipcMain.once(IpcChannels.TOGGLE_REPLACE_HTTP_CACHE, async (event) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    if (replaceHttpCache) {\n      await asyncFs.rm(REPLACE_HTTP_CACHE_PATH)\n    } else {\n      // create an empty file\n      const handle = await asyncFs.open(REPLACE_HTTP_CACHE_PATH, 'w')\n      await handle.close()\n    }\n\n    relaunch()\n  })\n\n  function playerCachePathForKey(key) {\n    // Remove path separators and period characters,\n    // to prevent any files outside of the player_cache directory,\n    // from being read or written\n    const sanitizedKey = `${key}`.replaceAll(/[./\\\\]/g, '__')\n\n    return path.join(PLAYER_CACHE_PATH, sanitizedKey)\n  }\n\n  ipcMain.handle(IpcChannels.PLAYER_CACHE_GET, async (event, key) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    const filePath = playerCachePathForKey(key)\n\n    try {\n      const contents = await asyncFs.readFile(filePath)\n\n      return contents.buffer\n    } catch (e) {\n      // Don't log the error if the file doesn't exist as we'll just fetch it from YouTube\n      // this usually happens when YouTube updates their player JavaScript\n      if (e.code !== 'ENOENT') {\n        console.error(e)\n      }\n\n      return undefined\n    }\n  })\n\n  ipcMain.handle(IpcChannels.PLAYER_CACHE_SET, async (event, key, value) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    const filePath = playerCachePathForKey(key)\n\n    await asyncFs.mkdir(PLAYER_CACHE_PATH, { recursive: true })\n\n    await asyncFs.writeFile(filePath, new Uint8Array(value))\n  })\n\n  /** @type {Map<number, { url: string, authorization: string }>} */\n  const invidiousAuthorizations = new Map()\n\n  ipcMain.on(IpcChannels.SET_INVIDIOUS_AUTHORIZATION, (event, authorization, url) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    if (!authorization) {\n      invidiousAuthorizations.delete(event.sender.id)\n    } else if (typeof authorization === 'string' && typeof url === 'string') {\n      invidiousAuthorizations.set(event.sender.id, { authorization, url })\n    }\n  })\n\n  // ************************************************* //\n  // DB related IPC calls\n  // *********** //\n\n  // Settings\n  ipcMain.handle(IpcChannels.DB_SETTINGS, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.settings.find()\n\n        case DBActions.GENERAL.UPSERT:\n          // This one is only allowed to be changed by the CHOOSE_DEFAULT_FOLDER IPC action\n          // to avoid the \"write to default folder\" IPC calls being abused to write to arbitrary locations\n          if (data._id === 'screenshotFolderPath') {\n            return null\n          }\n\n          await baseHandlers.settings.upsert(data._id, data.value)\n          syncOtherWindows(\n            IpcChannels.SYNC_SETTINGS,\n            event,\n            { event: SyncEvents.GENERAL.UPSERT, data }\n          )\n          switch (data._id) {\n            // Update app menu on related setting update\n            case 'backendFallback':\n              backendFallback = data.value\n              await setMenu()\n              break\n            case 'backendPreference':\n              backendPreference = data.value\n              await setMenu()\n              break\n            case 'hideTrendingVideos':\n            case 'hidePopularVideos':\n            case 'hidePlaylists':\n              await setMenu()\n              break\n            case 'hideToTrayOnMinimize':\n              if (process.platform !== 'darwin') {\n                trayOnMinimize = data.value\n                if (!trayOnMinimize) { showHiddenWindows() }\n              }\n              break\n\n            default:\n              // Do nothing for unmatched settings\n          }\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid settings db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n  // History\n  ipcMain.handle(IpcChannels.DB_HISTORY, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.history.find()\n\n        case DBActions.GENERAL.UPSERT:\n          await baseHandlers.history.upsert(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.UPSERT, data }\n          )\n          return null\n\n        case DBActions.GENERAL.OVERWRITE:\n          await baseHandlers.history.overwrite(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.OVERWRITE, data }\n          )\n          return null\n\n        case DBActions.HISTORY.UPDATE_WATCH_PROGRESS:\n          await baseHandlers.history.updateWatchProgress(data.videoId, data.watchProgress)\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.HISTORY.UPDATE_WATCH_PROGRESS, data }\n          )\n          return null\n\n        case DBActions.HISTORY.UPDATE_PLAYLIST:\n          await baseHandlers.history.updateLastViewedPlaylist(data.videoId, data.lastViewedPlaylistId, data.lastViewedPlaylistType, data.lastViewedPlaylistItemId)\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.HISTORY.UPDATE_PLAYLIST, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE:\n          await baseHandlers.history.delete(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.DELETE, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE_ALL:\n          await baseHandlers.history.deleteAll()\n          syncOtherWindows(\n            IpcChannels.SYNC_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.DELETE_ALL }\n          )\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid history db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n  // Profiles\n  ipcMain.handle(IpcChannels.DB_PROFILES, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.CREATE: {\n          const newProfile = await baseHandlers.profiles.create(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PROFILES,\n            event,\n            { event: SyncEvents.GENERAL.CREATE, data: newProfile }\n          )\n          return newProfile\n        }\n\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.profiles.find()\n\n        case DBActions.GENERAL.UPSERT:\n          await baseHandlers.profiles.upsert(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PROFILES,\n            event,\n            { event: SyncEvents.GENERAL.UPSERT, data }\n          )\n          return null\n\n        case DBActions.PROFILES.ADD_CHANNEL:\n          await baseHandlers.profiles.addChannelToProfiles(data.channel, data.profileIds)\n          syncOtherWindows(\n            IpcChannels.SYNC_PROFILES,\n            event,\n            { event: SyncEvents.PROFILES.ADD_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.PROFILES.REMOVE_CHANNEL:\n          await baseHandlers.profiles.removeChannelFromProfiles(data.channelId, data.profileIds)\n          syncOtherWindows(\n            IpcChannels.SYNC_PROFILES,\n            event,\n            { event: SyncEvents.PROFILES.REMOVE_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE:\n          await baseHandlers.profiles.delete(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PROFILES,\n            event,\n            { event: SyncEvents.GENERAL.DELETE, data }\n          )\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid profile db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n  // Playlists\n  // ! NOTE: A lot of these actions are currently not used for anything\n  // As such, only the currently used actions have synchronization implemented\n  // The remaining should have it implemented only when playlists\n  // get fully implemented into the app\n  ipcMain.handle(IpcChannels.DB_PLAYLISTS, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.CREATE:\n          await baseHandlers.playlists.create(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.GENERAL.CREATE, data }\n          )\n          return null\n\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.playlists.find()\n\n        case DBActions.GENERAL.UPSERT:\n          await baseHandlers.playlists.upsert(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.GENERAL.UPSERT, data }\n          )\n          return null\n\n        case DBActions.PLAYLISTS.UPSERT_VIDEO:\n          await baseHandlers.playlists.upsertVideoByPlaylistId(data._id, data.lastUpdatedAt, data.videoData)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.PLAYLISTS.UPSERT_VIDEO, data }\n          )\n          return null\n\n        case DBActions.PLAYLISTS.UPSERT_VIDEOS:\n          await baseHandlers.playlists.upsertVideosByPlaylistId(data._id, data.lastUpdatedAt, data.videos)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.PLAYLISTS.UPSERT_VIDEOS, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE:\n          await baseHandlers.playlists.delete(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.GENERAL.DELETE, data }\n          )\n          return null\n\n        case DBActions.PLAYLISTS.DELETE_VIDEO_ID:\n          await baseHandlers.playlists.deleteVideoIdByPlaylistId(data._id, data.lastUpdatedAt, data.videoId, data.playlistItemId)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.PLAYLISTS.DELETE_VIDEO, data }\n          )\n          return null\n\n        case DBActions.PLAYLISTS.DELETE_VIDEO_IDS:\n          await baseHandlers.playlists.deleteVideoIdsByPlaylistId(data._id, data.lastUpdatedAt, data.playlistItemIds)\n          syncOtherWindows(\n            IpcChannels.SYNC_PLAYLISTS,\n            event,\n            { event: SyncEvents.PLAYLISTS.DELETE_VIDEOS, data }\n          )\n          return null\n\n        case DBActions.PLAYLISTS.DELETE_ALL_VIDEOS:\n          await baseHandlers.playlists.deleteAllVideosByPlaylistId(data)\n          // TODO: Syncing (implement only when it starts being used)\n          // syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })\n          return null\n\n        case DBActions.GENERAL.DELETE_MULTIPLE:\n          await baseHandlers.playlists.deleteMultiple(data)\n          // TODO: Syncing (implement only when it starts being used)\n          // syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })\n          return null\n\n        case DBActions.GENERAL.DELETE_ALL:\n          await baseHandlers.playlists.deleteAll()\n          // TODO: Syncing (implement only when it starts being used)\n          // syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid playlist db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n\n  // ************** //\n  // Search History\n  ipcMain.handle(IpcChannels.DB_SEARCH_HISTORY, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.searchHistory.find()\n\n        case DBActions.GENERAL.UPSERT:\n          await baseHandlers.searchHistory.upsert(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_SEARCH_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.UPSERT, data }\n          )\n          return null\n\n        case DBActions.GENERAL.OVERWRITE:\n          await baseHandlers.searchHistory.overwrite(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_SEARCH_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.OVERWRITE, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE:\n          await baseHandlers.searchHistory.delete(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_SEARCH_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.DELETE, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE_ALL:\n          await baseHandlers.searchHistory.deleteAll()\n          syncOtherWindows(\n            IpcChannels.SYNC_SEARCH_HISTORY,\n            event,\n            { event: SyncEvents.GENERAL.DELETE_ALL }\n          )\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid search history db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n  // Profiles\n  ipcMain.handle(IpcChannels.DB_SUBSCRIPTION_CACHE, async (event, { action, data }) => {\n    if (!isFreeTubeUrl(event.senderFrame.url)) {\n      return\n    }\n\n    try {\n      switch (action) {\n        case DBActions.GENERAL.FIND:\n          return await baseHandlers.subscriptionCache.find()\n\n        case DBActions.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL:\n          await baseHandlers.subscriptionCache.updateVideosByChannelId(data.channelId, data.entries, data.timestamp)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL:\n          await baseHandlers.subscriptionCache.updateLiveStreamsByChannelId(data.channelId, data.entries, data.timestamp)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL:\n          await baseHandlers.subscriptionCache.updateShortsByChannelId(data.channelId, data.entries, data.timestamp)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL:\n          await baseHandlers.subscriptionCache.updateShortsWithChannelPageShortsByChannelId(data.channelId, data.entries)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL:\n          await baseHandlers.subscriptionCache.updateCommunityPostsByChannelId(data.channelId, data.entries, data.timestamp)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE_MULTIPLE:\n          await baseHandlers.subscriptionCache.deleteMultipleChannels(data)\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.GENERAL.DELETE_MULTIPLE, data }\n          )\n          return null\n\n        case DBActions.GENERAL.DELETE_ALL:\n          await baseHandlers.subscriptionCache.deleteAll()\n          syncOtherWindows(\n            IpcChannels.SYNC_SUBSCRIPTION_CACHE,\n            event,\n            { event: SyncEvents.GENERAL.DELETE_ALL, data }\n          )\n          return null\n\n        default:\n          // eslint-disable-next-line no-throw-literal\n          throw 'invalid subscriptionCache db action'\n      }\n    } catch (err) {\n      if (typeof err === 'string') throw err\n      else throw err.toString()\n    }\n  })\n\n  // *********** //\n\n  function syncOtherWindows(channel, event, payload) {\n    const otherWindows = BrowserWindow.getAllWindows().filter((window) => {\n      return window.webContents.id !== event.sender.id && isFreeTubeUrl(window.webContents.getURL())\n    })\n\n    for (const window of otherWindows) {\n      window.webContents.send(channel, payload)\n    }\n  }\n\n  // ************************************************* //\n\n  let resourcesCleanUpDone = false\n\n  app.on('window-all-closed', () => {\n    // Clean up resources (datastores' compaction + Electron cache and storage data clearing)\n    handleQuit()\n  })\n\n  if (process.platform === 'darwin') {\n    // `window-all-closed` doesn't fire for Cmd+Q\n    // https://www.electronjs.org/docs/latest/api/app#event-window-all-closed\n    // This is also fired when `app.quit` called\n    // Not using `before-quit` since that one is fired before windows are closed\n    app.on('will-quit', e => {\n      // Let app quit when the cleanup is finished\n\n      if (resourcesCleanUpDone) { return }\n\n      e.preventDefault()\n      cleanUpResources().finally(() => {\n        // Quit AFTER the resources cleanup is finished\n        // Which calls the listener again, which is why we have the variable\n\n        app.quit()\n      })\n    })\n  }\n\n  if (process.platform !== 'darwin') {\n    app.on('before-quit', () => {\n      if (tray) { tray.destroy() }\n    })\n  }\n\n  function handleQuit() {\n    cleanUpResources().finally(() => {\n      mainWindow = null\n      if (process.platform !== 'darwin') {\n        app.quit()\n      }\n    })\n  }\n\n  async function cleanUpResources() {\n    if (resourcesCleanUpDone) {\n      return\n    }\n\n    await Promise.allSettled([\n      baseHandlers.compactAllDatastores(),\n      session.defaultSession.clearCache(),\n      session.defaultSession.clearStorageData({\n        storages: [\n          'appcache',\n          'cookies',\n          'filesystem',\n          'indexdb',\n          'shadercache',\n          'websql',\n          'serviceworkers',\n          'cachestorage'\n        ]\n      })\n    ])\n\n    resourcesCleanUpDone = true\n  }\n\n  // MacOS event\n  // https://www.electronjs.org/docs/latest/api/app#event-activate-macos\n  app.on('activate', () => {\n    if (BrowserWindow.getAllWindows().length === 0) {\n      createWindow()\n    }\n  })\n\n  /*\n   * Callback when processing a freetube:// link (macOS)\n   */\n  app.on('open-url', async (event, url) => {\n    event.preventDefault()\n\n    const newStartupUrl = baseUrl(url)\n    if (!(mainWindow && mainWindow.webContents)) {\n      startupUrl = newStartupUrl\n      if (app.isReady()) await createWindow()\n      return\n    }\n\n    const openDeepLinksInNewWindow = (await baseHandlers.settings._findOne('openDeepLinksInNewWindow'))?.value\n    if (!openDeepLinksInNewWindow) {\n      if (mainWindow.isMinimized()) mainWindow.restore()\n      mainWindow.focus()\n      mainWindow.webContents.send(IpcChannels.OPEN_URL, newStartupUrl)\n      return\n    }\n\n    const newWindow = await createWindow({\n      replaceMainWindow: false,\n      showWindowNow: true,\n    })\n\n    /**\n     * @param {import('electron').IpcMainEvent} event\n     */\n    const readyHandler = (event) => {\n      if (isFreeTubeUrl(event.senderFrame.url)) {\n        newWindow.webContents.ipc.off(IpcChannels.APP_READY, readyHandler)\n\n        event.reply(IpcChannels.OPEN_URL, newStartupUrl)\n      }\n    }\n\n    newWindow.webContents.ipc.on(IpcChannels.APP_READY, readyHandler)\n  })\n\n  app.on('web-contents-created', (_, webContents) => {\n    webContents.once('destroyed', () => {\n      invidiousAuthorizations.delete(webContents.id)\n    })\n  })\n\n  /*\n   * Check if an argument was passed and send it over to the GUI (Linux / Windows).\n   * Remove freetube:// protocol if present\n   */\n  const url = getLinkUrl(process.argv)\n  if (url) {\n    startupUrl = url\n  }\n\n  function baseUrl(arg) {\n    let newArg = arg.replace('freetube://', '')\n    // add support for authority free url\n      .replace('freetube:', '')\n\n    // fix for Qt URL, like `freetube://https//www.youtube.com/watch?v=...`\n    // For details see https://github.com/FreeTubeApp/FreeTube/pull/3119\n    if (newArg.startsWith('https') && newArg.charAt(5) !== ':') {\n      newArg = 'https:' + newArg.substring(5)\n    }\n    return newArg\n  }\n\n  function getLinkUrl(argv) {\n    if (argv.length > 1) {\n      return baseUrl(argv[argv.length - 1])\n    } else {\n      return null\n    }\n  }\n\n  /*\n   * Auto Updater\n   *\n   * Uncomment the following code below and install `electron-updater` to\n   * support auto updating. Code Signing with a valid certificate is required.\n   * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating\n   */\n\n  /*\n  import { autoUpdater } from 'electron-updater'\n  autoUpdater.on('update-downloaded', () => {\n    autoUpdater.quitAndInstall()\n  })\n\n  app.on('ready', () => {\n    if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()\n  })\n   */\n\n  function navigateTo(path, browserWindow) {\n    if (browserWindow == null || !isFreeTubeUrl(browserWindow.webContents.getURL())) {\n      return\n    }\n\n    browserWindow.webContents.send(IpcChannels.CHANGE_VIEW, path)\n  }\n\n  async function setMenu() {\n    const sidenavSettings = baseHandlers.settings._findSidenavSettings()\n    const hideTrendingVideos = (await sidenavSettings.hideTrendingVideos)?.value\n    const hidePopularVideos = (await sidenavSettings.hidePopularVideos)?.value\n    const hidePlaylists = (await sidenavSettings.hidePlaylists)?.value\n\n    const template = [\n      ...process.platform === 'darwin'\n        ? [\n            {\n              label: app.getName(),\n              submenu: [\n                { role: 'about' },\n                { type: 'separator' },\n                { role: 'services' },\n                { type: 'separator' },\n                { role: 'hide' },\n                { role: 'hideothers' },\n                { role: 'unhide' },\n                { type: 'separator' },\n                { role: 'quit' }\n              ]\n            }\n          ]\n        : [],\n      {\n        label: 'File',\n        submenu: [\n          {\n            label: 'New Window',\n            accelerator: 'CmdOrCtrl+N',\n            click: (_menuItem, _browserWindow, _event) => {\n              createWindow({\n                replaceMainWindow: false,\n                showWindowNow: true\n              })\n            },\n            type: 'normal'\n          },\n          { type: 'separator' },\n          {\n            label: 'Preferences',\n            accelerator: 'CmdOrCtrl+,',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/settings', browserWindow)\n            },\n            type: 'normal'\n          },\n          { type: 'separator' },\n          { role: 'quit' }\n        ]\n      },\n      {\n        label: 'Edit',\n        submenu: [\n          { role: 'cut' },\n          {\n            role: 'copy',\n            accelerator: 'CmdOrCtrl+C',\n            selector: 'copy:'\n          },\n          {\n            role: 'paste',\n            accelerator: 'CmdOrCtrl+V',\n            selector: 'paste:'\n          },\n          { role: 'pasteandmatchstyle' },\n          { role: 'delete' },\n          { role: 'selectall' }\n        ]\n      },\n      {\n        label: 'View',\n        submenu: [\n          { role: 'toggledevtools' },\n          { role: 'toggledevtools', accelerator: 'f12', visible: false },\n          {\n            label: 'Enter Inspect Element Mode',\n            accelerator: 'CmdOrCtrl+Shift+C',\n            click: (_, window) => {\n              if (window.webContents.isDevToolsOpened()) {\n                window.devToolsWebContents.executeJavaScript('DevToolsAPI.enterInspectElementMode()')\n              } else {\n                window.webContents.once('devtools-opened', () => {\n                  window.devToolsWebContents.executeJavaScript('DevToolsAPI.enterInspectElementMode()')\n                })\n                window.webContents.openDevTools()\n              }\n            }\n          },\n          {\n            label: 'GPU Internals (chrome://gpu)',\n            click() {\n              const gpuWindow = new BrowserWindow({\n                show: true,\n                autoHideMenuBar: true,\n                webPreferences: {\n                  devTools: false\n                }\n              })\n              gpuWindow.loadURL('chrome://gpu')\n            }\n          },\n          { type: 'separator' },\n          { role: 'resetzoom' },\n          { role: 'resetzoom', accelerator: 'CmdOrCtrl+num0', visible: false },\n          { role: 'zoomin', accelerator: 'CmdOrCtrl+Plus' },\n          { role: 'zoomin', accelerator: 'CmdOrCtrl+=', visible: false },\n          { role: 'zoomin', accelerator: 'CmdOrCtrl+numadd', visible: false },\n          { role: 'zoomout' },\n          { role: 'zoomout', accelerator: 'CmdOrCtrl+numsub', visible: false },\n          { type: 'separator' },\n          { role: 'togglefullscreen' },\n          { type: 'separator' },\n          {\n            label: 'Back',\n            accelerator: 'Alt+Left',\n            click: (_menuItem, browserWindow, _event) => {\n              if (browserWindow == null) { return }\n\n              browserWindow.webContents.navigationHistory.goBack()\n            },\n            type: 'normal',\n          },\n          ...(process.platform === 'darwin'\n            ? [\n                {\n                  label: 'Back',\n                  accelerator: KeyboardShortcuts.APP.GENERAL.HISTORY_BACKWARD_ALT_MAC,\n                  click: (_menuItem, browserWindow, _event) => {\n                    if (browserWindow == null) { return }\n\n                    browserWindow.webContents.navigationHistory.goBack()\n                  },\n                  visible: false,\n                },\n              ]\n            : []),\n          {\n            label: 'Forward',\n            accelerator: 'Alt+Right',\n            click: (_menuItem, browserWindow, _event) => {\n              if (browserWindow == null) { return }\n\n              browserWindow.webContents.navigationHistory.goForward()\n            },\n            type: 'normal',\n          },\n          ...(process.platform === 'darwin'\n            ? [\n                {\n                  label: 'Forward',\n                  accelerator: KeyboardShortcuts.APP.GENERAL.HISTORY_FORWARD_ALT_MAC,\n                  click: (_menuItem, browserWindow, _event) => {\n                    if (browserWindow == null) { return }\n\n                    browserWindow.webContents.navigationHistory.goForward()\n                  },\n                  visible: false,\n                },\n              ]\n            : []),\n        ]\n      },\n      {\n        label: 'Navigate',\n        submenu: [\n          {\n            label: 'Subscriptions',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/subscriptions', browserWindow)\n            },\n            type: 'normal'\n          },\n          {\n            label: 'Channels',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/subscribedchannels', browserWindow)\n            },\n            type: 'normal'\n          },\n          (!hideTrendingVideos && (backendFallback || backendPreference === 'local')) && {\n            label: 'Trending',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/trending', browserWindow)\n            },\n            type: 'normal'\n          },\n          (!hidePopularVideos && (backendFallback || backendPreference === 'invidious')) && {\n            label: 'Most Popular',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/popular', browserWindow)\n            },\n            type: 'normal'\n          },\n          !hidePlaylists && {\n            label: 'Playlists',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/userplaylists', browserWindow)\n            },\n            type: 'normal'\n          },\n          {\n            label: 'History',\n            // MacOS: Command + Y\n            // Other OS: Ctrl + H\n            accelerator: process.platform === 'darwin' ? 'Cmd+Y' : 'Ctrl+H',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/history', browserWindow)\n            },\n            type: 'normal'\n          },\n          {\n            label: 'Profile Manager',\n            click: (_menuItem, browserWindow, _event) => {\n              navigateTo('/settings/profile/', browserWindow)\n            },\n            type: 'normal'\n          },\n        ].filter((v) => v !== false),\n      },\n      {\n        role: 'window',\n        submenu: [\n          { role: 'minimize' },\n          { role: 'close' }\n        ]\n      },\n      ...process.platform === 'darwin'\n        ? [\n            { role: 'window' },\n            { role: 'help' },\n            { role: 'services' }\n          ]\n        : []\n    ]\n\n    const menu = Menu.buildFromTemplate(template)\n    Menu.setApplicationMenu(menu)\n  }\n}\n"
  },
  {
    "path": "src/main/poTokenGenerator.js",
    "content": "import { session, WebContentsView } from 'electron'\nimport { readFile } from 'fs/promises'\nimport { join } from 'path'\n\n// #region queue\n\n/**\n * This is the internal Promise object which resolves when all the tasks of the queue are done.\n * It will change any time {@linkcode enqueueAsyncFunction} is called.\n */\nlet queueGuardian = Promise.resolve()\n\n/**\n * Enqueues an asynchronous function to be executed after the previous ones in the queue have finished.\n * That way the promises/asynchronous functions are executed sequentially rather than in parallel.\n *\n * @template T\n * @param {T} func\n * @param {Parameters<T>} args\n * @returns {ReturnType<T>}\n */\nfunction enqueueAsyncFunction(func, ...args) {\n  queueGuardian = queueGuardian.then(() => {\n    return func(...args)\n      .then(result => ({ error: false, result }), result => ({ error: true, result }))\n  })\n\n  return queueGuardian.then(({ error, result }) => {\n    if (error) return Promise.reject(result)\n    else return Promise.resolve(result)\n  })\n}\n\n// #endregion queue\n\nlet firstTime = true\n\n/**\n * Generates a content-bound poToken (proof of origin token) using `bgutils-js`.\n * The script to generate it is `src/botGuardScript.js`\n *\n * This is intentionally split out into it's own thing, with it's own in-memory session,\n * as the BotGuard stuff accesses the global `document` and `window` objects and also requires making some requests.\n * So we definitely don't want it running in the same places as the rest of the FreeTube code with the user data.\n * @param {string} videoId\n * @param {string} context\n * @param {string|undefined} proxyUrl\n * @returns {Promise<string>}\n */\nexport function generatePoToken(videoId, context, proxyUrl) {\n  if (firstTime) {\n    firstTime = false\n    enqueueAsyncFunction(sharedInit)\n  }\n\n  // We use a promise queue instead of running the `internalGeneratePotoken` function directly\n  // so that we can reuse the same session by clearing all data\n  // associated with the session before triggering generating the next PO token.\n\n  // Electron's session objects stick around for the entire lifetime of the Electron main process,\n  // holding onto OS resources such as the OS DNS resolver, so if we created a new session for each PO token generation\n  // the OS will eventually complain about the resources being exhausted (e.g. too many inotify instances on Linux)\n\n  // References\n  // - https://github.com/FreeTubeApp/FreeTube/issues/8640\n  // - https://github.com/electron/electron/pull/46131\n  // - https://github.com/electron/electron/commit/bac2f46ba981cc1763c0485cec44813c1d07fa18\n  const potokenPromise = enqueueAsyncFunction(internalGeneratePotoken, videoId, context, proxyUrl)\n\n  // schedule the cleanup separately,\n  // so that we can return the potoken without having to wait until the cleanup is done\n  enqueueAsyncFunction(cleanupSession)\n\n  return potokenPromise\n}\n\n/** @type {import('electron').Session} */\nlet theSession\n/** @type {string} */\nlet cachedScript\n\nasync function sharedInit() {\n  // setup session\n\n  theSession = session.fromPartition('potoken', { cache: false })\n\n  theSession.setPermissionCheckHandler(() => false)\n  // eslint-disable-next-line n/no-callback-literal\n  theSession.setPermissionRequestHandler((webContents, permission, callback) => callback(false))\n\n  theSession.setUserAgent(session.defaultSession.getUserAgent())\n\n  theSession.webRequest.onBeforeSendHeaders({\n    urls: ['https://www.google.com/js/*', 'https://www.youtube.com/youtubei/*']\n  }, ({ requestHeaders, url }, callback) => {\n    if (url.startsWith('https://www.youtube.com/youtubei/')) {\n      // make InnerTube requests work with the fetch function\n      // InnerTube rejects requests if the referer isn't YouTube or empty\n      requestHeaders.Referer = 'https://www.youtube.com/'\n      requestHeaders.Origin = 'https://www.youtube.com'\n\n      requestHeaders['Sec-Fetch-Site'] = 'same-origin'\n      requestHeaders['Sec-Fetch-Mode'] = 'same-origin'\n      requestHeaders['X-Youtube-Bootstrap-Logged-In'] = 'false'\n    } else {\n      requestHeaders['Sec-Fetch-Dest'] = 'script'\n      requestHeaders['Sec-Fetch-Site'] = 'cross-site'\n      requestHeaders['Accept-Language'] = '*'\n    }\n\n    callback({ requestHeaders })\n  })\n\n  theSession.webRequest.onHeadersReceived({ urls: ['https://*/*'] }, ({ responseHeaders }, callback) => {\n    if (responseHeaders) {\n      callback({\n        responseHeaders: {\n          ...responseHeaders,\n          'Access-Control-Allow-Origin': ['*'],\n          'Access-Control-Allow-Methods': ['GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH']\n        }\n      })\n    }\n  })\n\n  theSession.webRequest.onBeforeRequest({ urls: ['<all_urls>'], types: ['cspReport', 'ping'] }, (details, callback) => {\n    callback({ cancel: true })\n  })\n\n  // load script file\n\n  const pathToScript = process.env.NODE_ENV === 'development'\n    ? join(__dirname, '../../dist/botGuardScript.js')\n    : join(__dirname, 'botGuardScript.js')\n\n  const scriptContent = await readFile(pathToScript, 'utf-8')\n\n  const scriptExportMatch = scriptContent.match(/export{(\\w+) as default};/)\n\n  cachedScript = scriptContent.replace(scriptExportMatch[0], `;${scriptExportMatch[1]}(FT_PARAMS)`)\n}\n\n/**\n * @param {string} videoId\n * @param {string} context\n * @param {string|undefined} proxyUrl\n * @returns {Promise<string>}\n */\nasync function internalGeneratePotoken(videoId, context, proxyUrl) {\n  let webContentsView\n\n  try {\n    if (proxyUrl) {\n      await theSession.setProxy({\n        proxyRules: proxyUrl\n      })\n    }\n\n    webContentsView = new WebContentsView({\n      webPreferences: {\n        backgroundThrottling: false,\n        safeDialogs: true,\n        sandbox: true,\n        contextIsolation: true,\n        v8CacheOptions: 'none',\n        session: theSession,\n        offscreen: true,\n        disableBlinkFeatures: 'ElectronCSSCornerSmoothing'\n      }\n    })\n\n    webContentsView.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))\n\n    webContentsView.webContents.setAudioMuted(true)\n    webContentsView.setBounds({\n      x: 0,\n      y: 0,\n      width: 1920,\n      height: 1080\n    })\n\n    webContentsView.webContents.debugger.attach()\n\n    await webContentsView.webContents.loadURL('data:text/html,<!DOCTYPE html><html lang=\"en\"><head><title></title></head><body></body></html>', {\n      baseURLForDataURL: 'https://www.youtube.com/'\n    })\n\n    await webContentsView.webContents.debugger.sendCommand('Emulation.setDeviceMetricsOverride', {\n      width: 1920,\n      height: 1080,\n      deviceScaleFactor: 1,\n      mobile: false,\n      screenWidth: 1920,\n      screenHeight: 1080,\n      positionX: 0,\n      positionY: 0,\n      screenOrientation: {\n        type: 'landscapePrimary',\n        angle: 0\n      }\n    })\n\n    const script = cachedScript.replace('FT_PARAMS', `\"${videoId}\",${context}`)\n\n    return await webContentsView.webContents.executeJavaScript(script)\n  } finally {\n    if (webContentsView) {\n      webContentsView.webContents.close({ waitForBeforeUnload: false })\n    }\n  }\n}\n\nasync function cleanupSession() {\n  await theSession.closeAllConnections()\n  await theSession.clearData()\n}\n"
  },
  {
    "path": "src/main/utils.js",
    "content": "/**\n * @param {string | URL} url\n */\nexport function isFreeTubeUrl(url) {\n  let url_\n\n  if (url instanceof URL) {\n    url_ = url\n  } else {\n    url_ = URL.parse(url)\n  }\n\n  if (process.env.NODE_ENV === 'development') {\n    return url_ !== null && url_.protocol === 'http:' && url_.host === 'localhost:9080' && (url_.pathname === '/' || url_.pathname === '/index.html')\n  } else {\n    return url_ !== null && url_.protocol === 'app:' && url_.host === 'bundle' && (url_.pathname === '/' || url_.pathname === '/index.html')\n  }\n}\n"
  },
  {
    "path": "src/preload/interface.js",
    "content": "import { ipcRenderer, webFrame } from 'electron/renderer'\nimport { IpcChannels } from '../constants.js'\n\n/**\n * Linux fix for dynamically updating theme preference, this works on\n * all systems running the electron app.\n */\nipcRenderer.on(IpcChannels.NATIVE_THEME_UPDATE, (_, shouldUseDarkColors) => {\n  document.body.dataset.systemTheme = shouldUseDarkColors ? 'dark' : 'light'\n})\n\n// Force update the window title whenever the page title changes\n// as Electron doesn't do it when the back button is pressed, probably a bug.\n// It doesn't even fire the `page-title-updated` in the main process.\n\nconst titleMutationObserver = new MutationObserver((mutations) => {\n  ipcRenderer.send(IpcChannels.SET_WINDOW_TITLE, mutations[0].addedNodes[0].textContent)\n})\ndocument.addEventListener('DOMContentLoaded', () => {\n  titleMutationObserver.observe(document.querySelector('title'), { childList: true })\n}, { once: true })\n\nlet currentUpdateSearchInputTextListener\n\nexport default {\n  /**\n   * @returns {Promise<string>}\n   */\n  getSystemLocale: () => {\n    return ipcRenderer.invoke(IpcChannels.GET_SYSTEM_LOCALE)\n  },\n\n  /**\n   * @param {string} path\n   * @param {Record<string, string> | null | undefined} query\n   * @param {string | null | undefined} searchQueryText\n   */\n  openInNewWindow: (path, query, searchQueryText) => {\n    ipcRenderer.send(IpcChannels.CREATE_NEW_WINDOW, path, query, searchQueryText)\n  },\n\n  /**\n   * @param {string} url\n   */\n  enableProxy: (url) => {\n    ipcRenderer.send(IpcChannels.ENABLE_PROXY, url)\n  },\n\n  disableProxy: () => {\n    ipcRenderer.send(IpcChannels.DISABLE_PROXY)\n  },\n\n  /**\n   * @param {string} authorization\n   * @param {string} url\n   */\n  setInvidiousAuthorization: (authorization, url) => {\n    ipcRenderer.send(IpcChannels.SET_INVIDIOUS_AUTHORIZATION, authorization, url)\n  },\n\n  clearInvidiousAuthorization: () => {\n    ipcRenderer.send(IpcChannels.SET_INVIDIOUS_AUTHORIZATION, null)\n  },\n\n  startPowerSaveBlocker: () => {\n    ipcRenderer.send(IpcChannels.START_POWER_SAVE_BLOCKER)\n  },\n\n  stopPowerSaveBlocker: () => {\n    ipcRenderer.send(IpcChannels.STOP_POWER_SAVE_BLOCKER)\n  },\n\n  /**\n   * @returns {Promise<boolean>}\n   */\n  getReplaceHttpCache: () => {\n    return ipcRenderer.invoke(IpcChannels.GET_REPLACE_HTTP_CACHE)\n  },\n\n  toggleReplaceHttpCache: () => {\n    ipcRenderer.send(IpcChannels.TOGGLE_REPLACE_HTTP_CACHE)\n  },\n\n  // Allows programmatic toggling of picture-in-picture mode without accompanying user interaction.\n  // See: https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation\n  requestPiP: () => {\n    webFrame.executeJavaScript('document.querySelector(\"video.player\")?.ui.getControls().togglePiP()', true).catch()\n  },\n\n  // Allows programmatic toggling of fullscreen without accompanying user interaction.\n  // See: https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation\n  requestFullscreen: () => {\n    webFrame.executeJavaScript('document.querySelector(\"video.player\")?.ui.getControls().toggleFullScreen()', true).catch()\n  },\n\n  /**\n   * @param {string} key\n   * @returns {Promise<ArrayBuffer>}\n   */\n  playerCacheGet: (key) => {\n    return ipcRenderer.invoke(IpcChannels.PLAYER_CACHE_GET, key)\n  },\n\n  /**\n   * @param {string} key\n   * @param {ArrayBuffer} value\n   */\n  playerCacheSet: async (key, value) => {\n    await ipcRenderer.invoke(IpcChannels.PLAYER_CACHE_SET, key, value)\n  },\n\n  /**\n   * @param {string} videoId\n   * @param {string} context\n   * @returns {Promise<string>}\n   */\n  generatePoToken: (videoId, context) => {\n    return ipcRenderer.invoke(IpcChannels.GENERATE_PO_TOKEN, videoId, context)\n  },\n\n  chooseDefaultFolder: () => {\n    ipcRenderer.send(IpcChannels.CHOOSE_DEFAULT_FOLDER)\n  },\n\n  /**\n   * @param {string} filename\n   * @param {ArrayBuffer} contents\n   * @returns {Promise<boolean>}\n   */\n  writeToDefaultFolder: async (filename, contents) => {\n    return await ipcRenderer.invoke(IpcChannels.WRITE_TO_DEFAULT_FOLDER, filename, contents)\n  },\n\n  relaunch: () => {\n    ipcRenderer.send(IpcChannels.RELAUNCH_REQUEST)\n  },\n\n  /**\n   * @param {import('../main/externalPlayer').ExternalPlayerPayload} payload\n   */\n  openInExternalPlayer: (payload) => {\n    // require the user to have interacted with the page recently\n    if (navigator.userActivation.isActive) {\n      ipcRenderer.send(IpcChannels.OPEN_IN_EXTERNAL_PLAYER, payload)\n    }\n  },\n\n  /**\n   * @param {(\n   *   externalPlayer: string,\n   *   unsuportedActions: (import('../constants').UnsupportedPlayerAction)[],\n   *   isPlaylist: boolean\n   * ) => void} handler\n   */\n  handleOpenInExternalPlayerResult: (handler) => {\n    ipcRenderer.on(IpcChannels.OPEN_IN_EXTERNAL_PLAYER_RESULT,\n      (event, externalPlayer, unsupportedActions, isPlaylist) => {\n        handler(externalPlayer, unsupportedActions, isPlaylist)\n      })\n  },\n\n  /**\n   * @param {number} factor\n   */\n  setZoomFactor: (factor) => {\n    if (typeof factor === 'number' && factor > 0) {\n      webFrame.setZoomFactor(factor)\n    }\n  },\n\n  /**\n   * @returns {Promise<{ label: string, value: number, active: boolean }[]>}\n   */\n  getNavigationHistory: () => {\n    return ipcRenderer.invoke(IpcChannels.GET_NAVIGATION_HISTORY)\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbSettings: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_SETTINGS, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbHistory: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_HISTORY, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbProfiles: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_PROFILES, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbPlaylists: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_PLAYLISTS, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbSearchHistory: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_SEARCH_HISTORY, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {number} action\n   * @param {any} [data]\n   */\n  dbSubscriptionCache: (action, data) => {\n    return ipcRenderer.invoke(IpcChannels.DB_SUBSCRIPTION_CACHE, data ? { action, data } : { action })\n  },\n\n  /**\n   * @param {(route: string) => void} handler\n   */\n  handleChangeView: (handler) => {\n    ipcRenderer.on(IpcChannels.CHANGE_VIEW, (_, route) => {\n      handler(route)\n    })\n  },\n\n  /**\n   * @param {(url: string) => void} handler\n   */\n  handleOpenUrl: (handler) => {\n    ipcRenderer.on(IpcChannels.OPEN_URL, (_, url) => {\n      handler(url)\n    })\n    ipcRenderer.send(IpcChannels.APP_READY)\n  },\n\n  /**\n   * Pass `null` to clear the handler\n   * @param {(text: string) => void | null} handler\n   */\n  handleUpdateSearchInputText: (handler) => {\n    if (currentUpdateSearchInputTextListener) {\n      ipcRenderer.off(IpcChannels.UPDATE_SEARCH_INPUT_TEXT, currentUpdateSearchInputTextListener)\n      currentUpdateSearchInputTextListener = undefined\n    }\n\n    if (handler) {\n      currentUpdateSearchInputTextListener = (_, text) => {\n        handler(text)\n      }\n\n      ipcRenderer.on(IpcChannels.UPDATE_SEARCH_INPUT_TEXT, currentUpdateSearchInputTextListener)\n      ipcRenderer.send(IpcChannels.SEARCH_INPUT_HANDLING_READY)\n    }\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncSettings: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_SETTINGS, (_, { event, data }) => {\n      handler(event, data)\n    })\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncHistory: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_HISTORY, (_, { event, data }) => {\n      handler(event, data)\n    })\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncSearchHistory: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_SEARCH_HISTORY, (_, { event, data }) => {\n      handler(event, data)\n    })\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncProfiles: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_PROFILES, (_, { event, data }) => {\n      handler(event, data)\n    })\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncPlaylists: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_PLAYLISTS, (_, { event, data }) => {\n      handler(event, data)\n    })\n  },\n\n  /**\n   * @param {(event: number, data: any) => void} handler\n   */\n  handleSyncSubscriptionCache: (handler) => {\n    ipcRenderer.on(IpcChannels.SYNC_SUBSCRIPTION_CACHE, (_, { event, data }) => {\n      handler(event, data)\n    })\n  }\n}\n"
  },
  {
    "path": "src/preload/main.js",
    "content": "import { contextBridge } from 'electron/renderer'\nimport api from './interface.js'\n\ncontextBridge.exposeInMainWorld('ftElectron', api)\n"
  },
  {
    "path": "src/preload/preload-interface.d.ts",
    "content": "import api from './interface.js'\n\ndeclare global {\n  interface Window {\n    ftElectron: typeof api\n  }\n}\n"
  },
  {
    "path": "src/renderer/App.css",
    "content": "@font-face {\n  font-family: Roboto;\n  src: url('assets/font/Roboto-Regular.ttf');\n}\n\n.app {\n  display: flex;\n  flex-wrap: wrap;\n  font-family: Roboto, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n  block-size: 100%;\n}\n\n.routerView {\n  flex: 1 1 0%;\n  margin-block: 18px;\n  margin-inline: 10px;\n}\n\n.banner {\n  inline-size: 85%;\n  margin-block: 40px 0;\n  margin-inline: auto;\n}\n\n.banner + .banner {\n  margin-block: 20px;\n}\n\n.banner-wrapper {\n  margin-block: 0;\n  margin-inline: 10px;\n}\n\n.flexBox {\n  display: block;\n  user-select: unset;\n}\n\n.changeLogTitle {\n  padding-inline: 16px;\n  overflow-wrap: break-word;\n  margin-block-end: 16px;\n}\n\n.changeLogText {\n  overflow-y: scroll;\n  block-size: 40vh;\n  display: block;\n  padding-inline: 16px;\n  margin-block-end: 16px;\n  overflow-wrap: break-word;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.15s;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n  opacity: 0;\n}\n\n@media only screen and (width <= 680px) {\n  .routerView {\n    margin-block: 68px;\n    margin-inline: 8px;\n  }\n\n  .banner {\n    inline-size: 90%;\n    margin-block: 60px 0;\n  }\n\n  .flexBox {\n    margin-block: 60px -75px;\n  }\n\n  .changeLogText {\n    block-size: 65vh;\n  }\n}\n"
  },
  {
    "path": "src/renderer/App.vue",
    "content": "<template>\n  <div\n    v-if=\"dataReady\"\n    class=\"app\"\n    :class=\"{\n      hideOutlines: outlinesHidden,\n      isLocaleRightToLeft: isLocaleRightToLeft,\n      isSideNavOpen: isSideNavOpen,\n      hideLabelsSideBar: hideLabelsSideBar && !isSideNavOpen\n    }\"\n  >\n    <TopNav\n      :inert=\"isAnyPromptOpen\"\n    />\n    <SideNav\n      :inert=\"isAnyPromptOpen\"\n    />\n    <FtFlexBox\n      class=\"flexBox routerView\"\n      role=\"main\"\n      :inert=\"isAnyPromptOpen\"\n    >\n      <div\n        v-if=\"showUpdatesBanner || showBlogBanner\"\n        class=\"banner-wrapper\"\n      >\n        <FtNotificationBanner\n          v-if=\"showUpdatesBanner\"\n          class=\"banner\"\n          :message=\"updateBannerMessage\"\n          role=\"link\"\n          @click=\"handleUpdateBannerClick\"\n        />\n        <FtNotificationBanner\n          v-if=\"showBlogBanner\"\n          class=\"banner\"\n          :message=\"blogBannerMessage\"\n          role=\"link\"\n          @click=\"handleNewBlogBannerClick\"\n        />\n      </div>\n      <RouterView\n        v-slot=\"{ Component }\"\n        class=\"routerView\"\n      >\n        <Transition\n          mode=\"out-in\"\n          name=\"fade\"\n        >\n          <component :is=\"Component\" />\n        </Transition>\n      </RouterView>\n    </FtFlexBox>\n    <FtPrompt\n      v-if=\"showReleaseNotes\"\n      theme=\"readable-width\"\n      @click=\"toggleShowReleaseNotes\"\n    >\n      <template #label=\"{ labelId }\">\n        <h1\n          :id=\"labelId\"\n          class=\"changeLogTitle\"\n          dir=\"ltr\"\n        >\n          {{ changeLogTitle }}\n        </h1>\n      </template>\n      <bdo\n        v-safer-html.lenient=\"updateChangelog\"\n        class=\"changeLogText\"\n        dir=\"ltr\"\n        lang=\"en\"\n      />\n      <FtFlexBox>\n        <FtButton\n          :label=\"t('Download From Site')\"\n          @click=\"openDownloadsPage\"\n        />\n        <FtButton\n          :label=\"t('Close')\"\n          :text-color=\"null\"\n          :background-color=\"null\"\n          @click=\"toggleShowReleaseNotes\"\n        />\n      </FtFlexBox>\n    </FtPrompt>\n    <FtPrompt\n      v-if=\"showExternalLinkOpeningPrompt\"\n      :label=\"t('Are you sure you want to open this link?')\"\n      :extra-labels=\"[lastExternalLinkToBeOpened]\"\n      :option-names=\"externalLinkOpeningPromptNames\"\n      :option-values=\"EXTERNAL_LINK_OPENING_PROMPT_VALUES\"\n      @click=\"handleExternalLinkOpeningPromptAnswer\"\n    />\n    <FtSearchFilters\n      v-if=\"showSearchFilters\"\n    />\n    <FtKeyboardShortcutPrompt\n      v-if=\"isKeyboardShortcutPromptShown\"\n    />\n    <FtPlaylistAddVideoPrompt\n      v-if=\"showAddToPlaylistPrompt\"\n    />\n    <FtCreatePlaylistPrompt\n      v-if=\"showCreatePlaylistPrompt\"\n    />\n    <FtToast />\n    <FtProgressBar\n      v-if=\"showProgressBar\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { marked } from 'marked'\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useI18n } from './composables/use-i18n-polyfill'\nimport { useRoute, useRouter } from 'vue-router'\n\nimport FtFlexBox from './components/ft-flex-box/ft-flex-box.vue'\nimport TopNav from './components/TopNav/TopNav.vue'\nimport SideNav from './components/SideNav/SideNav.vue'\nimport FtNotificationBanner from './components/FtNotificationBanner/FtNotificationBanner.vue'\nimport FtPrompt from './components/FtPrompt/FtPrompt.vue'\nimport FtButton from './components/FtButton/FtButton.vue'\nimport FtToast from './components/FtToast/FtToast.vue'\nimport FtProgressBar from './components/FtProgressBar/FtProgressBar.vue'\nimport FtPlaylistAddVideoPrompt from './components/FtPlaylistAddVideoPrompt/FtPlaylistAddVideoPrompt.vue'\nimport FtCreatePlaylistPrompt from './components/FtCreatePlaylistPrompt/FtCreatePlaylistPrompt.vue'\nimport FtKeyboardShortcutPrompt from './components/FtKeyboardShortcutPrompt/FtKeyboardShortcutPrompt.vue'\nimport FtSearchFilters from './components/FtSearchFilters/FtSearchFilters.vue'\nimport { vSaferHtml } from './directives/vSaferHtml.js'\n\nimport store from './store/index'\n\nimport packageDetails from '../../package.json'\nimport { openExternalLink, openInternalPath, showToast } from './helpers/utils'\nimport { translateWindowTitle } from './helpers/strings'\nimport { loadLocale } from './i18n/index'\n\nconst route = useRoute()\nconst router = useRouter()\nconst { locale, t } = useI18n()\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isSideNavOpen = computed(() => store.getters.getIsSideNavOpen)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLabelsSideBar = computed(() => store.getters.getHideLabelsSideBar)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isAnyPromptOpen = computed(() => store.getters.isAnyPromptOpen)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showSearchFilters = computed(() => store.getters.getShowSearchFilters)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isKeyboardShortcutPromptShown = computed(() => store.getters.getIsKeyboardShortcutPromptShown)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showAddToPlaylistPrompt = computed(() => store.getters.getShowAddToPlaylistPrompt)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showCreatePlaylistPrompt = computed(() => store.getters.getShowCreatePlaylistPrompt)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showProgressBar = computed(() => store.getters.getShowProgressBar)\n\nconst landingPage = computed(() => '/' + store.getters.getLandingPage)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst defaultInvidiousInstance = computed(() => store.getters.getDefaultInvidiousInstance)\n\nconst dataReady = ref(false)\n\nonMounted(async () => {\n  await store.dispatch('grabUserSettings')\n\n  updateTheme()\n\n  await store.dispatch('fetchInvidiousInstancesFromFile')\n  if (defaultInvidiousInstance.value === '') {\n    await store.dispatch('setRandomCurrentInvidiousInstance')\n  }\n\n  store.dispatch('fetchInvidiousInstances').then(() => {\n    if (defaultInvidiousInstance.value === '') {\n      store.dispatch('setRandomCurrentInvidiousInstance')\n    }\n  })\n\n  store.dispatch('grabAllProfiles', t('Profile.All Channels')).then(() => {\n    store.dispatch('grabHistory')\n    store.dispatch('grabAllPlaylists')\n    store.dispatch('grabAllSubscriptions')\n    store.dispatch('grabSearchHistoryEntries')\n\n    if (process.env.IS_ELECTRON) {\n      store.dispatch('setupListenersToSyncWindows')\n      document.addEventListener('click', handleClick)\n      document.addEventListener('auxclick', handleAuxClick)\n      enableOpenUrl()\n      store.dispatch('getExternalPlayerCmdArgumentsData')\n    }\n\n    dataReady.value = true\n\n    setTimeout(() => {\n      checkForNewUpdates()\n      checkForNewBlogPosts()\n    }, 500)\n  })\n\n  if (route.path === '/') {\n    router.replace({ path: landingPage.value })\n  }\n\n  setWindowTitle()\n\n  document.addEventListener('keydown', handleKeyboardShortcuts)\n  document.addEventListener('mousedown', handleMouseDown)\n  document.addEventListener('dragstart', handleDragStart)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', handleKeyboardShortcuts)\n  document.removeEventListener('mousedown', handleMouseDown)\n  document.removeEventListener('dragstart', handleDragStart)\n  document.removeEventListener('click', handleClick)\n  document.removeEventListener('auxclick', handleAuxClick)\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst baseTheme = computed(() => store.getters.getBaseTheme)\n\nwatch(baseTheme, updateTheme)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst mainColor = computed(() => store.getters.getMainColor)\n\nwatch(mainColor, updateTheme)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst secColor = computed(() => store.getters.getSecColor)\n\nwatch(secColor, updateTheme)\n\nfunction updateTheme() {\n  document.body.className = `${baseTheme.value || 'system'} main${mainColor.value || 'Red'} sec${secColor.value || 'Blue'}`\n  document.body.dataset.systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nupdateTheme()\n\nconst showUpdatesBanner = ref(false)\nconst latestVersionNumber = ref('')\nconst showReleaseNotes = ref(false)\nconst changeLogTitle = ref('')\nconst updateChangelog = ref('')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst checkForUpdates = computed(() => store.getters.getCheckForUpdates)\n\nconst updateBannerMessage = computed(() => {\n  return t('Version {versionNumber} is now available!  Click for more details', {\n    versionNumber: latestVersionNumber.value\n  })\n})\n\nasync function checkForNewUpdates() {\n  if (!checkForUpdates.value) {\n    return\n  }\n\n  try {\n    const response = await fetch('https://api.github.com/repos/freetubeapp/freetube/releases?per_page=1')\n    const json = await response.json()\n\n    const tagName = json[0].tag_name\n    const versionNumber = tagName.replace('v', '').replace('-beta', '')\n\n    let changelog = json[0].body\n      // Link usernames to their GitHub profiles\n      .replaceAll(/@(\\S+)\\b/g, '[@$1](https://github.com/$1)')\n      // Shorten pull request links to #1234\n      .replaceAll(/https:\\/\\/github\\.com\\/FreeTubeApp\\/FreeTube\\/pull\\/(\\d+)/g, '[#$1]($&)')\n\n    // Add the title\n    changelog = `${changelog}`\n\n    updateChangelog.value = marked.parse(changelog)\n    changeLogTitle.value = json[0].name\n    latestVersionNumber.value = versionNumber\n\n    const appVersion = packageDetails.version.split('.')\n    const latestVersion = versionNumber.split('.')\n\n    if (parseInt(appVersion[0]) < parseInt(latestVersion[0])) {\n      showUpdatesBanner.value = true\n    } else if (parseInt(appVersion[1]) < parseInt(latestVersion[1])) {\n      showUpdatesBanner.value = true\n    } else if (parseInt(appVersion[2]) < parseInt(latestVersion[2]) && parseInt(appVersion[1]) <= parseInt(latestVersion[1])) {\n      showUpdatesBanner.value = true\n    }\n  } catch (error) {\n    console.error('errored while checking for updates', 'https://api.github.com/repos/freetubeapp/freetube/releases?per_page=1', error)\n  }\n}\n\nfunction toggleShowReleaseNotes() {\n  showReleaseNotes.value = !showReleaseNotes.value\n}\n\n/**\n * @param {boolean} response\n */\nfunction handleUpdateBannerClick(response) {\n  if (response) {\n    showReleaseNotes.value = true\n  } else {\n    showUpdatesBanner.value = false\n  }\n}\n\nfunction openDownloadsPage() {\n  openExternalLink('https://freetubeapp.io#download')\n  showReleaseNotes.value = false\n  showUpdatesBanner.value = false\n}\n\nconst showBlogBanner = ref(false)\nconst latestBlogTitle = ref('')\nconst latestBlogUrl = ref('')\n\nconst blogBannerMessage = computed(() => {\n  return t('A new blog is now available, {blogTitle}. Click to view more', { blogTitle: latestBlogTitle.value })\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst checkForBlogPosts = computed(() => store.getters.getCheckForBlogPosts)\n\nasync function checkForNewBlogPosts() {\n  if (!checkForBlogPosts.value) {\n    return\n  }\n\n  let lastAppWasRunning = localStorage.getItem('lastAppWasRunning')\n\n  if (lastAppWasRunning !== null) {\n    lastAppWasRunning = new Date(lastAppWasRunning)\n  }\n\n  const response = await fetch('https://write.as/freetube/feed/')\n  const text = await response.text()\n  const xmlDom = new DOMParser().parseFromString(text, 'application/xml')\n\n  const latestBlog = xmlDom.querySelector('item')\n  const latestPubDate = new Date(latestBlog.querySelector('pubDate').textContent)\n\n  if (lastAppWasRunning === null || latestPubDate > lastAppWasRunning) {\n    latestBlogTitle.value = latestBlog.querySelector('title').textContent\n    latestBlogUrl.value = latestBlog.querySelector('link').textContent\n    showBlogBanner.value = true\n  }\n\n  localStorage.setItem('lastAppWasRunning', new Date())\n}\n\n/**\n * @param {boolean} response\n */\nfunction handleNewBlogBannerClick(response) {\n  if (response) {\n    openExternalLink(latestBlogUrl.value)\n  }\n\n  showBlogBanner.value = false\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst outlinesHidden = computed(() => store.getters.getOutlinesHidden)\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction handleKeyboardShortcuts(event) {\n  // ignore user typing in HTML `input` elements\n  if (event.shiftKey && event.key === '?' && event.target.tagName !== 'INPUT') {\n    store.commit('setIsKeyboardShortcutPromptShown', !isKeyboardShortcutPromptShown.value)\n  }\n\n  if (event.key === 'Tab') {\n    store.dispatch('showOutlines')\n  }\n}\n\nfunction handleMouseDown() {\n  store.dispatch('hideOutlines')\n}\n\nconst lastExternalLinkToBeOpened = ref('')\nconst showExternalLinkOpeningPrompt = ref(false)\nconst EXTERNAL_LINK_OPENING_PROMPT_VALUES = ['yes', 'no']\n\nconst externalLinkOpeningPromptNames = computed(() => [\n  t('Yes, Open Link'),\n  t('No')\n])\n\n/** @type {import('vue').ComputedRef<'' | 'openLinkAfterPrompt' | 'doNothing'>} */\nconst externalLinkHandling = computed(() => store.getters.getExternalLinkHandling)\n\n/**\n * @param {'yes' | 'no' | null} option\n */\nfunction handleExternalLinkOpeningPromptAnswer(option) {\n  showExternalLinkOpeningPrompt.value = false\n\n  if (option === 'yes' && lastExternalLinkToBeOpened.value.length > 0) {\n    // Maybe user should be notified\n    // if `lastExternalLinkToBeOpened` is empty\n\n    // Open links externally\n    openExternalLink(lastExternalLinkToBeOpened.value)\n  }\n}\n\n/**\n * @param {PointerEvent} event\n */\nfunction isExternalLink(event) {\n  return event.target.tagName === 'A' && !event.target.href.startsWith(window.location.origin)\n}\n\n/**\n * @param {PointerEvent} event\n */\nfunction handleClick(event) {\n  if (isExternalLink(event)) {\n    handleLinkClick(event)\n  }\n}\n\n/**\n * @param {PointerEvent} event\n */\nfunction handleAuxClick(event) {\n  // auxclick fires for all clicks not performed with the primary button\n  // only handle the link click if it was the middle button,\n  // otherwise the context menu breaks\n  if (isExternalLink(event) && event.button === 1) {\n    handleLinkClick(event)\n  }\n}\n\n/**\n * @param {PointerEvent} event\n */\nfunction handleLinkClick(event) {\n  const href = event.target.href\n  event.preventDefault()\n\n  // Check if it's a YouTube link, but exclude live chat pop out\n  const youtubeUrlPattern = /^https?:\\/\\/((www\\.)?youtube\\.com(\\/embed)?|youtu\\.be)\\/(?!.*live_chat).*$/\n  const isYoutubeLink = youtubeUrlPattern.test(href)\n\n  if (isYoutubeLink) {\n    // `auxclick` is the event type for non-left click\n    // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event\n    handleYoutubeLink(href, {\n      doCreateNewWindow: event.type === 'auxclick'\n    })\n  } else if (externalLinkHandling.value === 'doNothing') {\n    // Let user know opening external link is disabled via setting\n    showToast(t('External link opening has been disabled in the general settings'))\n  } else if (externalLinkHandling.value === 'openLinkAfterPrompt') {\n    // Storing the URL is necessary as\n    // there is no other way to pass the URL to click callback\n    lastExternalLinkToBeOpened.value = href\n    showExternalLinkOpeningPrompt.value = true\n  } else {\n    // Open links externally\n    openExternalLink(href)\n  }\n}\n\nasync function handleYoutubeLink(href, { doCreateNewWindow = false } = {}) {\n  const result = await store.dispatch('getYoutubeUrlInfo', href)\n\n  switch (result.urlType) {\n    case 'video': {\n      const { videoId, timestamp, playlistId } = result\n\n      const query = {}\n      if (timestamp) {\n        query.timestamp = timestamp\n      }\n      if (playlistId && playlistId.length > 0) {\n        query.playlistId = playlistId\n      }\n\n      openInternalPath({\n        path: `/watch/${videoId}`,\n        query,\n        doCreateNewWindow\n      })\n      break\n    }\n\n    case 'playlist': {\n      const { playlistId, query } = result\n\n      openInternalPath({\n        path: `/playlist/${playlistId}`,\n        query,\n        doCreateNewWindow\n      })\n      break\n    }\n\n    case 'search': {\n      const { searchQuery, query } = result\n\n      openInternalPath({\n        path: `/search/${encodeURIComponent(searchQuery)}`,\n        query,\n        doCreateNewWindow,\n        searchQueryText: searchQuery\n      })\n      break\n    }\n\n    case 'hashtag': {\n      const { hashtag } = result\n      openInternalPath({\n        path: `/hashtag/${encodeURIComponent(hashtag)}`,\n        doCreateNewWindow\n      })\n      break\n    }\n\n    case 'post': {\n      const { postId, query } = result\n\n      openInternalPath({\n        path: `/post/${postId}`,\n        query,\n        doCreateNewWindow\n      })\n      break\n    }\n\n    case 'channel': {\n      const { channelId, subPath, url } = result\n\n      openInternalPath({\n        path: `/channel/${channelId}/${subPath}`,\n        doCreateNewWindow,\n        query: {\n          url\n        }\n      })\n      break\n    }\n\n    case 'trending':\n    case 'subscriptions':\n    case 'history':\n    case 'userplaylists':\n      openInternalPath({\n        path: `/${result.urlType}`,\n        doCreateNewWindow\n      })\n      break\n\n    case 'invalid_url': {\n      // Do nothing\n      break\n    }\n\n    default: {\n      // Unknown URL type\n      showToast(t('Unknown YouTube url type, cannot be opened in app'))\n    }\n  }\n}\n\nfunction enableOpenUrl() {\n  window.ftElectron.handleOpenUrl((url) => {\n    if (url) {\n      handleYoutubeLink(url)\n    }\n  })\n}\n\nconst windowTitle = computed(() => {\n  const routePath = route.path\n  if (\n    !routePath.startsWith('/channel/') &&\n    !routePath.startsWith('/watch/') &&\n    !routePath.startsWith('/hashtag/') &&\n    !routePath.startsWith('/playlist/') &&\n    !routePath.startsWith('/search/')\n  ) {\n    let title = translateWindowTitle(route.meta.title)\n    if (!title) {\n      title = packageDetails.productName\n    } else {\n      title = `${title} - ${packageDetails.productName}`\n    }\n    return title\n  } else {\n    return null\n  }\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst appTitle = computed(() => store.getters.getAppTitle)\n\nwatch(appTitle, (value) => {\n  document.title = value\n})\n\nwatch(windowTitle, setWindowTitle)\n\nfunction setWindowTitle() {\n  if (windowTitle.value !== null) {\n    store.commit('setAppTitle', windowTitle.value)\n  }\n}\n\nconst isLocaleRightToLeft = computed(() => {\n  const locale_ = locale.value\n\n  return locale_ === 'ar' || locale_ === 'fa' || locale_ === 'he' ||\n  locale_ === 'ur' || locale_ === 'yi' || locale_ === 'ku'\n})\n\nwatch(locale, (value) => {\n  document.documentElement.lang = value\n\n  document.body.dir = isLocaleRightToLeft.value ? 'rtl' : 'ltr'\n}, { immediate: true })\n\n// en-US is the fallback locale, which means we always need it\n// regardless of the user's settings so we can already start start loading it now\nloadLocale('en-US')\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/**\n * Transforms dragged in-app URLs into YouTube ones, so they they can be dragged into other applications.\n * Cancels the drag operation if the URL is FreeTube specific and cannot be transformed e.g. user playlist URLs\n * @param {DragEvent} event\n */\nfunction handleDragStart(event) {\n  if (!event.dataTransfer.types.includes('text/uri-list')) {\n    return\n  }\n\n  const originalUrlString = event.dataTransfer.getData('text/uri-list')\n  const originalUrl = new URL(originalUrlString)\n\n  // Check if this is an in-app URL\n  if (originalUrl.origin !== window.location.origin || originalUrl.pathname !== window.location.pathname) {\n    return\n  }\n\n  const [path, query] = originalUrl.hash.slice(2).split('?')\n  const pathParts = path.split('/')\n  const params = new URLSearchParams(query)\n\n  let transformed = false\n  let transformedURL = new URL('https://www.youtube.com')\n\n  switch (pathParts[0]) {\n    case 'watch':\n      transformedURL.pathname = '/watch'\n      transformedURL.searchParams.set('v', pathParts[1])\n\n      if (params.has('timestamp')) {\n        transformedURL.searchParams.set('t', params.get('timestamp') + 's')\n      }\n\n      if (params.has('playlistId') && params.get('playlistType') !== 'user') {\n        transformedURL.searchParams.set('list', params.get('playlistId'))\n      }\n\n      transformed = true\n      break\n    case 'playlist':\n      if (params.get('playlistType') !== 'user') {\n        transformedURL.pathname = '/playlist'\n        transformedURL.searchParams.set('list', pathParts[1])\n\n        transformed = true\n      }\n      break\n    case 'channel':\n      transformedURL.pathname = `/channel/${pathParts[1]}`\n\n      if (pathParts[2]) {\n        switch (pathParts[2]) {\n          case 'community':\n            transformedURL.pathname += '/posts'\n            break\n          case 'search':\n            transformedURL.pathname += '/search'\n            if (params.has('searchQueryText')) {\n              transformedURL.searchParams.set('query', params.get('searchQueryText'))\n            }\n            break\n          case 'videos':\n          case 'shorts':\n          case 'releases':\n          case 'podcasts':\n          case 'courses':\n          case 'playlists':\n          case 'about':\n            transformedURL.pathname += `/${pathParts[2]}`\n            break\n        }\n      }\n\n      transformed = true\n      break\n    case 'search':\n      transformedURL.pathname = '/results'\n      transformedURL.searchParams.set('search_query', decodeURIComponent(pathParts[1]))\n      transformed = true\n      break\n    case 'hashtag':\n    case 'post':\n      transformedURL.pathname = `/${pathParts[0]}/${pathParts[1]}`\n      transformed = true\n      break\n    case 'subscriptions':\n    case 'history':\n      transformedURL.pathname = `/feed/${pathParts[1]}`\n      transformed = true\n      break\n    case 'userplaylists':\n      transformedURL.pathname = '/feed/playlists'\n      transformed = true\n      break\n    case 'settings':\n      transformedURL.pathname = '/account'\n      transformed = true\n      break\n    case 'about':\n      transformedURL.pathname = '/about'\n      transformed = true\n      break\n    case 'popular':\n      transformedURL = new URL(`${currentInvidiousInstanceUrl.value}/feed/popular`)\n      transformed = true\n      break\n  }\n\n  if (transformed) {\n    const transformedURLString = transformedURL.toString()\n\n    event.dataTransfer.setData('text/uri-list', transformedURLString)\n\n    const plainText = event.dataTransfer.getData('text/plain')\n    if (plainText.length > 0) {\n      event.dataTransfer.setData('text/plain', plainText.replaceAll(originalUrlString, transformedURLString))\n    }\n\n    const html = event.dataTransfer.getData('text/html')\n    if (html.length > 0) {\n      const originalUrlStringEncoded = originalUrlString.replaceAll('&', '&amp;')\n      const transformedURLStringEncoded = transformedURLString.replaceAll('&', '&amp;')\n\n      event.dataTransfer.setData('text/html', html.replaceAll(originalUrlStringEncoded, transformedURLStringEncoded))\n    }\n  } else {\n    // Cancel the drag operation for FreeTube specific URLs that cannot be transformed such as user playlist URLs\n    event.preventDefault()\n    event.stopPropagation()\n  }\n}\n</script>\n\n<style src=\"./themes.css\" />\n<style scoped src=\"./App.css\" />\n"
  },
  {
    "path": "src/renderer/components/ChannelAbout/ChannelAbout.css",
    "content": ".about {\n  background-color: var(--card-bg-color);\n  margin-block-start: 0;\n  padding: 10px;\n  position: relative;\n  z-index: 1;\n}\n\n.aboutInfo {\n  font-size: 17px;\n  white-space: pre-wrap;\n}\n\n.aboutTags {\n  display: flex;\n  flex-flow: row wrap;\n  gap: 5px 15px;\n  justify-content: center;\n  margin: 0;\n  padding: 0;\n}\n\n.aboutTag {\n  display: flex;\n  list-style: none;\n}\n\n.aboutTagLink {\n  background-color: var(--secondary-card-bg-color);\n  color: var(--primary-text-color);\n  border-radius: 7px;\n  padding: 7px;\n  text-decoration: none;\n}\n\n.aboutDetails {\n  text-align: start;\n}\n\n.aboutDetails th {\n  padding-inline-end: 10px;\n}\n"
  },
  {
    "path": "src/renderer/components/ChannelAbout/ChannelAbout.vue",
    "content": "<template>\n  <div\n    class=\"about\"\n  >\n    <template\n      v-if=\"description\"\n    >\n      <h2>{{ $t(\"Channel.About.Channel Description\") }}</h2>\n      <div\n        v-safer-html=\"description\"\n        class=\"aboutInfo\"\n        dir=\"auto\"\n      />\n    </template>\n    <template\n      v-if=\"joined || views !== null || videos !== null || location\"\n    >\n      <h2>{{ $t('Channel.About.Details') }}</h2>\n      <table\n        class=\"aboutDetails\"\n      >\n        <tr\n          v-if=\"joined\"\n        >\n          <th\n            scope=\"row\"\n          >\n            {{ $t('Channel.About.Joined') }}\n          </th>\n          <td>{{ formattedJoined }}</td>\n        </tr>\n        <tr\n          v-if=\"views !== null\"\n        >\n          <th\n            scope=\"row\"\n          >\n            {{ $t('Video.Views') }}\n          </th>\n          <td>{{ formattedViews }}</td>\n        </tr>\n        <tr\n          v-if=\"videos !== null\"\n        >\n          <th\n            scope=\"row\"\n          >\n            {{ $t('Global.Videos') }}\n          </th>\n          <td>{{ formattedVideos }}</td>\n        </tr>\n        <tr\n          v-if=\"location\"\n        >\n          <th\n            scope=\"row\"\n          >\n            {{ $t('Channel.About.Location') }}\n          </th>\n          <td\n            dir=\"auto\"\n          >\n            {{ location }}\n          </td>\n        </tr>\n      </table>\n    </template>\n    <template\n      v-if=\"tags.length > 0\"\n    >\n      <h2>{{ $t('Channel.About.Tags.Tags') }}</h2>\n      <ul\n        class=\"aboutTags\"\n      >\n        <li\n          v-for=\"tag in tags\"\n          :key=\"tag\"\n          class=\"aboutTag\"\n          dir=\"auto\"\n        >\n          <router-link\n            v-if=\"!hideSearchBar\"\n            class=\"aboutTagLink\"\n            :title=\"$t('Channel.About.Tags.Search for', { tag })\"\n            :to=\"{\n              path: `/search/${encodeURIComponent(tag)}`,\n              query: searchSettings\n            }\"\n          >\n            {{ tag }}\n          </router-link>\n          <span\n            v-else\n            class=\"aboutTagLink\"\n          >\n            {{ tag }}\n          </span>\n        </li>\n      </ul>\n    </template>\n    <template\n      v-if=\"!hideFeaturedChannels && relatedChannels.length > 0\"\n    >\n      <h2>{{ $t(\"Channel.About.Featured Channels\") }}</h2>\n      <FtFlexBox>\n        <FtChannelBubble\n          v-for=\"channel in relatedChannels\"\n          :key=\"channel.id\"\n          :channel-id=\"channel.id\"\n          :channel-name=\"channel.name\"\n          :channel-thumbnail=\"channel.thumbnailUrl\"\n        />\n      </FtFlexBox>\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtChannelBubble from '../../components/FtChannelBubble/FtChannelBubble.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport { vSaferHtml } from '../../directives/vSaferHtml.js'\n\nimport store from '../../store/index'\n\nimport { formatNumber } from '../../helpers/utils'\n\nconst { locale } = useI18n()\n\nconst props = defineProps({\n  description: {\n    type: String,\n    default: ''\n  },\n  joined: {\n    type: Number,\n    default: 0\n  },\n  views: {\n    type: Number,\n    default: null\n  },\n  videos: {\n    type: Number,\n    default: null\n  },\n  location: {\n    type: String,\n    default: null\n  },\n  tags: {\n    type: Array,\n    default: () => []\n  },\n  relatedChannels: {\n    type: Array,\n    default: () => []\n  }\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideFeaturedChannels = computed(() => {\n  return store.getters.getHideFeaturedChannels\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSearchBar = computed(() => {\n  return store.getters.getHideSearchBar\n})\n\n/** @type {import('vue').ComputedRef<{ sortBy: string, time: string, type: string, duration: string, features: string[] }>} */\nconst searchSettings = computed(() => {\n  return store.getters.getSearchSettings\n})\n\nconst formattedJoined = computed(() => {\n  return new Intl.DateTimeFormat([locale.value, 'en'], { dateStyle: 'long' }).format(props.joined)\n})\n\nconst formattedViews = computed(() => formatNumber(props.views))\nconst formattedVideos = computed(() => formatNumber(props.videos))\n</script>\n\n<style scoped src=\"./ChannelAbout.css\" />\n"
  },
  {
    "path": "src/renderer/components/ChannelDetails/ChannelDetails.css",
    "content": ".bannerContainer {\n  background: center / cover no-repeat var(--banner-url, transparent);\n  block-size: 13vw;\n  min-block-size: 110px;\n  max-block-size: 32vh;\n  inline-size: 100%;\n}\n\n.bannerContainer.default {\n  background-color: #000;\n  background-image: url('../../assets/img/defaultBanner.png');\n  background-repeat: repeat;\n  background-size: contain;\n}\n\n.infoContainer {\n  position: relative;\n  background-color: var(--card-bg-color);\n  margin-block-start: 10px;\n  padding-block: 0;\n  padding-inline: 16px;\n}\n\n.info {\n  display: flex;\n  flex-flow: row wrap;\n  inline-size: 100%;\n  justify-content: space-between;\n}\n\n.infoHasError {\n  padding-block-end: 10px;\n}\n\n.thumbnail {\n  inline-size: 100px;\n  block-size: 100px;\n  border-radius: 200px;\n  object-fit: cover;\n}\n\n.name {\n  font-weight: bold;\n  inline-size: 100%;\n  font-size: 25px;\n}\n\n.subCount {\n  color: var(--tertiary-text-color);\n  inset-block-start: 50px;\n  inset-inline-start: 120px;\n}\n\n.infoActionsContainer {\n  display: flex;\n  gap: 30px;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.shareIcon {\n  align-self: center;\n}\n\n.channelSearch {\n  margin-block-start: 10px;\n  max-inline-size: 250px;\n  inline-size: 220px;\n  margin-inline-start: auto;\n  align-self: flex-end;\n  flex: 1 1 0%;\n}\n\n.infoTabs {\n  position: relative;\n  inline-size: 100%;\n  block-size: auto;\n  justify-content: unset;\n  gap: 32px;\n  padding-block: 0.3em;\n  padding-inline: 0;\n  flex-wrap: nowrap;\n}\n\n.tabs {\n  display: flex;\n  flex: 0 1 66%;\n  flex-wrap: wrap;\n}\n\n.tab {\n  padding: 15px;\n  font-size: 15px;\n  cursor: pointer;\n  align-self: flex-end;\n  text-align: center;\n  color: var(--tertiary-text-color);\n  border-block-end: 3px solid transparent;\n}\n\n.tab:hover,\n.tab:focus {\n  font-weight: bold;\n  border-block-end: 3px solid var(--tertiary-text-color);\n}\n\n.selectedTab {\n  color: var(--primary-text-color);\n  border-block-end: 3px solid var(--primary-color);\n  font-weight: bold;\n  box-sizing: border-box;\n}\n\n.thumbnailContainer {\n  display: flex;\n}\n\n.lineContainer {\n  display: flex;\n  justify-content: center;\n  flex-direction: column;\n  padding-inline-start: 1em;\n}\n\n.name,\n.subCount {\n  margin: 0;\n}\n\n@media only screen and (width <=800px) {\n  .infoTabs {\n    block-size: auto;\n    flex-flow: column-reverse;\n    gap: 0;\n  }\n\n  .channelSearch {\n    inline-size: 100%;\n    max-inline-size: none;\n  }\n\n  .tabs {\n    flex: 1 1 0;\n  }\n\n  .tab {\n    flex: 1 1 0%;\n  }\n}\n\n@media only screen and (width <=680px) {\n  .info {\n    flex-direction: column;\n    margin-block: 20px 10px;\n  }\n\n  .infoActionsContainer {\n    flex-direction: row-reverse;\n    justify-content: left;\n    gap: 10px;\n    margin-block-start: 5px;\n  }\n}\n\n@media only screen and (width <=400px) {\n  .info {\n    justify-content: center;\n    gap: 10px;\n  }\n\n  .infoActionsContainer {\n    justify-content: center;\n  }\n\n  .clineContainer {\n    padding-inline-start: 0;\n  }\n\n  .thumbnailContainer {\n    flex-direction: column;\n  }\n\n  .thumbnailContainer,\n  .infoActionsContainer {\n    flex-wrap: wrap;\n    align-items: center;\n    text-align: center;\n    gap: 10px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ChannelDetails/ChannelDetails.vue",
    "content": "<template>\n  <FtCard>\n    <div\n      class=\"bannerContainer\"\n      :class=\"{\n        default: !bannerUrl\n      }\"\n      :style=\"{ '--banner-url': `url('${bannerUrl}')` }\"\n    />\n\n    <div\n      class=\"infoContainer\"\n    >\n      <div\n        class=\"info\"\n        :class=\"{ infoHasError: hasErrorMessage }\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <img\n            v-if=\"thumbnailUrl\"\n            class=\"thumbnail\"\n            :src=\"thumbnailUrl\"\n            alt=\"\"\n          >\n          <FontAwesomeIcon\n            v-else\n            class=\"thumbnail\"\n            :icon=\"['fas', 'circle-user']\"\n          />\n          <div\n            class=\"lineContainer\"\n          >\n            <h1\n              class=\"name\"\n              dir=\"auto\"\n            >\n              {{ name }}\n            </h1>\n\n            <p\n              v-if=\"subCount !== null && !hideChannelSubscriptions\"\n              class=\"subCount\"\n            >\n              {{ $t('Global.Counts.Subscriber Count', { count: formattedSubCount }, subCount) }}\n            </p>\n          </div>\n        </div>\n\n        <div class=\"infoActionsContainer\">\n          <FtShareButton\n            v-if=\"!hideSharingActions && showShareMenu\"\n            :id=\"id\"\n            share-target-type=\"Channel\"\n            class=\"shareIcon\"\n          />\n\n          <FtSubscribeButton\n            v-if=\"!hideUnsubscribeButton && (!hasErrorMessage || isSubscribed)\"\n            :channel-id=\"id\"\n            :channel-name=\"name\"\n            :channel-thumbnail=\"thumbnailUrl\"\n            @subscribed=\"subscribed\"\n          />\n        </div>\n      </div>\n\n      <FtFlexBox\n        v-if=\"!hasErrorMessage\"\n        class=\"infoTabs\"\n      >\n        <div\n          class=\"tabs\"\n          role=\"tablist\"\n          :aria-label=\"$t('Channel.Channel Tabs')\"\n        >\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('home')\"\n            id=\"homeTab\"\n            class=\"tab\"\n            :class=\"{ selectedTab: currentTab === 'home' }\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'home'\"\n            aria-controls=\"homePanel\"\n            :tabindex=\"(currentTab === 'home' || currentTab === 'search') ? 0 : -1\"\n            @click=\"changeTab('home')\"\n            @keydown.left.right=\"focusTab('home', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('home')\"\n          >\n            {{ $t(\"Channel.Home.Home\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('videos')\"\n            id=\"videosTab\"\n            class=\"tab\"\n            :class=\"{ selectedTab: currentTab === 'videos' }\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'videos'\"\n            aria-controls=\"videoPanel\"\n            :tabindex=\"(currentTab === 'videos' || currentTab === 'search') ? 0 : -1\"\n            @click=\"changeTab('videos')\"\n            @keydown.left.right=\"focusTab('videos', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('videos')\"\n          >\n            {{ $t(\"Channel.Videos.Videos\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('shorts')\"\n            id=\"shortsTab\"\n            class=\"tab\"\n            :class=\"{ selectedTab: currentTab === 'shorts' }\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'shorts'\"\n            aria-controls=\"shortPanel\"\n            :tabindex=\"currentTab === 'shorts' ? 0 : -1\"\n            @click=\"changeTab('shorts')\"\n            @keydown.left.right=\"focusTab('shorts', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('shorts')\"\n          >\n            {{ $t(\"Global.Shorts\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('live')\"\n            id=\"liveTab\"\n            class=\"tab\"\n            :class=\"{ selectedTab: currentTab === 'live' }\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'live'\"\n            aria-controls=\"livePanel\"\n            :tabindex=\"currentTab === 'live' ? 0 : -1\"\n            @click=\"changeTab('live')\"\n            @keydown.left.right=\"focusTab('live', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('live')\"\n          >\n            {{ $t(\"Channel.Live.Live\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('releases')\"\n            id=\"releasesTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'releases'\"\n            aria-controls=\"releasePanel\"\n            :tabindex=\"currentTab === 'releases' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'releases' }\"\n            @click=\"changeTab('releases')\"\n            @keydown.left.right=\"focusTab('releases', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('releases')\"\n          >\n            {{ $t(\"Channel.Releases.Releases\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('podcasts')\"\n            id=\"podcastsTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'podcasts'\"\n            aria-controls=\"podcastPanel\"\n            :tabindex=\"currentTab === 'podcasts' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'podcasts' }\"\n            @click=\"changeTab('podcasts')\"\n            @keydown.left.right=\"focusTab('podcasts', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('podcasts')\"\n          >\n            {{ $t(\"Channel.Podcasts.Podcasts\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('courses')\"\n            id=\"coursesTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'courses'\"\n            aria-controls=\"coursesPanel\"\n            :tabindex=\"currentTab === 'courses' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'courses' }\"\n            @click=\"changeTab('courses')\"\n            @keydown.left.right=\"focusTab('courses', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('courses')\"\n          >\n            {{ $t(\"Channel.Courses.Courses\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('playlists')\"\n            id=\"playlistsTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'playlists'\"\n            aria-controls=\"playlistPanel\"\n            :tabindex=\"currentTab === 'playlists' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'playlists' }\"\n            @click=\"changeTab('playlists')\"\n            @keydown.left.right=\"focusTab('playlists', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('playlists')\"\n          >\n            {{ $t(\"Channel.Playlists.Playlists\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            v-if=\"visibleTabs.includes('community')\"\n            id=\"communityTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'community'\"\n            aria-controls=\"communityPanel\"\n            :tabindex=\"currentTab === 'community' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'community' }\"\n            @click=\"changeTab('community')\"\n            @keydown.left.right=\"focusTab('community', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('community')\"\n          >\n            {{ $t(\"Global.Posts\") }}\n          </div>\n          <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n          <div\n            id=\"aboutTab\"\n            class=\"tab\"\n            role=\"tab\"\n            :aria-selected=\"currentTab === 'about'\"\n            aria-controls=\"aboutPanel\"\n            :tabindex=\"currentTab === 'about' ? 0 : -1\"\n            :class=\"{ selectedTab: currentTab === 'about' }\"\n            @click=\"changeTab('about')\"\n            @keydown.left.right=\"focusTab('about', $event)\"\n            @keydown.enter.space.prevent=\"changeTab('about')\"\n          >\n            {{ $t(\"Channel.About.About\") }}\n          </div>\n        </div>\n\n        <FtInput\n          v-if=\"showSearchBar\"\n          ref=\"searchBar\"\n          :placeholder=\"$t('Channel.Search Channel')\"\n          :value=\"query\"\n          :show-clear-text-button=\"true\"\n          class=\"channelSearch\"\n          :maxlength=\"255\"\n          @click=\"search\"\n        />\n      </FtFlexBox>\n    </div>\n  </FtCard>\n</template>\n\n<script setup>\nimport { computed, onBeforeUnmount, onMounted, useTemplateRef } from 'vue'\n\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtShareButton from '../FtShareButton/FtShareButton.vue'\nimport FtSubscribeButton from '../FtSubscribeButton/FtSubscribeButton.vue'\nimport FtInput from '../FtInput/FtInput.vue'\n\nimport store from '../../store/index'\n\nimport { ctrlFHandler, formatNumber } from '../../helpers/utils'\n\nconst props = defineProps({\n  id: {\n    type: String,\n    required: true\n  },\n  name: {\n    type: String,\n    default: null\n  },\n  bannerUrl: {\n    type: String,\n    default: null\n  },\n  hasErrorMessage: {\n    type: Boolean,\n    default: false\n  },\n  thumbnailUrl: {\n    type: String,\n    default: null\n  },\n  subCount: {\n    type: Number,\n    default: null\n  },\n  showShareMenu: {\n    type: Boolean,\n    default: true\n  },\n  showSearchBar: {\n    type: Boolean,\n    default: true\n  },\n  isSubscribed: {\n    type: Boolean,\n    default: false\n  },\n  visibleTabs: {\n    type: Array,\n    default: () => ([])\n  },\n  currentTab: {\n    type: String,\n    default: 'videos'\n  },\n  query: {\n    type: String,\n    default: ''\n  },\n})\n\nconst emit = defineEmits(['change-tab', 'search', 'subscribed'])\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelSubscriptions = computed(() => {\n  return store.getters.getHideChannelSubscriptions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSharingActions = computed(() => {\n  return store.getters.getHideSharingActions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUnsubscribeButton = computed(() => {\n  return store.getters.getHideUnsubscribeButton\n})\n\nconst formattedSubCount = computed(() => {\n  if (hideChannelSubscriptions.value) {\n    return null\n  }\n  return formatNumber(props.subCount)\n})\n\nfunction subscribed() {\n  emit('subscribed')\n}\n\n/**\n * @param {string} tab\n */\nfunction changeTab(tab) {\n  emit('change-tab', tab)\n}\n\n/**\n * @param {string} currentTab\n * @param {KeyboardEvent} event\n */\nfunction focusTab(currentTab, event) {\n  if (event.altKey) {\n    return\n  }\n\n  event.preventDefault()\n\n  const visibleTabs = props.visibleTabs\n\n  const index = visibleTabs.indexOf(currentTab)\n\n  // focus left or right tab with wrap around\n  const tab = (event.key === 'ArrowLeft')\n    ? visibleTabs[(index > 0 ? index : visibleTabs.length) - 1]\n    : visibleTabs[(index + 1) % visibleTabs.length]\n\n  document.getElementById(`${tab}Tab`).focus()\n  store.dispatch('showOutlines')\n}\n\n/**\n * @param {string} query\n */\nfunction search(query) {\n  emit('search', query)\n}\n\nconst searchBar = useTemplateRef('searchBar')\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchBar.value)\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n</script>\n\n<style scoped src=\"./ChannelDetails.css\" />\n"
  },
  {
    "path": "src/renderer/components/ChannelHome/ChannelHome.css",
    "content": ".shelfContainer {\n  max-inline-size: 85vw;\n}\n\n.shelfTitle {\n  font-size: 24px;\n  cursor: pointer;\n\n  /* Prevents overflow for long values */\n  max-inline-size: 100%;\n  overflow-wrap: anywhere;\n}\n\n.shelfTitle::marker {\n  font-size: 20px;\n  color: var(--accent-color);\n}\n\n.shelfUnderline {\n  border-color: var(--primary-color);\n}\n\n.playAllSpan {\n  font-size: 18px;\n  margin-inline-start: 10px;\n}\n\n.playAllLink {\n  font-style: italic;\n  padding-block: 5px;\n  padding-inline: 7px;\n  border-radius: 10px;\n  text-decoration: none;\n}\n\n.playAllLink:hover {\n  background-color: var(--bg-color);\n}\n\n.shelfSubtitle {\n  font-style: italic;\n  color: var(--tertiary-text-color);\n\n  /* Prevents overflow for long values */\n  max-inline-size: 100%;\n  overflow-wrap: anywhere;\n}\n"
  },
  {
    "path": "src/renderer/components/ChannelHome/ChannelHome.vue",
    "content": "<template>\n  <div>\n    <div\n      v-for=\"(shelf, index) in filteredShelves\"\n      :key=\"index\"\n      class=\"shelfContainer\"\n    >\n      <details\n        open\n      >\n        <summary\n          class=\"shelfTitle\"\n        >\n          <bdi>\n            {{ shelf.title }}\n          </bdi>\n          <span\n            v-if=\"shelf.playlistId\"\n            class=\"playAllSpan\"\n          >\n            <router-link\n              class=\"playAllLink\"\n              :to=\"{\n                path: `/playlist/${shelf.playlistId}`\n              }\"\n            >\n              <FontAwesomeIcon\n                class=\"thumbnail\"\n                :icon=\"['fas', 'list']\"\n              />\n              {{ $t('Channel.Home.View Playlist') }}\n            </router-link>\n          </span>\n          <hr class=\"shelfUnderline\">\n        </summary>\n        <p\n          v-if=\"shelf.subtitle\"\n          class=\"shelfSubtitle\"\n          dir=\"auto\"\n        >\n          {{ shelf.subtitle }}\n        </p>\n        <FtElementList\n          :data=\"shelf.content\"\n          :use-channels-hidden-preference=\"false\"\n          :display=\"shelf.isCommunity ? 'list' : ''\"\n        />\n      </details>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed } from 'vue'\nimport FtElementList from '../FtElementList/FtElementList.vue'\nimport store from '../../store/index'\n\nconst props = defineProps({\n  shelves: {\n    type: Array,\n    default: () => []\n  }\n})\n\n/** @type {import('vue').ComputedRef<bool>} */\nconst hideFeaturedChannels = computed(() => {\n  return store.getters.getHideFeaturedChannels\n})\n\nconst filteredShelves = computed(() => {\n  let shelves = props.shelves\n  if (hideFeaturedChannels.value) {\n    shelves = shelves.filter(shelf => shelf.content[0].type !== 'channel')\n  }\n\n  return shelves.filter(shelf => shelf.content.length > 0)\n})\n</script>\n\n<style scoped src=\"./ChannelHome.css\" />\n"
  },
  {
    "path": "src/renderer/components/CommentSection/CommentSection.css",
    "content": ".card {\n  padding-block: 0;\n  padding-inline: 16px;\n}\n\n.getCommentsTitle,\n.commentsTitle,\n.getMoreComments {\n  margin: 0;\n}\n\n.getCommentsTitle {\n  padding-block: 8px;\n  text-align: center;\n  text-decoration: underline;\n  cursor: pointer;\n  color: var(--title-color);\n}\n\n.noCommentMsg {\n  padding-block: 1em;\n  text-align: center;\n}\n\n.commentsTitle {\n  padding-block: 1em;\n  display: inline-block;\n}\n\n.commentSort {\n  float: inline-end;\n}\n\n@media only screen and (width <= 1000px) {\n  .commentSort {\n    float: none;\n  }\n}\n\n\n.comment {\n  padding: 15px;\n}\n\n.hideComments {\n  font-size: 13px;\n  text-decoration: underline;\n  cursor: pointer;\n  color: var(--title-color);\n}\n\n.commentThumbnail {\n  float: inline-start;\n  inline-size: 60px;\n  block-size: 60px;\n  border-radius: 200px;\n}\n\n.commentThumbnailHidden {\n  float: inline-start;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  inline-size: 60px;\n  block-size: 60px;\n  font-size: 20px;\n  line-height: 1em;\n  color: rgb(0 0 0);\n  background-color: rgb(235 160 172);\n  border-radius: 50%;\n}\n\n.commentAuthorWrapper {\n  font-weight: bold;\n  font-size: 14px;\n  margin-inline-start: 68px;\n  margin-block-start: 0;\n  overflow-wrap: break-word;\n}\n\n.commentOwner {\n  background-color: var(--secondary-card-bg-color);\n  border-radius: 10px;\n  padding-inline: 10px;\n}\n\n\n.commentAuthor {\n  color: inherit;\n  text-decoration: none;\n}\n\n.commentText {\n  white-space: pre-wrap;\n  font-size: 14px;\n  /* stylelint-disable-next-line liberty/use-logical-spec */\n  margin-left: -10px;\n  margin-inline-start: 70px;\n  overflow-wrap: break-word;\n}\n\n/* stylelint-disable liberty/use-logical-spec */\n:global(body[dir='rtl'] .commentText) {\n  margin-left: initial;\n  margin-right: -10px;\n}\n/* stylelint-enable liberty/use-logical-spec */\n\n.commentPinned {\n  font-weight: normal;\n  font-size: 12px;\n  margin-block: 0 5px;\n  margin-inline-start: 68px;\n}\n\n.commentDate {\n  font-weight: normal;\n  margin-inline-start: 5px;\n  font-size: 12px;\n}\n\n.commentMemberIcon {\n  margin-inline-start: 5px;\n  inline-size: 14px;\n  block-size: 14px;\n}\n\n.commentSubscribedIcon {\n  content: var(--logo-icon);\n  block-size: 14px;\n  inline-size: 14px;\n  vertical-align: middle;\n  margin-inline: 0.25em;\n}\n\n.commentLikeCount {\n  font-size: 11px;\n  margin-inline-start: 70px;\n  margin-block-start: 0;\n}\n\n.commentHeartBadge {\n  display: inline-block;\n  position: relative;\n  inline-size: 25px;\n  block-size: 20px;\n  margin-inline-start: 10px;\n  margin-block-end: -7px;\n}\n\n.commentHeartBadgeImg {\n  position: absolute;\n  inset-inline-start: 0;\n  inline-size: 15px;\n  block-size: 15px;\n  border-radius: 50%;\n}\n\n.commentHeartBadgeWhite {\n  position: absolute;\n  inset-inline-start: 9px;\n  inset-block-end: 1px;\n  inline-size: 11px;\n  block-size: 11px;\n  z-index: 1;\n}\n\n.commentHeartBadgeRed {\n  position: absolute;\n  color: var(--red-500);\n  inset-inline-start: 10px;\n  inset-block-end: 2px;\n  inline-size: 9px;\n  block-size: 9px;\n  z-index: 2;\n}\n\n.commentMoreReplies {\n  font-size: 11px;\n  margin-inline-start: 5px;\n  text-decoration: underline;\n  cursor: pointer;\n  color: var(--title-color);\n}\n\n.commentReplies {\n  margin-inline-start: 30px;\n}\n\n.showMoreReplies {\n  margin-inline-start: 30px;\n  font-size: 15px;\n  cursor: pointer;\n  text-decoration: underline;\n}\n\n.getMoreComments {\n  padding-block-end: 1em;\n  text-align: center;\n  text-decoration: underline;\n  cursor: pointer;\n  color: var(--title-color);\n}\n"
  },
  {
    "path": "src/renderer/components/CommentSection/CommentSection.vue",
    "content": "<template>\n  <FtCard\n    class=\"card\"\n  >\n    <h3\n      v-if=\"commentData.length > 0 && !isLoading && showComments\"\n      class=\"commentsTitle\"\n    >\n      {{ $t(\"Comments.Comments\") }}\n      <span\n        class=\"hideComments\"\n        role=\"button\"\n        tabindex=\"0\"\n        @click=\"showComments = false\"\n        @keydown.space.prevent=\"showComments = false\"\n        @keydown.enter.prevent=\"showComments = false\"\n      >\n        {{ $t(\"Comments.Hide Comments\") }}\n      </span>\n    </h3>\n    <h4\n      v-if=\"canPerformInitialCommentLoading\"\n      class=\"getCommentsTitle\"\n      role=\"button\"\n      tabindex=\"0\"\n      @click=\"getCommentData\"\n      @keydown.space.prevent=\"getCommentData\"\n      @keydown.enter.prevent=\"getCommentData\"\n    >\n      {{ $t(\"Comments.Click to View Comments\") }}\n    </h4>\n    <h4\n      v-if=\"commentData.length > 0 && !isLoading && !showComments\"\n      class=\"getCommentsTitle\"\n      role=\"button\"\n      tabindex=\"0\"\n      @click=\"showComments = true\"\n      @keydown.space.prevent=\"showComments = true\"\n      @keydown.enter.prevent=\"showComments = true\"\n    >\n      {{ $t(\"Comments.Click to View Comments\") }}\n    </h4>\n    <FtSelect\n      v-if=\"commentData.length > 0 && !isLoading && showComments && showSortBy\"\n      class=\"commentSort\"\n      :placeholder=\"$t('Global.Sort By')\"\n      :value=\"currentSortValue\"\n      :select-names=\"sortNames\"\n      :select-values=\"sortValues\"\n      :icon=\"['fas', 'arrow-down-short-wide']\"\n      @change=\"handleSortChange\"\n    />\n    <div\n      v-if=\"commentData.length > 0 && showComments\"\n    >\n      <div\n        v-for=\"(comment, index) in commentData\"\n        :id=\"'comment' + index\"\n        :key=\"comment.id\"\n        class=\"comment\"\n      >\n        <router-link\n          :to=\"`/channel/${comment.authorLink}`\"\n          tabindex=\"-1\"\n        >\n          <!-- Hide comment photo only if it isn't the video uploader -->\n          <div\n            v-if=\"hideCommentPhotos && !comment.isOwner\"\n            class=\"commentThumbnailHidden\"\n            dir=\"auto\"\n          >\n            {{ comment.author.substring(1, 2) }}\n          </div>\n          <img\n            v-else\n            :src=\"comment.authorThumb\"\n            alt=\"\"\n            class=\"commentThumbnail\"\n          >\n        </router-link>\n        <p\n          v-if=\"comment.isPinned\"\n          class=\"commentPinned\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'thumbtack']\"\n          />\n          {{ $t(\"Comments.Pinned by\") }} <bdi>{{ channelName }}</bdi>\n        </p>\n        <p\n          class=\"commentAuthorWrapper\"\n        >\n          <router-link\n            class=\"commentAuthor\"\n            dir=\"auto\"\n            :class=\"{\n              commentOwner: comment.isOwner\n            }\"\n            :to=\"`/channel/${comment.authorLink}`\"\n          >\n            {{ comment.author }}\n          </router-link>\n          <img\n            v-if=\"comment.isMember\"\n            :src=\"comment.memberIconUrl\"\n            :title=\"$t('Comments.Member')\"\n            :aria-label=\"$t('Comments.Member')\"\n            class=\"commentMemberIcon\"\n            alt=\"\"\n          >\n          <img\n            v-if=\"isSubscribedToChannel(comment.authorId)\"\n            :title=\"$t('Comments.Subscribed')\"\n            :aria-label=\"$t('Comments.Subscribed')\"\n            class=\"commentSubscribedIcon\"\n            alt=\"\"\n          >\n          <span class=\"commentDate\">\n            {{ comment.time }}\n          </span>\n        </p>\n        <FtTimestampCatcher\n          class=\"commentText\"\n          :input-html=\"comment.text\"\n          @timestamp-event=\"onTimestamp\"\n        />\n        <p class=\"commentLikeCount\">\n          <template\n            v-if=\"!hideCommentLikes\"\n          >\n            <FontAwesomeIcon\n              :icon=\"['fas', 'thumbs-up']\"\n            />\n            {{ comment.likes }}\n          </template>\n          <span\n            v-if=\"comment.isHearted\"\n            class=\"commentHeartBadge\"\n          >\n            <img\n              :src=\"channelThumbnail\"\n              :title=\"$t('Comments.Hearted')\"\n              :aria-label=\"$t('Comments.Hearted')\"\n              class=\"commentHeartBadgeImg\"\n              alt=\"\"\n            >\n            <FontAwesomeIcon\n              :icon=\"['fas', 'heart']\"\n              class=\"commentHeartBadgeWhite\"\n            />\n            <FontAwesomeIcon\n              :icon=\"['fas', 'heart']\"\n              class=\"commentHeartBadgeRed\"\n            />\n          </span>\n          <span\n            v-if=\"comment.numReplies > 0\"\n            class=\"commentMoreReplies\"\n            role=\"button\"\n            tabindex=\"0\"\n            @click=\"toggleCommentReplies(index)\"\n            @keydown.space.prevent=\"toggleCommentReplies(index)\"\n            @keydown.enter.prevent=\"toggleCommentReplies(index)\"\n          >\n            <span>\n              {{ toggleCommentRepliesLinkText(comment) }}\n            </span>\n          </span>\n        </p>\n        <div\n          v-if=\"comment.showReplies\"\n          class=\"commentReplies\"\n        >\n          <div\n            v-for=\"(reply, replyIndex) in comment.replies\"\n            :id=\"'comment' + index + '-' + replyIndex\"\n            :key=\"replyIndex\"\n            class=\"comment\"\n          >\n            <router-link\n              :to=\"`/channel/${reply.authorLink}`\"\n              tabindex=\"-1\"\n            >\n              <!-- Hide comment photo only if it isn't the video uploader -->\n              <div\n                v-if=\"hideCommentPhotos && !reply.isOwner\"\n                class=\"commentThumbnailHidden\"\n                dir=\"auto\"\n              >\n                {{ reply.author.substring(1, 2) }}\n              </div>\n              <img\n                v-else\n                :src=\"reply.authorThumb\"\n                alt=\"\"\n                class=\"commentThumbnail\"\n              >\n            </router-link>\n            <p class=\"commentAuthorWrapper\">\n              <router-link\n                class=\"commentAuthor\"\n                dir=\"auto\"\n                :class=\"{\n                  commentOwner: reply.isOwner\n                }\"\n                :to=\"`/channel/${reply.authorLink}`\"\n              >\n                {{ reply.author }}\n              </router-link>\n              <img\n                v-if=\"reply.isMember\"\n                :src=\"reply.memberIconUrl\"\n                class=\"commentMemberIcon\"\n                alt=\"\"\n              >\n              <img\n                v-if=\"isSubscribedToChannel(reply.authorId)\"\n                :title=\"$t('Comments.Subscribed')\"\n                :aria-label=\"$t('Comments.Subscribed')\"\n                class=\"commentSubscribedIcon\"\n                alt=\"\"\n              >\n              <span class=\"commentDate\">\n                {{ reply.time }}\n              </span>\n            </p>\n            <FtTimestampCatcher\n              class=\"commentText\"\n              :input-html=\"reply.text\"\n              @timestamp-event=\"onTimestamp\"\n            />\n            <p class=\"commentLikeCount\">\n              <template\n                v-if=\"!hideCommentLikes\"\n              >\n                <FontAwesomeIcon\n                  v-if=\"!hideCommentLikes\"\n                  :icon=\"['fas', 'thumbs-up']\"\n                />\n                {{ reply.likes }}\n              </template>\n              <span\n                v-if=\"reply.isHearted\"\n                class=\"commentHeartBadge\"\n              >\n                <img\n                  :src=\"channelThumbnail\"\n                  :title=\"$t('Comments.Hearted')\"\n                  :aria-label=\"$t('Comments.Hearted')\"\n                  class=\"commentHeartBadgeImg\"\n                  alt=\"\"\n                >\n                <FontAwesomeIcon\n                  :icon=\"['fas', 'heart']\"\n                  class=\"commentHeartBadgeWhite\"\n                />\n                <FontAwesomeIcon\n                  :icon=\"['fas', 'heart']\"\n                  class=\"commentHeartBadgeRed\"\n                />\n              </span>\n            </p>\n            <p\n              v-if=\"reply.numReplies > 0\"\n              class=\"commentMoreReplies\"\n            >\n              {{ $t('Comments.View {replyCount} replies', { replyCount: reply.numReplies }, reply.numReplies) }}\n            </p>\n          </div>\n          <div\n            v-if=\"comment.hasReplyToken\"\n            class=\"showMoreReplies\"\n            role=\"button\"\n            tabindex=\"0\"\n            @click=\"getCommentReplies(index)\"\n            @keydown.space.prevent=\"getCommentReplies(index)\"\n            @keydown.enter.prevent=\"getCommentReplies(index)\"\n          >\n            <span>{{ $t(\"Comments.Show More Replies\") }}</span>\n          </div>\n        </div>\n      </div>\n    </div>\n    <div\n      v-else-if=\"showComments && !isLoading\"\n    >\n      <h3\n        v-if=\"isPostComments\"\n        class=\"noCommentMsg\"\n      >\n        {{ $t(\"Comments.There are no comments available for this post\") }}\n      </h3>\n      <h3\n        v-else\n        class=\"noCommentMsg\"\n      >\n        {{ $t(\"Comments.There are no comments available for this video\") }}\n      </h3>\n    </div>\n    <h4\n      v-if=\"canPerformMoreCommentLoading\"\n      class=\"getMoreComments\"\n      role=\"button\"\n      tabindex=\"0\"\n      @click=\"getMoreComments\"\n      @keydown.space.prevent=\"getMoreComments\"\n      @keydown.enter.prevent=\"getMoreComments\"\n    >\n      {{ $t(\"Comments.Load More Comments\") }}\n    </h4>\n    <FtLoader\n      v-if=\"isLoading\"\n    />\n    <div\n      v-observe-visibility=\"observeVisibilityOptions\"\n    >\n      <!--\n        Dummy element to be observed by Intersection Observer\n      -->\n    </div>\n  </FtCard>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, ref, shallowRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtLoader from '../FtLoader/FtLoader.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\nimport FtTimestampCatcher from '../FtTimestampCatcher.vue'\n\nimport store from '../../store/index'\n\nimport { copyToClipboard, showToast } from '../../helpers/utils'\nimport { getLocalCommunityPostComments, getLocalComments, parseLocalComment } from '../../helpers/api/local'\nimport {\n  getInvidiousCommunityPostCommentReplies,\n  getInvidiousCommunityPostComments,\n  invidiousGetCommentReplies,\n  invidiousGetComments\n} from '../../helpers/api/invidious'\n\nconst { t } = useI18n()\n\nconst props = defineProps({\n  id: {\n    type: String,\n    required: true\n  },\n  channelName: {\n    type: String,\n    required: true\n  },\n  channelThumbnail: {\n    type: String,\n    required: true\n  },\n  videoPlayerReady: {\n    type: Boolean,\n    required: true\n  },\n  isPostComments: {\n    type: Boolean,\n    default: false,\n  },\n  postAuthorId: {\n    type: String,\n    default: null\n  },\n  showSortBy: {\n    type: Boolean,\n    default: true,\n  }\n})\n\nconst isLoading = ref(false)\nconst showComments = ref(false)\nconst nextPageToken = shallowRef(null)\n\n// Has to be ref not shallowRef, as the replies are stored in a property on the comments\n// we need to react to new replies and showReplies being toggled\nconst commentData = ref([])\n\n/** @type {import('youtubei.js').YT.Comments | undefined} */\nlet localCommentsInstance\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => {\n  return store.getters.getBackendFallback\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideCommentLikes = computed(() => {\n  return store.getters.getHideCommentLikes\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideCommentPhotos = computed(() => {\n  return store.getters.getHideCommentPhotos\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst generalAutoLoadMorePaginatedItemsEnabled = computed(() => {\n  return store.getters.getGeneralAutoLoadMorePaginatedItemsEnabled\n})\n\nconst canPerformInitialCommentLoading = computed(() => {\n  return commentData.value.length === 0 && !isLoading.value && !showComments.value\n})\n\nconst canPerformMoreCommentLoading = computed(() => {\n  return commentData.value.length > 0 && !isLoading.value && showComments.value && !!nextPageToken.value\n})\n\nconst observeVisibilityOptions = computed(() => {\n  if (!generalAutoLoadMorePaginatedItemsEnabled.value) {\n    return false\n  }\n  if (!props.videoPlayerReady && !props.isPostComments) { return false }\n\n  return {\n    /**\n     * @param {boolean} isVisible\n     */\n    callback: (isVisible) => {\n      // This is also fired when **hidden**\n      // No point doing anything if not visible\n      if (!isVisible) { return }\n      // It's possible the comments are being loaded/already loaded\n      if (canPerformInitialCommentLoading.value) {\n        getCommentData()\n      } else if (canPerformMoreCommentLoading.value) {\n        getMoreComments()\n      }\n    },\n    intersection: {\n      // Only when it intersects with N% above bottom\n      rootMargin: '0% 0% 0% 0%',\n    },\n    // Callback responsible for loading multiple comment pages\n    once: false,\n  }\n})\n\nconst sortNames = computed(() => [\n  t('Comments.Top comments'),\n  t('Comments.Newest first')\n])\n\nconst sortValues = [\n  'top',\n  'newest'\n]\n\nconst sortNewest = ref(false)\n\nconst currentSortValue = computed(() => sortNewest.value ? 'newest' : 'top')\n\nfunction handleSortChange() {\n  sortNewest.value = !sortNewest.value\n  commentData.value = []\n  nextPageToken.value = null\n  getCommentData()\n}\n\nconst emit = defineEmits(['timestamp-event'])\n\n/**\n * @param {number} timestamp\n */\nfunction onTimestamp(timestamp) {\n  emit('timestamp-event', timestamp)\n}\n\n/** @type {import('vue').ComputedRef<Set<string>>} */\nconst subscribedChannelIds = computed(() => {\n  return store.getters.getActiveProfile.subscriptions.reduce((set, channel) => {\n    return set.add(channel.id)\n  }, new Set())\n})\n\n/**\n * @param {string} channelId\n */\nfunction isSubscribedToChannel(channelId) {\n  return subscribedChannelIds.value.has(channelId)\n}\n\nfunction getCommentData() {\n  isLoading.value = true\n\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    if (!props.isPostComments) {\n      getCommentDataInvidious()\n    } else {\n      getPostCommentsInvidious()\n    }\n  } else {\n    getCommentDataLocal()\n  }\n}\n\nfunction getMoreComments() {\n  if (commentData.value.length === 0 || nextPageToken.value == null) {\n    showToast(t('Comments.There are no more comments for this video'))\n  } else {\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      if (!props.isPostComments) {\n        getCommentDataInvidious()\n      } else {\n        getPostCommentsInvidious()\n      }\n    } else {\n      getCommentDataLocal(true)\n    }\n  }\n}\n\n/** @typedef {import('../../helpers/api/local').LocalComment | import('../../helpers/api/invidious').InvidiousComment} Comment */\n/**\n * @param {Comment} comment\n */\nfunction toggleCommentRepliesLinkText(comment) {\n  if (comment.showReplies) {\n    return t('Comments.Hide {replyCount} replies', { replyCount: comment.numReplies }, comment.numReplies)\n  }\n\n  if (comment.hasOwnerReplied) {\n    if (comment.numReplies > 1) {\n      return t('Comments.View {replyCount} replies from {channelName} and others', { replyCount: comment.numReplies, channelName: props.channelName })\n    }\n\n    return t('Comments.View 1 reply from {channelName}', { channelName: props.channelName })\n  }\n\n  return t('Comments.View {replyCount} replies', { replyCount: comment.numReplies }, comment.numReplies)\n}\n\n/**\n * @param {number} index\n */\nfunction toggleCommentReplies(index) {\n  if (commentData.value[index].showReplies || commentData.value[index].replies.length > 0) {\n    commentData.value[index].showReplies = !commentData.value[index].showReplies\n  } else {\n    getCommentReplies(index)\n  }\n}\n\n/**\n * @param {number} index\n */\nfunction getCommentReplies(index) {\n  if (!process.env.SUPPORTS_LOCAL_API || commentData.value[index].dataType === 'invidious') {\n    if (!props.isPostComments) {\n      getCommentRepliesInvidious(index)\n    } else {\n      getPostCommentRepliesInvidious(index)\n    }\n  } else {\n    getCommentRepliesLocal(index)\n  }\n}\n\n/** @type {Map<string, (import('youtubei.js').YTNodes.CommentThread | string)>} */\nconst replyTokens = new Map()\n\n/**\n * @param {boolean | undefined} more\n */\nasync function getCommentDataLocal(more = false) {\n  try {\n    /** @type {import('youtubei.js').YT.Comments} */\n    let comments\n    if (more) {\n      comments = await nextPageToken.value.getContinuation()\n    } else if (localCommentsInstance) {\n      comments = await localCommentsInstance.applySort(sortNewest.value ? 'NEWEST_FIRST' : 'TOP_COMMENTS')\n      localCommentsInstance = comments\n    } else {\n      if (props.isPostComments) {\n        comments = await getLocalCommunityPostComments(props.id, props.postAuthorId)\n        sortNewest.value = comments.header?.sort_menu?.sub_menu_items?.[1].selected ?? false\n        localCommentsInstance = comments\n      } else {\n        comments = await getLocalComments(props.id)\n        sortNewest.value = comments.header?.sort_menu?.sub_menu_items?.[1].selected ?? false\n        localCommentsInstance = comments\n      }\n    }\n\n    const parsedComments = comments.contents\n      .map(commentThread => {\n        // Use destructuring to create a new object without the replyToken\n        const { replyToken, ...comment } = parseLocalComment(commentThread.comment, commentThread)\n\n        if (comment.hasReplyToken) {\n          replyTokens.set(comment.id, replyToken)\n        } else {\n          replyTokens.delete(comment.id)\n        }\n\n        return comment\n      })\n\n    if (more) {\n      commentData.value = commentData.value.concat(parsedComments)\n    } else {\n      commentData.value = parsedComments\n    }\n\n    nextPageToken.value = comments.has_continuation ? comments : null\n    isLoading.value = false\n    showComments.value = true\n  } catch (err) {\n    // region No comment detection\n    // No comment related info when video info requested earlier in parent component\n    if (err.message.includes('Comments page did not have any content')) {\n      // For videos without any comment (comment disabled?)\n      // e.g. https://youtu.be/8NBSwDEf8a8\n      commentData.value = []\n      nextPageToken.value = null\n      isLoading.value = false\n      showComments.value = true\n      localCommentsInstance = undefined\n      return\n    }\n    // endregion No comment detection\n\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendFallback.value && backendPreference.value === 'local') {\n      localCommentsInstance = undefined\n      showToast(t('Falling back to Invidious API'))\n      if (props.isPostComments) {\n        getPostCommentsInvidious()\n      } else {\n        getCommentDataInvidious()\n      }\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\n/**\n * @param {number} index\n */\nasync function getCommentRepliesLocal(index) {\n  showToast(t('Comments.Getting comment replies, please wait'))\n\n  try {\n    const comment = commentData.value[index]\n    /** @type {import('youtubei.js').YTNodes.CommentThread} */\n    const commentThread = replyTokens.get(comment.id)\n\n    if (commentThread == null) {\n      replyTokens.delete(comment.id)\n      comment.hasReplyToken = false\n      return\n    }\n\n    if (comment.replies.length > 0) {\n      await commentThread.getContinuation()\n      comment.replies = comment.replies.concat(commentThread.replies.map(reply => parseLocalComment(reply)))\n    } else {\n      await commentThread.getReplies()\n      comment.replies = commentThread.replies.map(reply => parseLocalComment(reply))\n    }\n\n    if (commentThread.has_continuation) {\n      replyTokens.set(comment.id, commentThread)\n      comment.hasReplyToken = true\n    } else {\n      replyTokens.delete(comment.id)\n      comment.hasReplyToken = false\n    }\n\n    comment.showReplies = true\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendFallback.value && backendPreference.value === 'local') {\n      showToast(t('Falling back to Invidious API'))\n      getCommentDataInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getCommentDataInvidious() {\n  try {\n    let { response, commentData: comments } = await invidiousGetComments({\n      id: props.id,\n      nextPageToken: nextPageToken.value,\n      sortNewest: sortNewest.value\n    })\n\n    comments = comments.map(({ replyToken, ...comment }) => {\n      if (comment.hasReplyToken) {\n        replyTokens.set(comment.id, replyToken)\n      } else {\n        replyTokens.delete(comment.id)\n      }\n\n      return comment\n    })\n\n    commentData.value = commentData.value.concat(comments)\n    nextPageToken.value = response.continuation\n    isLoading.value = false\n    showComments.value = true\n  } catch (err) {\n    // region No comment detection\n    // No comment related info when video info requested earlier in parent component\n    if (err.message.includes('Comments not found')) {\n      // For videos without any comment (comment disabled?)\n      // e.g. https://youtu.be/8NBSwDEf8a8\n      commentData.value = []\n      nextPageToken.value = null\n      isLoading.value = false\n      showComments.value = true\n      return\n    }\n    // endregion No comment detection\n\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendFallback.value && backendPreference.value === 'invidious') {\n      showToast(t('Falling back to Local API'))\n      getCommentDataLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\n/**\n * @param {number} index\n */\nasync function getCommentRepliesInvidious(index) {\n  showToast(t('Comments.Getting comment replies, please wait'))\n\n  const comment = commentData.value[index]\n  const replyToken = replyTokens.get(comment.id)\n\n  try {\n    const { commentData, continuation } = await invidiousGetCommentReplies({ id: props.id, replyToken })\n\n    comment.replies = comment.replies.concat(commentData)\n    comment.showReplies = true\n\n    if (continuation) {\n      replyTokens.set(comment.id, continuation)\n      comment.hasReplyToken = true\n    } else {\n      replyTokens.delete(comment.id)\n      comment.hasReplyToken = false\n    }\n\n    isLoading.value = false\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    isLoading.value = false\n  }\n}\n\nfunction getPostCommentsInvidious() {\n  const fetchComments = nextPageToken.value == null\n    ? getInvidiousCommunityPostComments({ postId: props.id, authorId: props.postAuthorId })\n    : getInvidiousCommunityPostCommentReplies({ postId: props.id, replyToken: nextPageToken.value, authorId: props.postAuthorId })\n\n  fetchComments.then(({ response, commentData: comments, continuation }) => {\n    comments = comments.map(({ replyToken, ...comment }) => {\n      if (comment.hasReplyToken) {\n        replyTokens.set(comment.id, replyToken)\n      } else {\n        replyTokens.delete(comment.id)\n      }\n\n      return comment\n    })\n\n    commentData.value = commentData.value.concat(comments)\n    nextPageToken.value = response?.continuation ?? continuation\n    isLoading.value = false\n    showComments.value = true\n  }).catch((err) => {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendFallback.value && backendPreference.value === 'invidious') {\n      showToast(t('Falling back to Local API'))\n      getCommentDataLocal()\n    } else {\n      isLoading.value = false\n    }\n  })\n}\n\nasync function getPostCommentRepliesInvidious(index) {\n  showToast(t('Comments.Getting comment replies, please wait'))\n\n  const comment = commentData.value[index]\n  const replyToken = replyTokens.get(comment.id)\n\n  try {\n    const { commentData: comments, continuation } = await getInvidiousCommunityPostCommentReplies({\n      postId: props.id,\n      replyToken: replyToken,\n      authorId: props.postAuthorId\n    })\n    comment.replies = comment.replies.concat(comments)\n    comment.showReplies = true\n\n    if (continuation) {\n      replyTokens.set(comment.id, continuation)\n      comment.hasReplyToken = true\n    } else {\n      replyTokens.delete(comment.id)\n      comment.hasReplyToken = false\n    }\n\n    isLoading.value = false\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    isLoading.value = false\n  }\n}\n</script>\n\n<style scoped src=\"./CommentSection.css\" />\n"
  },
  {
    "path": "src/renderer/components/DataSettings/DataSettings.css",
    "content": ".box {\n  justify-content: center;\n}\n"
  },
  {
    "path": "src/renderer/components/DataSettings/DataSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Data Settings.Data Settings')\"\n  >\n    <h4 class=\"groupTitle\">\n      {{ $t('Subscriptions.Subscriptions') }}\n    </h4>\n    <FtFlexBox class=\"box\">\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Import Subscriptions')\"\n        @click=\"importSubscriptions\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Manage Subscriptions')\"\n        @click=\"openProfileSettings\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Export Subscriptions')\"\n        @click=\"showExportSubscriptionsPrompt = true\"\n      />\n    </FtFlexBox>\n    <FtFlexBox>\n      <p>\n        <a href=\"https://docs.freetubeapp.io/usage/importing-subscriptions/\">\n          {{ $t(\"Settings.Data Settings.How do I import my subscriptions?\") }}\n        </a>\n      </p>\n    </FtFlexBox>\n    <h4 class=\"groupTitle\">\n      {{ $t('History.History') }}\n    </h4>\n    <FtFlexBox class=\"box\">\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Import History')\"\n        @click=\"importWatchHistory\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Export History')\"\n        @click=\"showExportWatchHistoryPrompt = true\"\n      />\n    </FtFlexBox>\n    <h4 class=\"groupTitle\">\n      {{ $t('Playlists') }}\n    </h4>\n    <FtFlexBox class=\"box\">\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Import Playlists')\"\n        @click=\"importPlaylists\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Data Settings.Export Playlists')\"\n        @click=\"exportPlaylists\"\n      />\n    </FtFlexBox>\n    <h4 class=\"groupTitle\">\n      {{ t('Settings.Data Settings.Search history') }}\n    </h4>\n    <FtFlexBox class=\"box\">\n      <FtButton\n        :label=\"t('Settings.Data Settings.Import search history')\"\n        @click=\"importSearchHistory\"\n      />\n      <FtButton\n        :label=\"t('Settings.Data Settings.Export search history')\"\n        @click=\"showExportSearchHistoryPrompt = true\"\n      />\n    </FtFlexBox>\n    <FtPrompt\n      v-if=\"showExportSubscriptionsPrompt\"\n      :label=\"$t('Settings.Data Settings.Select Export Type')\"\n      :option-names=\"exportSubscriptionsPromptNames\"\n      :option-values=\"SUBSCRIPTIONS_PROMPT_VALUES\"\n      @click=\"exportSubscriptions\"\n    />\n    <FtPrompt\n      v-if=\"showExportWatchHistoryPrompt\"\n      :label=\"t('Settings.Data Settings.Select Export Type')\"\n      :option-names=\"exportWatchSearchHistoryPromptNames\"\n      :option-values=\"WATCH_SEARCH_HISTORY_PROMPT_VALUES\"\n      @click=\"exportWatchHistory\"\n    />\n    <FtPrompt\n      v-if=\"showExportSearchHistoryPrompt\"\n      :label=\"t('Settings.Data Settings.Select Export Type')\"\n      :option-names=\"exportWatchSearchHistoryPromptNames\"\n      :option-values=\"WATCH_SEARCH_HISTORY_PROMPT_VALUES\"\n      @click=\"exportSearchHistory\"\n    />\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRouter } from 'vue-router'\n\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\n\nimport store from '../../store/index'\n\nimport { MAIN_PROFILE_ID } from '../../../constants'\nimport { calculateColorLuminance, getRandomColor } from '../../helpers/colors'\nimport {\n  deepCopy,\n  escapeHTML,\n  getTodayDateStrLocalTimezone,\n  readFileWithPicker,\n  showToast,\n  writeFileWithPicker,\n} from '../../helpers/utils'\nimport { processToBeAddedPlaylistVideo } from '../../helpers/playlists'\n\nconst IMPORT_DIRECTORY_ID = 'data-settings-import'\nconst START_IN_DIRECTORY = 'downloads'\n\nconst { t } = useI18n()\nconst router = useRouter()\n\nfunction openProfileSettings() {\n  router.push('/settings/profile')\n}\n\n/**\n * @param {string} fileName\n * @param {string | Blob} content\n * @param {string} fileTypeDescription\n * @param {string} mimeType\n * @param {string} fileExtension\n * @param {string} successMessage\n */\nasync function promptAndWriteToFile(\n  fileName,\n  content,\n  fileTypeDescription,\n  mimeType,\n  fileExtension,\n  successMessage\n) {\n  try {\n    const response = await writeFileWithPicker(\n      fileName,\n      content,\n      fileTypeDescription,\n      mimeType,\n      fileExtension,\n      'data-settings-export',\n      START_IN_DIRECTORY\n    )\n\n    if (response) {\n      showToast(successMessage)\n    }\n  } catch (error) {\n    const message = t('Settings.Data Settings.Unable to write file')\n    showToast(`${message}: ${error}`)\n  }\n}\n\nconst SUBSCRIPTIONS_PROMPT_VALUES = [\n  'freetube',\n  'youtubenew',\n  'youtube',\n  'youtubeold',\n  'newpipe',\n  'close'\n]\n\nconst exportSubscriptionsPromptNames = computed(() => {\n  const exportFreeTube = t('Settings.Data Settings.Export FreeTube')\n  const exportYouTube = t('Settings.Data Settings.Export YouTube')\n  const exportNewPipe = t('Settings.Data Settings.Export NewPipe')\n\n  return [\n    `${exportFreeTube} (.db)`,\n    `${exportYouTube} (.csv)`,\n    `${exportYouTube} (.json)`,\n    `${exportYouTube} (.opml)`,\n    `${exportNewPipe} (.json)`,\n    t('Close')\n  ]\n})\n\nconst profileList = computed(() => store.getters.getProfileList)\nconst primaryProfile = computed(() => deepCopy(profileList.value[0]))\n\n// #region subscriptions import\n\nasync function importSubscriptions() {\n  let response\n  try {\n    response = await readFileWithPicker(\n      t('Settings.Data Settings.Subscription File'),\n      {\n        'application/x-freetube-db': '.db',\n        'text/csv': '.csv',\n        'application/json': '.json',\n        'application/xml': ['.xml', '.opml']\n      },\n      IMPORT_DIRECTORY_ID,\n      START_IN_DIRECTORY\n    )\n  } catch (err) {\n    const message = t('Settings.Data Settings.Unable to read file')\n    showToast(`${message}: ${err}`)\n    return\n  }\n\n  if (response === null) {\n    return\n  }\n\n  const { filename, content } = response\n\n  if (filename.endsWith('.csv')) {\n    importCsvYouTubeSubscriptions(content)\n  } else if (filename.endsWith('.db')) {\n    importFreeTubeSubscriptions(content)\n  } else if (filename.endsWith('.opml') || filename.endsWith('.xml')) {\n    importOpmlYouTubeSubscriptions(content)\n  } else if (filename.endsWith('.json')) {\n    const jsonContent = JSON.parse(content)\n    if (jsonContent.subscriptions) {\n      importNewPipeSubscriptions(jsonContent)\n    } else {\n      importYouTubeSubscriptions(jsonContent)\n    }\n  }\n}\n\n/**\n * @param {string | null} channelId\n * @param {{ id: string, name: string, thumbnail: string | null }[]} subscriptions\n */\nfunction isChannelSubscribed(channelId, subscriptions) {\n  if (channelId === null) { return true }\n\n  const subExists = primaryProfile.value.subscriptions.some((sub) => {\n    return sub.id === channelId\n  })\n\n  const subDuplicateExists = subscriptions.some((sub) => {\n    return sub.id === channelId\n  })\n\n  return subExists || subDuplicateExists\n}\n\n/**\n * @param {any[]} oldData\n */\nfunction convertOldFreeTubeFormatToNew(oldData) {\n  const convertedData = []\n  for (const channel of oldData) {\n    const listOfProfilesAlreadyAdded = []\n    for (const profile of channel.profile) {\n      let index = convertedData.findIndex(p => p.name === profile.value)\n      if (index === -1) { // profile doesn't exist yet\n        const randomBgColor = getRandomColor().value\n        const contrastyTextColor = calculateColorLuminance(randomBgColor)\n        convertedData.push({\n          name: profile.value,\n          bgColor: randomBgColor,\n          textColor: contrastyTextColor,\n          subscriptions: [],\n          _id: channel._id\n        })\n        index = convertedData.length - 1\n      } else if (listOfProfilesAlreadyAdded.includes(index)) {\n        continue\n      }\n      listOfProfilesAlreadyAdded.push(index)\n      convertedData[index].subscriptions.push({\n        id: channel.channelId,\n        name: channel.channelName,\n        thumbnail: channel.channelThumbnail\n      })\n    }\n  }\n  return convertedData\n}\n\n/**\n * @param {string} textDecode\n */\nfunction importFreeTubeSubscriptions(textDecode) {\n  textDecode = textDecode.split('\\n')\n  textDecode.pop()\n  textDecode = textDecode.map(data => JSON.parse(data))\n\n  const firstEntry = textDecode[0]\n  if (firstEntry.channelId && firstEntry.channelName && firstEntry.channelThumbnail && firstEntry._id && firstEntry.profile) {\n    // Old FreeTube subscriptions format detected, so convert it to the new one:\n    textDecode = convertOldFreeTubeFormatToNew(textDecode)\n  }\n\n  const requiredKeys = [\n    '_id',\n    'name',\n    'bgColor',\n    'textColor',\n    'subscriptions'\n  ]\n\n  textDecode.forEach((profileData) => {\n    // We would technically already be done by the time the data is parsed,\n    // however we want to limit the possibility of malicious data being sent\n    // to the app, so we'll only grab the data we need here.\n\n    const profileObject = {}\n    Object.keys(profileData).forEach((key) => {\n      if (!requiredKeys.includes(key)) {\n        const message = t('Settings.Data Settings.Unknown data key')\n        showToast(`${message}: ${key}`)\n      } else {\n        profileObject[key] = profileData[key]\n      }\n    })\n\n    if (Object.keys(profileObject).length < requiredKeys.length) {\n      const message = t('Settings.Data Settings.Profile object has insufficient data, skipping item')\n      showToast(message)\n    } else {\n      if (profileObject._id === MAIN_PROFILE_ID) {\n        primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(profileObject.subscriptions)\n        primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.filter((sub, index) => {\n          const profileIndex = primaryProfile.value.subscriptions.findIndex((x) => {\n            return x.id === sub.id\n          })\n\n          return profileIndex === index\n        })\n        store.dispatch('updateProfile', primaryProfile.value)\n      } else {\n        const existingProfileIndex = profileList.value.findIndex((profile) => {\n          return profile.name.includes(profileObject.name)\n        })\n\n        if (existingProfileIndex !== -1) {\n          const existingProfile = deepCopy(profileList.value[existingProfileIndex])\n          existingProfile.subscriptions = existingProfile.subscriptions.concat(profileObject.subscriptions)\n          existingProfile.subscriptions = existingProfile.subscriptions.filter((sub, index) => {\n            const profileIndex = existingProfile.subscriptions.findIndex((x) => {\n              return x.id === sub.id\n            })\n\n            return profileIndex === index\n          })\n          store.dispatch('updateProfile', existingProfile)\n        } else {\n          store.dispatch('updateProfile', profileObject)\n        }\n\n        primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(profileObject.subscriptions)\n        primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.filter((sub, index) => {\n          const profileIndex = primaryProfile.value.subscriptions.findIndex((x) => {\n            return x.id === sub.id\n          })\n\n          return profileIndex === index\n        })\n        store.dispatch('updateProfile', primaryProfile.value)\n      }\n    }\n  })\n\n  showToast(t('Settings.Data Settings.All subscriptions and profiles have been successfully imported'))\n}\n\n/**\n * @param {string} textDecode\n */\nfunction importCsvYouTubeSubscriptions(textDecode) { // first row = header, last row = empty\n  const youtubeSubscriptions = textDecode.split('\\n').filter(sub => {\n    return sub !== ''\n  })\n  const subscriptions = []\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n\n  const splitCSVRegex = /(?:,|\\n|^)(\"(?:(?:\"\")|[^\"])*\"|[^\\n\",]*|(?:\\n|$))/g\n\n  const ytsubs = youtubeSubscriptions.slice(1).map(yt => {\n    return [...yt.matchAll(splitCSVRegex)].map(s => {\n      let newVal = s[1]\n      if (newVal.startsWith('\"')) {\n        newVal = newVal.substring(1, newVal.length - 1).replaceAll('\"\"', '\"')\n      }\n      return newVal\n    })\n  }).filter(channel => {\n    return channel.length > 0\n  })\n\n  ytsubs.forEach((yt) => {\n    const channelId = yt[0]\n    if (!isChannelSubscribed(channelId, subscriptions)) {\n      const subscription = {\n        id: channelId,\n        name: yt[2],\n        thumbnail: null\n      }\n\n      subscriptions.push(subscription)\n    }\n  })\n\n  primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(subscriptions)\n  store.dispatch('updateProfile', primaryProfile.value)\n  showToast(t('Settings.Data Settings.All subscriptions have been successfully imported'))\n  store.commit('setShowProgressBar', false)\n}\n\n/**\n * @param {object} textDecode\n */\nfunction importYouTubeSubscriptions(textDecode) {\n  const subscriptions = []\n  let count = 0\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n\n  textDecode.forEach((channel) => {\n    const snippet = channel.snippet\n    if (typeof snippet === 'undefined') {\n      const message = t('Settings.Data Settings.Invalid subscriptions file')\n      showToast(message)\n      throw new Error('Unable to find channel data')\n    }\n\n    const channelId = snippet.resourceId.channelId\n    if (!isChannelSubscribed(channelId, subscriptions)) {\n      subscriptions.push({\n        id: channelId,\n        name: snippet.title,\n        thumbnail: snippet.thumbnails.default.url\n      })\n    }\n\n    count++\n\n    const progressPercentage = (count / (textDecode.length - 1)) * 100\n    store.commit('setProgressBarPercentage', progressPercentage)\n  })\n\n  primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(subscriptions)\n  store.dispatch('updateProfile', primaryProfile.value)\n  showToast(t('Settings.Data Settings.All subscriptions have been successfully imported'))\n  store.commit('setShowProgressBar', false)\n}\n\n/**\n * @param {string} data\n */\nfunction importOpmlYouTubeSubscriptions(data) {\n  let xmlDom\n  const domParser = new DOMParser()\n  try {\n    xmlDom = domParser.parseFromString(data, 'application/xml')\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#error_handling\n    const errorNode = xmlDom.querySelector('parsererror')\n    if (errorNode) {\n      throw errorNode.textContent\n    }\n  } catch (err) {\n    console.error('error reading OPML subscriptions file, falling back to HTML parser...')\n    console.error(err)\n    // try parsing with the html parser instead which is more lenient\n    try {\n      const htmlDom = domParser.parseFromString(data, 'text/html')\n\n      xmlDom = htmlDom\n    } catch {\n      const message = t('Settings.Data Settings.Invalid subscriptions file')\n      showToast(`${message}: ${err}`)\n      return\n    }\n  }\n\n  const feedData = xmlDom.querySelectorAll('body outline[xmlUrl]')\n  if (feedData.length === 0) {\n    const message = t('Settings.Data Settings.Invalid subscriptions file')\n    showToast(message)\n    return\n  }\n\n  const subscriptions = []\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n\n  let count = 0\n\n  feedData.forEach((channel) => {\n    const xmlUrl = channel.getAttribute('xmlUrl')\n    const channelName = channel.getAttribute('title')\n    let channelId\n    if (xmlUrl.includes('https://www.youtube.com/feeds/videos.xml?channel_id=')) {\n      channelId = new URL(xmlUrl).searchParams.get('channel_id')\n    } else if (xmlUrl.includes('/feed/channel/')) {\n      // handle invidious exports https://yewtu.be/feed/channel/{CHANNELID}\n      channelId = new URL(xmlUrl).pathname.split('/').filter(part => part).at(-1)\n    } else {\n      console.error(`Unknown xmlUrl format: ${xmlUrl}`)\n    }\n\n    if (!isChannelSubscribed(channelId, subscriptions)) {\n      const subscription = {\n        id: channelId,\n        name: channelName,\n        thumbnail: null\n      }\n      subscriptions.push(subscription)\n    }\n\n    count++\n\n    const progressPercentage = (count / feedData.length) * 100\n    store.commit('setProgressBarPercentage', progressPercentage)\n  })\n\n  primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(subscriptions)\n  store.dispatch('updateProfile', primaryProfile.value)\n  showToast(t('Settings.Data Settings.All subscriptions have been successfully imported'))\n  store.commit('setShowProgressBar', false)\n}\n\n/**\n * @param {object} newPipeData\n */\nfunction importNewPipeSubscriptions(newPipeData) {\n  if (typeof newPipeData.subscriptions === 'undefined') {\n    showToast(t('Settings.Data Settings.Invalid subscriptions file'))\n\n    return\n  }\n\n  const newPipeSubscriptions = newPipeData.subscriptions.filter((channel) => {\n    return new URL(channel.url).hostname === 'www.youtube.com'\n  })\n\n  const subscriptions = []\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n\n  let count = 0\n\n  newPipeSubscriptions.forEach((channel) => {\n    const channelId = channel.url.replace(/https:\\/\\/(www\\.)?youtube\\.com\\/channel\\//, '')\n\n    if (!isChannelSubscribed(channelId, subscriptions)) {\n      subscriptions.push({\n        id: channelId,\n        name: channel.name,\n        thumbnail: null\n      })\n    }\n    count++\n\n    const progressPercentage = (count / (newPipeSubscriptions.length - 1)) * 100\n    store.commit('setProgressBarPercentage', progressPercentage)\n  })\n\n  primaryProfile.value.subscriptions = primaryProfile.value.subscriptions.concat(subscriptions)\n  store.dispatch('updateProfile', primaryProfile.value)\n  showToast(t('Settings.Data Settings.All subscriptions have been successfully imported'))\n  store.commit('updateShowProgressBar', false)\n}\n\n// #endregion subscriptions import\n\n// #region subscriptions export\n\nconst showExportSubscriptionsPrompt = ref(false)\n\n/**\n * @param {'freetube' | 'youtubenew' | 'youtube' | 'youtubeold' | 'newpipe' | 'close' | null} option\n */\nfunction exportSubscriptions(option) {\n  showExportSubscriptionsPrompt.value = false\n\n  if (option === null) {\n    return\n  }\n\n  switch (option) {\n    case 'freetube':\n      exportFreeTubeSubscriptions()\n      break\n    case 'youtubenew':\n      exportCsvYouTubeSubscriptions()\n      break\n    case 'youtube':\n      exportYouTubeSubscriptions()\n      break\n    case 'youtubeold':\n      exportOpmlYouTubeSubscriptions()\n      break\n    case 'newpipe':\n      exportNewPipeSubscriptions()\n      break\n  }\n}\n\nasync function exportFreeTubeSubscriptions() {\n  const subscriptionsDb = profileList.value.map((profile) => {\n    return JSON.stringify(profile)\n  }).join('\\n') + '\\n'// a trailing line is expected\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'freetube-subscriptions-' + dateStr + '.db'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    subscriptionsDb,\n    t('Settings.Data Settings.Subscription File'),\n    'application/x-freetube-db',\n    '.db',\n    t('Settings.Data Settings.Subscriptions have been successfully exported')\n  )\n}\n\nasync function exportYouTubeSubscriptions() {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'youtube-subscriptions-' + dateStr + '.json'\n\n  const subscriptionsObject = profileList.value[0].subscriptions.map((channel) => {\n    const object = {\n      contentDetails: {\n        activityType: 'all',\n        newItemCount: 0,\n        totalItemCount: 0\n      },\n      etag: '',\n      id: '',\n      kind: 'youtube#subscription',\n      snippet: {\n        channelId: channel.id,\n        description: '',\n        publishedAt: new Date(),\n        resourceId: {\n          channelId: channel.id,\n          kind: 'youtube#channel'\n        },\n        thumbnails: {\n          default: {\n            url: channel.thumbnail\n          },\n          high: {\n            url: channel.thumbnail\n          },\n          medium: {\n            url: channel.thumbnail\n          }\n        },\n        title: channel.name\n      }\n    }\n\n    return object\n  })\n\n  await promptAndWriteToFile(\n    exportFileName,\n    JSON.stringify(subscriptionsObject),\n    t('Settings.Data Settings.Subscription File'),\n    'application/json',\n    '.json',\n    t('Settings.Data Settings.Subscriptions have been successfully exported')\n  )\n}\n\nasync function exportOpmlYouTubeSubscriptions() {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'youtube-subscriptions-' + dateStr + '.opml'\n\n  let opmlData = '<opml version=\"1.1\"><body><outline text=\"YouTube Subscriptions\" title=\"YouTube Subscriptions\">'\n\n  profileList.value[0].subscriptions.forEach((channel) => {\n    const escapedName = escapeHTML(channel.name)\n\n    const channelOpmlString = `<outline text=\"${escapedName}\" title=\"${escapedName}\" type=\"rss\" xmlUrl=\"https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}\"/>`\n    opmlData += channelOpmlString\n  })\n\n  opmlData += '</outline></body></opml>'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    opmlData,\n    t('Settings.Data Settings.Subscription File'),\n    'application/xml',\n    '.opml',\n    t('Settings.Data Settings.Subscriptions have been successfully exported')\n  )\n}\n\nasync function exportCsvYouTubeSubscriptions() {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'youtube-subscriptions-' + dateStr + '.csv'\n\n  let exportText = 'Channel ID,Channel URL,Channel title\\n'\n  profileList.value[0].subscriptions.forEach((channel) => {\n    const channelUrl = `https://www.youtube.com/channel/${channel.id}`\n\n    // always have channel name quoted to simplify things\n    const channelName = `\"${channel.name.replaceAll('\"', '\"\"')}\"`\n    exportText += `${channel.id},${channelUrl},${channelName}\\n`\n  })\n  exportText += '\\n'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    exportText,\n    t('Settings.Data Settings.Subscription File'),\n    'text/csv',\n    '.csv',\n    t('Settings.Data Settings.Subscriptions have been successfully exported')\n  )\n}\n\nasync function exportNewPipeSubscriptions() {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'newpipe-subscriptions-' + dateStr + '.json'\n\n  const newPipeObject = {\n    app_version: '0.19.8',\n    app_version_int: 953,\n    subscriptions: []\n  }\n\n  profileList.value[0].subscriptions.forEach((channel) => {\n    const channelUrl = `https://www.youtube.com/channel/${channel.id}`\n    const subscription = {\n      service_id: 0,\n      url: channelUrl,\n      name: channel.name\n    }\n\n    newPipeObject.subscriptions.push(subscription)\n  })\n\n  await promptAndWriteToFile(\n    exportFileName,\n    JSON.stringify(newPipeObject),\n    t('Settings.Data Settings.Subscription File'),\n    'application/json',\n    '.json',\n    t('Settings.Data Settings.Subscriptions have been successfully exported')\n  )\n}\n\n// #endregion subscriptions export\n\nconst WATCH_SEARCH_HISTORY_PROMPT_VALUES = [\n  'freetube',\n  'youtube'\n]\n\nconst exportWatchSearchHistoryPromptNames = computed(() => [\n  `${t('Settings.Data Settings.Export FreeTube')} (.db)`,\n  `${t('Settings.Data Settings.Export YouTube')} (.json)`,\n  t('Close')\n])\n\n// #region watch history\n\nconst historyCacheById = computed(() => {\n  return store.getters.getHistoryCacheById\n})\n\nconst historyCacheSorted = computed(() => {\n  return store.getters.getHistoryCacheSorted\n})\n\nasync function importWatchHistory() {\n  let response\n  try {\n    response = await readFileWithPicker(\n      t('Settings.Data Settings.History File'),\n      {\n        'application/x-freetube-db': '.db',\n        'application/json': '.json'\n      },\n      IMPORT_DIRECTORY_ID,\n      START_IN_DIRECTORY\n    )\n  } catch (err) {\n    const message = t('Settings.Data Settings.Unable to read file')\n    showToast(`${message}: ${err}`)\n    return\n  }\n\n  if (response === null) {\n    return\n  }\n\n  const { filename, content } = response\n\n  if (filename.endsWith('.db')) {\n    importFreeTubeWatchHistory(content.split('\\n'))\n  } else if (filename.endsWith('.json')) {\n    importYouTubeWatchHistory(JSON.parse(content))\n  }\n}\n\n/**\n * @param {string[]} textDecode\n */\nasync function importFreeTubeWatchHistory(textDecode) {\n  textDecode.pop()\n\n  const requiredKeys = [\n    'author',\n    'authorId',\n    'description',\n    'isLive',\n    'lengthSeconds',\n    'published',\n    'timeWatched',\n    'title',\n    'type',\n    'videoId',\n    'watchProgress',\n  ]\n\n  const optionalKeys = [\n    // `_id` absent if marked as watched manually\n    '_id',\n    'lastViewedPlaylistId',\n    'lastViewedPlaylistItemId',\n    'lastViewedPlaylistType',\n    'viewCount',\n  ]\n\n  const ignoredKeys = [\n    'paid',\n  ]\n\n  // deep copy so we don't get errors from Electron when we try to pass reactive objects through the IPC channels\n  const historyItems = new Map(deepCopy(Object.entries(historyCacheById.value)))\n\n  textDecode.forEach((history) => {\n    const historyData = JSON.parse(history)\n    // We would technically already be done by the time the data is parsed,\n    // however we want to limit the possibility of malicious data being sent\n    // to the app, so we'll only grab the data we need here.\n\n    const historyObject = {}\n\n    Object.keys(historyData).forEach((key) => {\n      if (requiredKeys.includes(key) || optionalKeys.includes(key)) {\n        historyObject[key] = historyData[key]\n      } else if (!ignoredKeys.includes(key)) {\n        showToast(`Unknown data key: ${key}`)\n      }\n      // Else do not import the key\n    })\n\n    const historyObjectKeysSet = new Set(Object.keys(historyObject))\n    const missingKeys = requiredKeys.filter(x => !historyObjectKeysSet.has(x))\n    if (missingKeys.length > 0) {\n      showToast(t('Settings.Data Settings.History object has insufficient data, skipping item'))\n      console.error('Missing Keys: ', missingKeys, historyData)\n    } else {\n      historyItems.set(historyObject.videoId, historyObject)\n    }\n  })\n\n  await store.dispatch('overwriteHistory', historyItems)\n\n  showToast(t('Settings.Data Settings.All watched history has been successfully imported'))\n}\n\n/**\n * @param {any[]} historyData\n */\nasync function importYouTubeWatchHistory(historyData) {\n  const filterPredicate = item =>\n    item.products.includes('YouTube') &&\n    item.titleUrl != null && // removed video doesnt contain url...\n    item.titleUrl.includes('www.youtube.com/watch?v') &&\n    item.details == null // dont import ads\n\n  const filteredHistoryData = historyData.filter(filterPredicate)\n\n  // remove 'Watched' and translated variants from start of title\n  // so we get the common string prefix for all the titles\n  const getCommonStart = (allTitles) => {\n    const watchedTitle = allTitles[0].split(' ')\n    allTitles.forEach((title) => {\n      const splitTitle = title.split(' ')\n      for (let wtIndex = 0; wtIndex <= watchedTitle.length; wtIndex++) {\n        if (!splitTitle.includes(watchedTitle[wtIndex])) {\n          watchedTitle.splice(wtIndex, watchedTitle.length - wtIndex)\n        }\n      }\n    })\n\n    return watchedTitle.join(' ')\n  }\n\n  const commonStart = getCommonStart(filteredHistoryData.map(e => e.title))\n  // We would technically already be done by the time the data is parsed,\n  // however we want to limit the possibility of malicious data being sent\n  // to the app, so we'll only grab the data we need here.\n\n  const keyMapping = {\n    title: [{ importKey: 'title', predicate: item => item.slice(commonStart.length) }], // Removes the \"Watched \" term on the title\n    titleUrl: [{ importKey: 'videoId', predicate: item => item.replaceAll(/https:\\/\\/www\\.youtube\\.com\\/watch\\?v=/gi, '') }], // Extracts the video ID\n    time: [{ importKey: 'timeWatched', predicate: item => new Date(item).valueOf() }],\n    subtitles: [\n      { importKey: 'author', predicate: item => item[0].name ?? '' },\n      { importKey: 'authorId', predicate: item => item[0].url?.replaceAll(/https:\\/\\/www\\.youtube\\.com\\/channel\\//gi, '') ?? '' },\n    ],\n  }\n\n  const knownKeys = [\n    'header',\n    'description',\n    'products',\n    'details',\n    'activityControls',\n  ].concat(Object.keys(keyMapping))\n\n  // deep copy so we don't get errors from Electron when we try to pass reactive objects through the IPC channels\n  const historyItems = new Map(deepCopy(Object.entries(historyCacheById.value)))\n\n  filteredHistoryData.forEach(element => {\n    const historyObject = {}\n\n    Object.keys(element).forEach((key) => {\n      if (!knownKeys.includes(key)) {\n        showToast(`Unknown data key: ${key}`)\n      } else {\n        const mapping = keyMapping[key]\n\n        if (mapping && Array.isArray(mapping)) {\n          mapping.forEach(item => {\n            historyObject[item.importKey] = item.predicate(element[key])\n          })\n        }\n      }\n    })\n\n    if (Object.keys(historyObject).length < keyMapping.length - 1) {\n      showToast(t('Settings.Data Settings.History object has insufficient data, skipping item'))\n    } else {\n      // YouTube history export does not have this data, setting some defaults.\n      historyObject.type = 'video'\n      historyObject.published = historyObject.timeWatched ?? 1\n      historyObject.description = ''\n      historyObject.lengthSeconds = null\n      historyObject.watchProgress = 1\n      historyObject.isLive = false\n\n      historyItems.set(historyObject.videoId, historyObject)\n    }\n  })\n\n  await store.dispatch('overwriteHistory', historyItems)\n\n  showToast(t('Settings.Data Settings.All watched history has been successfully imported'))\n}\n\nconst showExportWatchHistoryPrompt = ref(false)\n\n/**\n * @param {'freetube' | 'youtube' | null} option\n */\nasync function exportWatchHistory(option) {\n  showExportWatchHistoryPrompt.value = false\n\n  switch (option) {\n    case 'freetube':\n      exportFreeTubeWatchHistory()\n      break\n    case 'youtube':\n      exportYouTubeWatchHistory()\n      break\n  }\n}\n\nasync function exportFreeTubeWatchHistory() {\n  const historyDb = historyCacheSorted.value.map((historyEntry) => {\n    return JSON.stringify(historyEntry)\n  }).join('\\n') + '\\n'\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'freetube-watch-history-' + dateStr + '.db'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    historyDb,\n    t('Settings.Data Settings.History File'),\n    'application/x-freetube-db',\n    '.db',\n    t('Settings.Data Settings.All watched history has been successfully exported')\n  )\n}\n\nasync function exportYouTubeWatchHistory() {\n  const historyData = historyCacheSorted.value.map((entry) => {\n    return {\n      header: 'YouTube',\n      title: `Watched ${entry.title}`,\n      titleUrl: `https://www.youtube.com/watch?v=${entry.videoId}`,\n      subtitles: [{\n        name: entry.author,\n        url: `https://www.youtube.com/channel/${entry.authorId}`\n      }],\n      time: new Date(entry.timeWatched).toISOString(),\n      products: [\n        'YouTube'\n      ],\n      activityControls: [\n        'YouTube watch history'\n      ]\n    }\n  })\n\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'youtube-watch-history-' + dateStr + '.json'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    JSON.stringify(historyData),\n    t('Settings.Data Settings.History File'),\n    'application/json',\n    '.json',\n    t('Settings.Data Settings.All watched history has been successfully exported')\n  )\n}\n\n// #endregion watch history\n\n// #region playlists\n\nconst allPlaylists = computed(() => store.getters.getAllPlaylists)\n\nasync function importPlaylists() {\n  let response\n  try {\n    response = await readFileWithPicker(\n      t('Settings.Data Settings.Playlist File'),\n      {\n        'application/x-freetube-db': '.db'\n      },\n      IMPORT_DIRECTORY_ID,\n      START_IN_DIRECTORY\n    )\n  } catch (err) {\n    const message = t('Settings.Data Settings.Unable to read file')\n    showToast(`${message}: ${err}`)\n    return\n  }\n\n  if (response === null) {\n    return\n  }\n\n  let data = response.content\n\n  let playlists\n\n  // for the sake of backwards compatibility,\n  // check if this is the old JSON array export (used until version 0.19.1),\n  // that didn't match the actual database format\n  const trimmedData = data.trim()\n\n  if (trimmedData[0] === '[' && trimmedData[trimmedData.length - 1] === ']') {\n    playlists = JSON.parse(trimmedData)\n  } else {\n    // otherwise assume this is the correct database format,\n    // which is also what we export now (used in 0.20.0 and later versions)\n    data = data.split('\\n')\n    data.pop()\n\n    playlists = data.map(playlistJson => JSON.parse(playlistJson))\n  }\n\n  const requiredKeys = [\n    'playlistName',\n    'videos',\n  ]\n\n  const optionalKeys = [\n    '_id',\n    'description',\n    'createdAt',\n  ]\n\n  const ignoredKeys = [\n    'title',\n    'type',\n    'protected',\n    'lastUpdatedAt',\n    'lastPlayedAt',\n    'removeOnWatched',\n\n    'thumbnail',\n    'channelName',\n    'channelId',\n    'playlistId',\n    'videoCount',\n  ]\n\n  const knownKeys = [...requiredKeys, ...optionalKeys, ...ignoredKeys]\n\n  const requiredVideoKeys = [\n    'videoId',\n    'title',\n    'lengthSeconds',\n    'timeAdded',\n\n    // These two properties will be missing for shorts added to a playlist from anywhere but the watch page\n    // 'author',\n    // 'authorId',\n\n    // `playlistItemId` should be optional for backward compatibility\n    // 'playlistItemId',\n  ]\n\n  const newPlaylists = []\n\n  playlists.forEach((playlistData) => {\n    // We would technically already be done by the time the data is parsed,\n    // however we want to limit the possibility of malicious data being sent\n    // to the app, so we'll only grab the data we need here.\n\n    const playlistObject = {}\n    const videoIdToBeAddedSet = new Set()\n    let countRequiredKeysPresent = 0\n\n    Object.keys(playlistData).forEach((key) => {\n      if (!knownKeys.includes(key)) {\n        const message = `${t('Settings.Data Settings.Unknown data key')}: ${key}`\n        showToast(message)\n      } else if (key === 'videos') {\n        const videoArray = []\n        playlistData.videos.forEach((video) => {\n          const videoPropertyKeys = Object.keys(video)\n          const videoObjectHasAllRequiredKeys = requiredVideoKeys.every((k) => videoPropertyKeys.includes(k))\n\n          if (videoObjectHasAllRequiredKeys) {\n            videoArray.push(video)\n            videoIdToBeAddedSet.add(video.videoId)\n          }\n        })\n\n        playlistObject.videos = videoArray\n\n        if (requiredKeys.includes(key)) {\n          countRequiredKeysPresent++\n        }\n      } else if (!ignoredKeys.includes(key)) {\n        // Do nothing for keys to be ignored\n        playlistObject[key] = playlistData[key]\n\n        if (requiredKeys.includes(key)) {\n          countRequiredKeysPresent++\n        }\n      }\n    })\n\n    if (countRequiredKeysPresent !== requiredKeys.length) {\n      const message = t('Settings.Data Settings.Playlist insufficient data', { playlist: playlistData.playlistName })\n      showToast(message)\n      return\n    }\n\n    const existingPlaylist = allPlaylists.value.find((playlist) => {\n      if (playlistObject._id != null && playlist._id === playlistObject._id) {\n        return true\n      }\n\n      return playlist.playlistName === playlistObject.playlistName\n    })\n\n    if (existingPlaylist === undefined) {\n      newPlaylists.push(playlistObject)\n      return\n    }\n\n    /** @type {Set<string> | undefined} */\n    let existingVideoIdSet\n\n    let shouldAddDuplicateVideos = playlistObject.videos.length > videoIdToBeAddedSet.size\n\n    if (!shouldAddDuplicateVideos) {\n      existingVideoIdSet = existingPlaylist.videos.reduce((set, video) => set.add(video.videoId), new Set())\n      shouldAddDuplicateVideos = existingPlaylist.videos.length > existingVideoIdSet.size\n    }\n\n    const playlistVideos = [...existingPlaylist.videos]\n\n    playlistObject.videos.forEach((video) => {\n      let videoExists = false\n      if (shouldAddDuplicateVideos) {\n        if (video.playlistItemId != null) {\n          // Find by `playlistItemId` if present\n          videoExists = playlistVideos.some((x) => {\n            // Allow duplicate (by videoId) videos to be added\n            return x.videoId === video.videoId && x.playlistItemId === video.playlistItemId\n          })\n        } else {\n          // Older playlist exports have no `playlistItemId` but have `timeAdded`\n          // Which might be duplicate for copied playlists with duplicate `videoId`\n          videoExists = playlistVideos.some((x) => {\n            // Allow duplicate (by videoId) videos to be added\n            return x.videoId === video.videoId && x.timeAdded === video.timeAdded\n          })\n        }\n      } else if (existingVideoIdSet !== undefined) {\n        // Disallow duplicate (by videoId) videos to be added\n\n        if (existingVideoIdSet.has(video.videoId)) {\n          videoExists = true\n        } else {\n          existingVideoIdSet.add(video.videoId)\n        }\n      } else {\n        videoExists = playlistVideos.some((x) => {\n          // Disallow duplicate (by videoId) videos to be added\n          return x.videoId === video.videoId\n        })\n      }\n\n      if (!videoExists) {\n        // Keep original `timeAdded` value\n        processToBeAddedPlaylistVideo(video)\n        playlistVideos.push(video)\n      }\n    })\n    // Update playlist's `lastUpdatedAt` & other attributes\n    store.dispatch('updatePlaylist', {\n      _id: existingPlaylist._id,\n      // Only these attributes would be updated (besides videos)\n      playlistName: playlistObject.playlistName,\n      description: playlistObject.description,\n      videos: playlistVideos\n    })\n  })\n\n  if (newPlaylists.length > 0) {\n    store.dispatch('addPlaylists', newPlaylists)\n  }\n\n  showToast(t('Settings.Data Settings.All playlists has been successfully imported'))\n}\n\nasync function exportPlaylists() {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'freetube-playlists-' + dateStr + '.db'\n\n  const playlistsDb = allPlaylists.value.map(playlist => {\n    return JSON.stringify(playlist)\n  }).join('\\n') + '\\n'// a trailing line is expected\n\n  await promptAndWriteToFile(\n    exportFileName,\n    playlistsDb,\n    t('Settings.Data Settings.Playlist File'),\n    'application/x-freetube-db',\n    '.db',\n    t('Settings.Data Settings.All playlists has been successfully exported')\n  )\n}\n\n// #endregion playlists\n\n// #region search history\n\n/** @type {import('vue').ComputedRef<{ _id: string, lastUpdatedAt: number }[]>} */\nconst searchHistoryEntries = computed(() => {\n  return store.getters.getSearchHistoryEntries\n})\n\nasync function importSearchHistory() {\n  let response\n  try {\n    response = await readFileWithPicker(\n      t('Settings.Data Settings.Search history file'),\n      {\n        'application/x-freetube-db': '.db',\n        'application/json': '.json'\n      },\n      IMPORT_DIRECTORY_ID,\n      START_IN_DIRECTORY\n    )\n  } catch (err) {\n    const message = t('Settings.Data Settings.Unable to read file')\n    showToast(`${message}: ${err}`)\n    return\n  }\n\n  if (response === null) {\n    return\n  }\n\n  const { filename, content } = response\n\n  if (filename.endsWith('.db')) {\n    importFreeTubeSearchHistory(content.split('\\n'))\n  } else if (filename.endsWith('.json')) {\n    importYouTubeSearchHistory(JSON.parse(content))\n  }\n}\n\n/**\n * @param {string[]} textDecode\n */\nasync function importFreeTubeSearchHistory(textDecode) {\n  textDecode.pop()\n\n  // deep copy so we don't get errors from Electron when we try to pass reactive objects through the IPC channels\n  const historyItems = new Map(deepCopy(searchHistoryEntries.value).map(entry => [entry._id, entry]))\n\n  textDecode.forEach((rawEntry) => {\n    const entry = JSON.parse(rawEntry)\n\n    if (typeof entry._id !== 'string' || typeof entry.lastUpdatedAt !== 'number') {\n      showToast(t('Settings.Data Settings.History object has insufficient data, skipping item'))\n      console.error('Missing keys:', entry)\n    } else {\n      const existingEntry = historyItems.get(entry._id)\n\n      if (existingEntry == null || entry.lastUpdatedAt > existingEntry.lastUpdatedAt) {\n        let newEntry\n\n        if (Object.keys(entry) === 2) {\n          newEntry = entry\n        } else {\n          newEntry = { _id: entry._id, lastUpdatedAt: entry.lastUpdatedAt }\n        }\n\n        historyItems.set(entry._id, newEntry)\n      }\n    }\n  })\n\n  const newSearchHistoryEntries = Array.from(historyItems.values())\n\n  await store.dispatch('overwriteSearchHistory', newSearchHistoryEntries)\n\n  showToast(t('Settings.Data Settings.All search history has been successfully imported'))\n}\n\n/**\n * @param {any[]} historyData\n */\nasync function importYouTubeSearchHistory(historyData) {\n  // deep copy so we don't get errors from Electron when we try to pass reactive objects through the IPC channels\n  const historyItems = new Map(deepCopy(searchHistoryEntries.value).map(entry => [entry._id, entry]))\n\n  for (const entry of historyData) {\n    if (\n      entry.products?.includes('YouTube') &&\n      entry.titleUrl?.includes('youtube.com/results?search_query') &&\n      entry.details == null // dont import ads\n    ) {\n      try {\n        const url = new URL(entry.titleUrl)\n        const query = url.searchParams.get('search_query')\n\n        const lastUpdatedAt = Date.parse(entry.time)\n\n        if (!query || typeof query !== 'string' || query.length === 0 || isNaN(lastUpdatedAt)) {\n          showToast(t('Settings.Data Settings.History object has insufficient data, skipping item'))\n          console.error('Missing keys:', entry)\n        } else {\n          const existingEntry = historyItems.get(query)\n\n          if (existingEntry == null || lastUpdatedAt > existingEntry.lastUpdatedAt) {\n            historyItems.set(query, { _id: query, lastUpdatedAt })\n          }\n        }\n      } catch (error) {\n        console.error(error)\n        showToast(t('Settings.Data Settings.History object has insufficient data, skipping item'))\n      }\n    }\n  }\n\n  const newSearchHistoryEntries = Array.from(historyItems.values())\n\n  await store.dispatch('overwriteSearchHistory', newSearchHistoryEntries)\n\n  showToast(t('Settings.Data Settings.All search history has been successfully imported'))\n}\n\nconst showExportSearchHistoryPrompt = ref(false)\n\n/**\n * @param {'freetube' | 'youtube' | null} option\n */\nasync function exportSearchHistory(option) {\n  showExportSearchHistoryPrompt.value = false\n\n  switch (option) {\n    case 'freetube':\n      exportFreeTubeSearchHistory()\n      break\n    case 'youtube':\n      exportYouTubeSearchHistory()\n      break\n  }\n}\n\nasync function exportFreeTubeSearchHistory() {\n  const historyDb = searchHistoryEntries.value.map((entry) => {\n    return JSON.stringify(entry)\n  }).join('\\n') + '\\n'\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'freetube-search-history-' + dateStr + '.db'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    historyDb,\n    t('Settings.Data Settings.Search history file'),\n    'application/x-freetube-db',\n    '.db',\n    t('Settings.Data Settings.All search history has been successfully exported')\n  )\n}\n\nasync function exportYouTubeSearchHistory() {\n  const historyData = searchHistoryEntries.value.map((entry) => {\n    return {\n      header: 'YouTube',\n      title: `Searched for ${entry._id}`,\n      titleUrl: `https://www.youtube.com/results?search_query=${encodeURIComponent(entry._id)}`,\n      time: new Date(entry.lastUpdatedAt).toISOString(),\n      products: [\n        'YouTube'\n      ],\n      activityControls: [\n        'YouTube search history'\n      ]\n    }\n  })\n\n  const dateStr = getTodayDateStrLocalTimezone()\n  const exportFileName = 'youtube-search-history-' + dateStr + '.json'\n\n  await promptAndWriteToFile(\n    exportFileName,\n    JSON.stringify(historyData),\n    t('Settings.Data Settings.Search history file'),\n    'application/json',\n    '.json',\n    t('Settings.Data Settings.All search history has been successfully exported')\n  )\n}\n\n// #endregion search history\n</script>\n\n<style scoped src=\"./DataSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/DistractionSettings/DistractionSettings.css",
    "content": "@media only screen and (width <= 800px) {\n  .hide-on-mobile {\n    display: none;\n  }\n}\n\n.containingTextFlexBox {\n  margin-block-end: 2em;\n}\n"
  },
  {
    "path": "src/renderer/components/DistractionSettings/DistractionSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"t('Settings.Distraction Free Settings.Distraction Free Settings')\"\n  >\n    <h4\n      class=\"groupTitle\"\n    >\n      {{ t('Settings.Distraction Free Settings.Sections.General') }}\n    </h4>\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Video Views')\"\n          :compact=\"true\"\n          :default-value=\"hideVideoViews\"\n          @change=\"updateHideVideoViews\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Subscribers')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelSubscriptions\"\n          @change=\"updateHideChannelSubscriptions\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Sharing Actions')\"\n          :compact=\"true\"\n          :default-value=\"hideSharingActions\"\n          @change=\"updateHideSharingActions\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Videos on Watch')\"\n          :default-value=\"hideWatchedSubs\"\n          :compact=\"true\"\n          :tooltip=\"t('Tooltips.Distraction Free Settings.Hide Videos on Watch')\"\n          @change=\"updateHideWatchedSubs\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Live Streams')\"\n          :compact=\"true\"\n          :default-value=\"hideLiveStreams\"\n          @change=\"updateHideLiveStreams\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Upcoming Premieres')\"\n          :compact=\"true\"\n          :default-value=\"hideUpcomingPremieres\"\n          @change=\"updateHideUpcomingPremieres\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Display Titles Without Excessive Capitalisation')\"\n          :compact=\"true\"\n          :default-value=\"showDistractionFreeTitles\"\n          @change=\"updateShowDistractionFreeTitles\"\n        />\n      </div>\n    </div>\n    <br class=\"hide-on-mobile\">\n    <FtFlexBox>\n      <FtInputTags\n        :disabled=\"channelHiderDisabled\"\n        :disabled-msg=\"t('Settings.Distraction Free Settings.Hide Channels Disabled Message')\"\n        :label=\"t('Settings.Distraction Free Settings.Hide Channels')\"\n        :tag-name-placeholder=\"t('Settings.Distraction Free Settings.Hide Channels Placeholder')\"\n        :tag-list=\"channelsHidden\"\n        :tooltip=\"t('Tooltips.Distraction Free Settings.Hide Channels')\"\n        :validate-tag-name=\"checkYoutubeChannelId\"\n        :find-tag-info=\"findChannelTagInfoWrapper\"\n        :are-channel-tags=\"true\"\n        :show-tags=\"showAddedChannelsHidden\"\n        @invalid-name=\"handleInvalidChannel\"\n        @error-find-tag-info=\"handleChannelAPIError\"\n        @change=\"handleChannelsHidden\"\n        @already-exists=\"handleChannelsExists\"\n        @toggle-show-tags=\"handleAddedChannelsHidden\"\n      />\n    </FtFlexBox>\n    <FtFlexBox class=\"containingTextFlexBox\">\n      <FtInputTags\n        :label=\"t('Settings.Distraction Free Settings.Hide Videos, Playlists and Channels Containing Text')\"\n        :tag-name-placeholder=\"t('Settings.Distraction Free Settings.Hide Videos, Playlists and Channels Containing Text Placeholder')\"\n        :show-tags=\"showAddedForbiddenTitles\"\n        :tag-list=\"forbiddenTitles\"\n        :min-input-length=\"1\"\n        :tooltip=\"t('Tooltips.Distraction Free Settings.Hide Videos, Playlists and Channels Containing Text')\"\n        @change=\"handleForbiddenTitles\"\n        @toggle-show-tags=\"handleAddedForbiddenTitles\"\n      />\n    </FtFlexBox>\n    <h4\n      class=\"groupTitle\"\n    >\n      {{ t('Settings.Distraction Free Settings.Sections.Side Bar') }}\n    </h4>\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          v-if=\"SUPPORTS_LOCAL_API\"\n          :label=\"t('Settings.Distraction Free Settings.Hide Trending Videos')\"\n          :compact=\"true\"\n          :disabled=\"disableHideTrendingVideos\"\n          :default-value=\"hideTrendingVideos\"\n          @change=\"updateHideTrendingVideos\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Popular Videos')\"\n          :compact=\"true\"\n          :disabled=\"disableHidePopularVideos\"\n          :default-value=\"disableHidePopularVideos || hidePopularVideos\"\n          @change=\"updateHidePopularVideos\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Playlists')\"\n          :compact=\"true\"\n          :default-value=\"hidePlaylists\"\n          @change=\"updateHidePlaylists\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Active Subscriptions')\"\n          :compact=\"true\"\n          :default-value=\"hideActiveSubscriptions\"\n          @change=\"updateHideActiveSubscriptions\"\n        />\n      </div>\n    </div>\n    <h4\n      class=\"groupTitle\"\n    >\n      {{ t('Settings.Distraction Free Settings.Sections.Subscriptions Page') }}\n    </h4>\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Subscriptions Videos')\"\n          :compact=\"true\"\n          :default-value=\"hideSubscriptionsVideos\"\n          @change=\"updateHideSubscriptionsVideos\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Subscriptions Shorts')\"\n          :compact=\"true\"\n          :default-value=\"hideSubscriptionsShorts\"\n          @change=\"updateHideSubscriptionsShorts\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Subscriptions Live')\"\n          :compact=\"true\"\n          :disabled=\"hideLiveStreams\"\n          :default-value=\"hideLiveStreams || hideSubscriptionsLive\"\n          :tooltip=\"hideLiveStreams ? hideSubscriptionsLiveTooltip : ''\"\n          v-on=\"!hideLiveStreams ? { change: updateHideSubscriptionsLive } : {}\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Subscriptions Posts')\"\n          :compact=\"true\"\n          :default-value=\"hideSubscriptionsCommunity\"\n          @change=\"updateHideSubscriptionsCommunity\"\n        />\n      </div>\n    </div>\n    <h4\n      class=\"groupTitle\"\n    >\n      {{ t('Settings.Distraction Free Settings.Sections.Channel Page') }}\n    </h4>\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Home')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelHome\"\n          @change=\"updateHideChannelHome\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Shorts')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelShorts\"\n          @change=\"updateHideChannelShorts\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Playlists')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelPlaylists\"\n          @change=\"updateHideChannelPlaylists\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Podcasts')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelPodcasts\"\n          @change=\"updateHideChannelPodcasts\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Posts')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelCommunity\"\n          @change=\"updateHideChannelCommunity\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Featured Channels')\"\n          :compact=\"true\"\n          :default-value=\"hideFeaturedChannels\"\n          @change=\"updateHideFeaturedChannels\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Releases')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelReleases\"\n          @change=\"updateHideChannelReleases\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Channel Courses')\"\n          :compact=\"true\"\n          :default-value=\"hideChannelCourses\"\n          @change=\"updateHideChannelCourses\"\n        />\n      </div>\n    </div>\n    <h4\n      class=\"groupTitle\"\n    >\n      {{ t('Settings.Distraction Free Settings.Sections.Watch Page') }}\n    </h4>\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Video Likes And Dislikes')\"\n          :compact=\"true\"\n          :default-value=\"hideVideoLikesAndDislikes\"\n          @change=\"updateHideVideoLikesAndDislikes\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Chapters')\"\n          :compact=\"true\"\n          :default-value=\"hideChapters\"\n          @change=\"updateHideChapters\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Video Description')\"\n          :compact=\"true\"\n          :default-value=\"hideVideoDescription\"\n          @change=\"updateHideVideoDescription\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Comment Likes')\"\n          :compact=\"true\"\n          :default-value=\"hideCommentLikes\"\n          @change=\"updateHideCommentLikes\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Live Chat')\"\n          :compact=\"true\"\n          :default-value=\"hideLiveChat\"\n          @change=\"updateHideLiveChat\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Recommended Videos')\"\n          :compact=\"true\"\n          :default-value=\"hideRecommendedVideos\"\n          @change=\"handleHideRecommendedVideos\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Comments')\"\n          :compact=\"true\"\n          :default-value=\"hideComments\"\n          @change=\"updateHideComments\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Distraction Free Settings.Hide Profile Pictures in Comments')\"\n          :compact=\"true\"\n          :default-value=\"hideCommentPhotos\"\n          @change=\"updateHideCommentPhotos\"\n        />\n      </div>\n    </div>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, onMounted, ref } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport FtInputTags from '../FtInputTags/FtInputTags.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\n\nimport store from '../../store/index'\n\nimport { showToast } from '../../helpers/utils'\nimport { checkYoutubeChannelId, findChannelTagInfo } from '../../helpers/channels'\n\nconst { t } = useI18n()\n\nconst SUPPORTS_LOCAL_API = process.env.SUPPORTS_LOCAL_API\n\nconst channelHiderDisabled = ref(false)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\nconst backendOptions = computed(() => ({\n  preference: backendPreference.value,\n  fallback: backendFallback.value\n}))\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoViews = computed(() => store.getters.getHideVideoViews)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideVideoViews(value) {\n  store.dispatch('updateHideVideoViews', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoLikesAndDislikes = computed(() => store.getters.getHideVideoLikesAndDislikes)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideVideoLikesAndDislikes(value) {\n  store.dispatch('updateHideVideoLikesAndDislikes', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelSubscriptions = computed(() => store.getters.getHideChannelSubscriptions)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelSubscriptions(value) {\n  store.dispatch('updateHideChannelSubscriptions', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideCommentLikes = computed(() => store.getters.getHideCommentLikes)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideCommentLikes(value) {\n  store.dispatch('updateHideCommentLikes', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideRecommendedVideos = computed(() => store.getters.getHideRecommendedVideos)\n\n/**\n * @param {boolean} value\n */\nfunction handleHideRecommendedVideos(value) {\n  if (value) {\n    store.dispatch('updatePlayNextVideo', false)\n  }\n\n  store.dispatch('updateHideRecommendedVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideTrendingVideos = computed(() => store.getters.getHideTrendingVideos)\n\nconst disableHideTrendingVideos = computed(() => backendPreference.value !== 'local' && !backendFallback.value)\n/**\n * @param {boolean} value\n */\nfunction updateHideTrendingVideos(value) {\n  store.dispatch('updateHideTrendingVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePopularVideos = computed(() => store.getters.getHidePopularVideos)\n\nconst disableHidePopularVideos = computed(() => backendPreference.value !== 'invidious' && !backendFallback.value)\n\n/**\n * @param {boolean} value\n */\nfunction updateHidePopularVideos(value) {\n  store.dispatch('updateHidePopularVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePlaylists = computed(() => store.getters.getHidePlaylists)\n\n/**\n * @param {boolean} value\n */\nfunction updateHidePlaylists(value) {\n  store.dispatch('updateHidePlaylists', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLiveChat = computed(() => store.getters.getHideLiveChat)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideLiveChat(value) {\n  store.dispatch('updateHideLiveChat', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideActiveSubscriptions = computed(() => store.getters.getHideActiveSubscriptions)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideActiveSubscriptions(value) {\n  store.dispatch('updateHideActiveSubscriptions', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoDescription = computed(() => store.getters.getHideVideoDescription)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideVideoDescription(value) {\n  store.dispatch('updateHideVideoDescription', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideComments = computed(() => store.getters.getHideComments)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideComments(value) {\n  store.dispatch('updateHideComments', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideCommentPhotos = computed(() => store.getters.getHideCommentPhotos)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideCommentPhotos(value) {\n  store.dispatch('updateHideCommentPhotos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLiveStreams = computed(() => store.getters.getHideLiveStreams)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideLiveStreams(value) {\n  store.dispatch('updateHideLiveStreams', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUpcomingPremieres = computed(() => store.getters.getHideUpcomingPremieres)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideUpcomingPremieres(value) {\n  store.dispatch('updateHideUpcomingPremieres', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSharingActions = computed(() => store.getters.getHideSharingActions)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSharingActions(value) {\n  store.dispatch('updateHideSharingActions', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChapters = computed(() => store.getters.getHideChapters)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChapters(value) {\n  store.dispatch('updateHideChapters', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideFeaturedChannels = computed(() => store.getters.getHideFeaturedChannels)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideFeaturedChannels(value) {\n  store.dispatch('updateHideFeaturedChannels', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelShorts = computed(() => store.getters.getHideChannelShorts)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelShorts(value) {\n  store.dispatch('updateHideChannelShorts', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelPlaylists = computed(() => store.getters.getHideChannelPlaylists)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelPlaylists(value) {\n  store.dispatch('updateHideChannelPlaylists', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelPodcasts = computed(() => store.getters.getHideChannelPodcasts)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelPodcasts(value) {\n  store.dispatch('updateHideChannelPodcasts', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelReleases = computed(() => store.getters.getHideChannelReleases)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelReleases(value) {\n  store.dispatch('updateHideChannelReleases', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelCourses = computed(() => store.getters.getHideChannelCourses)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelCourses(value) {\n  store.dispatch('updateHideChannelCourses', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelCommunity = computed(() => store.getters.getHideChannelCommunity)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelCommunity(value) {\n  store.dispatch('updateHideChannelCommunity', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelHome = computed(() => store.getters.getHideChannelHome)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideChannelHome(value) {\n  store.dispatch('updateHideChannelHome', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsVideos = computed(() => store.getters.getHideSubscriptionsVideos)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSubscriptionsVideos(value) {\n  store.dispatch('updateHideSubscriptionsVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsShorts = computed(() => store.getters.getHideSubscriptionsShorts)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSubscriptionsShorts(value) {\n  store.dispatch('updateHideSubscriptionsShorts', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsLive = computed(() => store.getters.getHideSubscriptionsLive)\n\nconst hideSubscriptionsLiveTooltip = computed(() => {\n  return t('Tooltips.Distraction Free Settings.Hide Subscriptions Live', {\n    appWideSetting: t('Settings.Distraction Free Settings.Hide Live Streams'),\n    subsection: t('Settings.Distraction Free Settings.Sections.General'),\n    settingsSection: t('Settings.Distraction Free Settings.Distraction Free Settings')\n  })\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSubscriptionsLive(value) {\n  store.dispatch('updateHideSubscriptionsLive', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsCommunity = computed(() => store.getters.getHideSubscriptionsCommunity)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSubscriptionsCommunity(value) {\n  store.dispatch('updateHideSubscriptionsCommunity', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showDistractionFreeTitles = computed(() => store.getters.getShowDistractionFreeTitles)\n\n/**\n * @param {boolean} value\n */\nfunction updateShowDistractionFreeTitles(value) {\n  store.dispatch('updateShowDistractionFreeTitles', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showAddedChannelsHidden = computed(() => store.getters.getShowAddedChannelsHidden)\n\nfunction handleAddedChannelsHidden() {\n  store.dispatch('updateShowAddedChannelsHidden', !showAddedChannelsHidden.value)\n}\n\n/** @type {import('vue').ComputedRef<any[]>} */\nconst channelsHidden = computed(() => {\n  return JSON.parse(store.getters.getChannelsHidden).map((ch) => {\n    // Legacy support\n    if (typeof ch === 'string') {\n      return { name: ch, preferredName: '', icon: '' }\n    }\n    return ch\n  })\n})\n\n/**\n * @param {any[]} value\n */\nfunction handleChannelsHidden(value) {\n  store.dispatch('updateChannelsHidden', JSON.stringify(value))\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showAddedForbiddenTitles = computed(() => store.getters.getShowAddedForbiddenTitles)\n\nfunction handleAddedForbiddenTitles() {\n  store.dispatch('updateShowAddedForbiddenTitles', !showAddedForbiddenTitles.value)\n}\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst forbiddenTitles = computed(() => JSON.parse(store.getters.getForbiddenTitles))\n\n/**\n * @param {string[]} value\n */\nfunction handleForbiddenTitles(value) {\n  store.dispatch('updateForbiddenTitles', JSON.stringify(value))\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideWatchedSubs = computed(() => store.getters.getHideWatchedSubs)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideWatchedSubs(value) {\n  store.dispatch('updateHideWatchedSubs', value)\n}\n\nonMounted(() => {\n  verifyChannelsHidden()\n})\n\nfunction handleInvalidChannel() {\n  showToast(t('Settings.Distraction Free Settings.Hide Channels Invalid'))\n}\n\nfunction handleChannelAPIError() {\n  showToast(t('Settings.Distraction Free Settings.Hide Channels API Error'))\n}\n\nfunction handleChannelsExists() {\n  showToast(t('Settings.Distraction Free Settings.Hide Channels Already Exists'))\n}\n\n/**\n * @param {string} text\n */\nasync function findChannelTagInfoWrapper(text) {\n  return await findChannelTagInfo(text, backendOptions.value)\n}\n\nasync function verifyChannelsHidden() {\n  const channelsHiddenCpy = [...channelsHidden.value]\n\n  for (let i = 0; i < channelsHiddenCpy.length; i++) {\n    const tag = channelsHiddenCpy[i]\n\n    // if channel has been processed and confirmed as non existent, skip\n    if (tag.invalid) continue\n\n    // process if no preferred name and is possibly a YouTube ID\n    if ((tag.preferredName === '' || !tag.icon) && checkYoutubeChannelId(tag.name)) {\n      channelHiderDisabled.value = true\n\n      const { preferredName, icon, iconHref, invalidId } = await findChannelTagInfoWrapper(tag.name)\n      if (invalidId) {\n        channelsHiddenCpy[i] = { name: tag.name, invalid: invalidId }\n      } else {\n        channelsHiddenCpy[i] = { name: tag.name, preferredName, icon, iconHref }\n      }\n\n      // update on every tag in case it closes\n      handleChannelsHidden(channelsHiddenCpy)\n    }\n  }\n\n  channelHiderDisabled.value = false\n}\n</script>\n\n<style scoped src=\"./DistractionSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/ExperimentalSettings/ExperimentalSettings.css",
    "content": ".experimental-warning {\n  text-align: center;\n  font-weight: bold;\n  padding-inline: 4%;\n}\n"
  },
  {
    "path": "src/renderer/components/ExperimentalSettings/ExperimentalSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Experimental Settings.Experimental Settings')\"\n  >\n    <p class=\"experimental-warning\">\n      {{ $t('Settings.Experimental Settings.Warning') }}\n    </p>\n    <FtFlexBox>\n      <FtToggleSwitch\n        tooltip-position=\"top\"\n        :label=\"$t('Settings.Experimental Settings.Replace HTTP Cache')\"\n        compact\n        :default-value=\"replaceHttpCache\"\n        :disabled=\"replaceHttpCacheLoading\"\n        :tooltip=\"$t('Tooltips.Experimental Settings.Replace HTTP Cache')\"\n        @change=\"handleRestartPrompt\"\n      />\n    </FtFlexBox>\n    <FtPrompt\n      v-if=\"showRestartPrompt\"\n      :label=\"$t('Settings[\\'The app needs to restart for changes to take effect. Restart and apply change?\\']')\"\n      :option-names=\"[$t('Yes, Restart'), $t('Cancel')]\"\n      :option-values=\"['restart', 'cancel']\"\n      @click=\"handleReplaceHttpCache\"\n    />\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { onMounted, ref } from 'vue'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\n\nconst replaceHttpCacheLoading = ref(true)\nconst replaceHttpCache = ref(false)\nconst showRestartPrompt = ref(false)\n\nonMounted(async () => {\n  if (process.env.IS_ELECTRON) {\n    replaceHttpCache.value = await window.ftElectron.getReplaceHttpCache()\n  }\n\n  replaceHttpCacheLoading.value = false\n})\n\n/**\n * @param {boolean} value\n */\nfunction handleRestartPrompt(value) {\n  replaceHttpCache.value = value\n  showRestartPrompt.value = true\n}\n\n/**\n * @param {'restart' | 'cancel' | null} value\n */\nfunction handleReplaceHttpCache(value) {\n  showRestartPrompt.value = false\n\n  if (value === null || value === 'cancel') {\n    replaceHttpCache.value = !replaceHttpCache.value\n    return\n  }\n\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.toggleReplaceHttpCache()\n  }\n}\n</script>\n\n<style scoped src=\"./ExperimentalSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/ExternalPlayerSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.External Player Settings.External Player Settings')\"\n  >\n    <FtFlexBox>\n      <FtSelect\n        :placeholder=\"$t('Settings.External Player Settings.External Player')\"\n        :value=\"externalPlayer\"\n        :select-names=\"externalPlayerNames\"\n        :select-values=\"externalPlayerValues\"\n        :tooltip=\"$t('Tooltips.External Player Settings.External Player')\"\n        :icon=\"['fas', 'external-link-alt']\"\n        @change=\"updateExternalPlayer\"\n      />\n    </FtFlexBox>\n    <FtFlexBox>\n      <FtToggleSwitch\n        :label=\"$t('Settings.External Player Settings.Ignore Unsupported Action Warnings')\"\n        :default-value=\"externalPlayerIgnoreWarnings\"\n        :disabled=\"externalPlayer === ''\"\n        :compact=\"true\"\n        :tooltip=\"$t('Tooltips.External Player Settings.Ignore Warnings')\"\n        @change=\"updateExternalPlayerIgnoreWarnings\"\n      />\n      <FtToggleSwitch\n        :label=\"$t('Settings.External Player Settings.Ignore Default Arguments')\"\n        :default-value=\"externalPlayerIgnoreDefaultArgs\"\n        :disabled=\"externalPlayer === ''\"\n        :compact=\"true\"\n        :tooltip=\"$t('Tooltips.External Player Settings.Ignore Default Arguments')\"\n        @change=\"updateExternalPlayerIgnoreDefaultArgs\"\n      />\n    </FtFlexBox>\n    <FtFlexBox\n      v-if=\"externalPlayer !== ''\"\n      class=\"settingsFlexStart460px\"\n    >\n      <FtInput\n        :placeholder=\"$t('Settings.External Player Settings.Custom External Player Executable')\"\n        :show-action-button=\"false\"\n        :show-label=\"true\"\n        :value=\"externalPlayerExecutable\"\n        :tooltip=\"$t('Tooltips.External Player Settings.Custom External Player Executable')\"\n        @input=\"updateExternalPlayerExecutable\"\n      />\n    </FtFlexBox>\n    <FtFlexBox\n      v-if=\"externalPlayer !== ''\"\n    >\n      <FtInputTags\n        :label=\"$t('Settings.External Player Settings.Custom External Player Arguments')\"\n        :tag-name-placeholder=\"$t('Settings.External Player Settings.Custom External Player Arguments')\"\n        :tag-list=\"externalPlayerCustomArgs\"\n        :tooltip=\"externalPlayerCustomArgsTooltip\"\n        :show-tags=\"showAddedExternalPlayerCustomArgs\"\n        @change=\"handleExternalPlayerCustomArgs\"\n        @toggle-show-tags=\"handleAddedExternalPayerCustomArgs\"\n      />\n    </FtFlexBox>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'\nimport FtSelect from './FtSelect/FtSelect.vue'\nimport FtInput from './FtInput/FtInput.vue'\nimport FtToggleSwitch from './FtToggleSwitch/FtToggleSwitch.vue'\nimport FtFlexBox from './ft-flex-box/ft-flex-box.vue'\nimport FtInputTags from './FtInputTags/FtInputTags.vue'\n\nimport store from '../store/index'\n\nconst { t } = useI18n()\n\n/** @type {import('vue').ComputedRef<string>} */\nconst externalPlayer = computed(() => store.getters.getExternalPlayer)\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst externalPlayerNames = computed(() => {\n  return store.getters.getExternalPlayerNames.map((name) => {\n    return name === 'None'\n      ? t('Settings.External Player Settings.Players.None.Name')\n      : name\n  })\n})\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst externalPlayerValues = computed(() => store.getters.getExternalPlayerValues)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst externalPlayerExecutable = computed(() => store.getters.getExternalPlayerExecutable)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst externalPlayerIgnoreWarnings = computed(() => store.getters.getExternalPlayerIgnoreWarnings)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst externalPlayerIgnoreDefaultArgs = computed(() => store.getters.getExternalPlayerIgnoreDefaultArgs)\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst externalPlayerCustomArgs = computed(() => JSON.parse(store.getters.getExternalPlayerCustomArgs))\n\nconst externalPlayerCustomArgsTooltip = computed(() => {\n  const tooltip = t('Tooltips.External Player Settings.Custom External Player Arguments')\n\n  const cmdArgs = store.getters.getExternalPlayerCmdArguments[externalPlayer.value]\n  if (cmdArgs && typeof cmdArgs.defaultCustomArguments === 'string' && cmdArgs.defaultCustomArguments !== '') {\n    const defaultArgs = t(\n      'Tooltips.External Player Settings.DefaultCustomArgumentsTemplate',\n      {\n        defaultCustomArguments: cmdArgs.defaultCustomArguments\n      })\n    return `${tooltip} ${defaultArgs}`\n  }\n\n  return tooltip\n})\n\n/**\n * @param {string} value\n */\nfunction updateExternalPlayer(value) {\n  store.dispatch('updateExternalPlayer', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateExternalPlayerIgnoreWarnings(value) {\n  store.dispatch('updateExternalPlayerIgnoreWarnings', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateExternalPlayerIgnoreDefaultArgs(value) {\n  store.dispatch('updateExternalPlayerIgnoreDefaultArgs', value)\n}\n\n/**\n * @param {string} value\n */\nfunction updateExternalPlayerExecutable(value) {\n  store.dispatch('updateExternalPlayerExecutable', value)\n}\n\n/**\n * @param {string[]} args\n */\nfunction handleExternalPlayerCustomArgs(args) {\n  store.dispatch('updateExternalPlayerCustomArgs', JSON.stringify(args))\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showAddedExternalPlayerCustomArgs = computed(() => store.getters.getShowAddedExternalPlayerCustomArgs)\n\nfunction handleAddedExternalPayerCustomArgs() {\n  store.dispatch('updateShowAddedExternalPlayerCustomArgs', !showAddedExternalPlayerCustomArgs.value)\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/FtAgeRestricted/FtAgeRestricted.css",
    "content": ".message {\n  padding-block: 10px;\n}\n\n.frown {\n  font-size: 10em;\n  block-size: 100%;\n  padding-block: 20px;\n}\n\n.message,\n.frown {\n  color: var(--primary-text-color);\n  background-color: var(--card-bg-color);\n  padding-inline: 0;\n  text-align: center;\n  inline-size: 100%;\n}\n"
  },
  {
    "path": "src/renderer/components/FtAgeRestricted/FtAgeRestricted.vue",
    "content": "<template>\n  <div>\n    <h2 class=\"message\">\n      {{ restrictedMessage }}\n    </h2>\n    <div class=\"frown\">\n      {{ emoji }}\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport { randomArrayItem } from '../../helpers/utils'\n\nconst { t } = useI18n()\n\nconst props = defineProps({\n  isChannel: {\n    type: Boolean,\n    default: false,\n  }\n})\n\nconst emoji = randomArrayItem(['😵', '😦', '🙁', '☹️', '😦', '🤫', '😕'])\n\nconst restrictedMessage = computed(() => {\n  if (props.isChannel) {\n    return t('Age Restricted.This channel is age restricted')\n  }\n\n  return t('Age Restricted.This video is age restricted')\n})\n</script>\n\n<style scoped src=\"./FtAgeRestricted.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtAutoGrid/FtAutoGrid.css",
    "content": ".grid {\n  display: grid;\n  gap: 8px;\n  grid-template-columns: repeat(auto-fill, minmax(262px, 1fr));\n  justify-content: space-evenly;\n}\n\n.list {\n  display: grid;\n  gap: 4px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtAutoGrid/FtAutoGrid.vue",
    "content": "<template>\n  <div\n    :class=\"{\n      grid: grid,\n      list: !grid\n    }\"\n  >\n    <slot />\n  </div>\n</template>\n\n<script setup>\ndefineProps({\n  grid: {\n    type: Boolean,\n    required: true\n  }\n})\n</script>\n\n<style scoped src=\"./FtAutoGrid.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtAutoLoadNextPageWrapper.vue",
    "content": "<template>\n  <div\n    class=\"ft-auto-load-next-page-wrapper\"\n  >\n    <div\n      v-observe-visibility=\"observeVisibilityOptions\"\n    >\n      <!--\n        Dummy element to be observed by Intersection Observer\n      -->\n    </div>\n    <slot />\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport store from '../store/index'\n\nconst emit = defineEmits(['load-next-page'])\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst generalAutoLoadMorePaginatedItemsEnabled = computed(() => {\n  return store.getters.getGeneralAutoLoadMorePaginatedItemsEnabled\n})\n\nconst observeVisibilityOptions = computed(() => {\n  if (generalAutoLoadMorePaginatedItemsEnabled.value) {\n    return {\n      callback: (isVisible, _entry) => {\n        // This is also fired when **hidden**\n        // No point doing anything if not visible\n        if (isVisible) {\n          emit('load-next-page')\n        }\n      },\n      intersection: {\n        // Only when it intersects with N% above bottom\n        rootMargin: '0% 0% 0% 0%',\n      },\n      // Callback responsible for loading multiple pages\n      once: false,\n    }\n  } else {\n    return false\n  }\n})\n</script>\n"
  },
  {
    "path": "src/renderer/components/FtButton/FtButton.css",
    "content": ".btn {\n  font-family: Roboto, sans-serif;\n  min-inline-size: 100px;\n  font-size: 0.9rem;\n  padding-block: 10px;\n  padding-inline: 20px;\n  block-size: fit-content;\n  box-sizing: border-box;\n  cursor: pointer;\n  align-items: center;\n  justify-content: center;\n  text-align: center;\n  text-decoration: none;\n  transition: 0.3s;\n  border-radius: 4px;\n  white-space: nowrap;\n  font-weight: 500;\n  vertical-align: middle;\n  display: flex;\n  gap: 10px;\n  margin: 5px;\n  box-shadow: 0 1px 2px rgb(0 0 0 / 50%);\n  border: 2px solid;\n}\n\n.btn:disabled {\n  opacity: 0.4;\n  cursor: not-allowed;\n}\n\n.ripple {\n  position: relative;\n  overflow: hidden;\n  transform: translate3d(0, 0, 0);\n}\n\n.ripple::after {\n  content: '';\n  display: block;\n  position: absolute;\n  inline-size: 100%;\n  block-size: 100%;\n  inset-block-start: 0;\n  inset-inline-start: 0;\n  pointer-events: none;\n  background-image: radial-gradient(circle, #fff 10%, transparent 10.01%);\n  background-repeat: no-repeat;\n  background-position: 50%;\n  transform: scale(10, 10);\n  opacity: 0;\n  transition: transform 0.5s, opacity 1s;\n}\n\n.ripple:active::after {\n  transform: scale(0, 0);\n  opacity: 0.3;\n  transition: 0s;\n}\n"
  },
  {
    "path": "src/renderer/components/FtButton/FtButton.vue",
    "content": "<template>\n  <button\n    class=\"btn ripple\"\n    :style=\"{\n      color: textColor,\n      backgroundColor: backgroundColor,\n      borderColor: backgroundColor\n    }\"\n    @click=\"click\"\n  >\n    <slot>\n      <FontAwesomeIcon\n        v-if=\"icon\"\n        :icon=\"icon\"\n      />\n      {{ label }}\n    </slot>\n  </button>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\n\ndefineProps({\n  label: {\n    type: String,\n    default: ''\n  },\n  textColor: {\n    type: String,\n    default: 'var(--text-with-accent-color)'\n  },\n  backgroundColor: {\n    type: String,\n    default: 'var(--accent-color)'\n  },\n  icon: {\n    type: Array,\n    default: null\n  }\n})\n\nconst emit = defineEmits(['click'])\n\nfunction click() {\n  emit('click')\n}\n</script>\n\n<style scoped src=\"./FtButton.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtChannelBubble/FtChannelBubble.css",
    "content": ".bubblePadding {\n  position: relative;\n  inline-size: 100px;\n  block-size: 100px;\n  padding: 10px;\n  cursor: pointer;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 16px;\n  overflow: hidden;\n  color: inherit;\n  text-decoration: none;\n  transition: background 0.2s ease-out;\n}\n\n.bubblePadding:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.bubble {\n  inline-size: 50px;\n  block-size: 50px;\n  border-radius: 100%;\n  object-fit: cover;\n}\n\n.selected {\n  position: absolute;\n  inset-block-start: 10px;\n  background-color: rgb(0 0 0 / 50%);\n}\n\n.icon {\n  color: #eee;\n  font-size: 25px;\n  position: absolute;\n  inset-block-start: 12px;\n  inset-inline-start: 12px;\n}\n\n.channelName {\n  display: block;\n  font-size: 13px;\n  overflow: hidden;\n  text-align: center;\n  text-overflow: ellipsis;\n  inline-size: 100%;\n}\n"
  },
  {
    "path": "src/renderer/components/FtChannelBubble/FtChannelBubble.vue",
    "content": "<template>\n  <router-link\n    v-if=\"!selectable\"\n    class=\"bubblePadding\"\n    :aria-labelledby=\"id\"\n    :to=\"`/channel/${channelId}`\"\n  >\n    <img\n      v-if=\"channelThumbnail != null\"\n      class=\"bubble\"\n      :src=\"channelThumbnail\"\n      alt=\"\"\n    >\n    <FontAwesomeIcon\n      v-else\n      :icon=\"['fas', 'circle-user']\"\n      class=\"bubble\"\n    />\n    <div\n      :id=\"id\"\n      class=\"channelName\"\n      dir=\"auto\"\n    >\n      {{ channelName }}\n    </div>\n  </router-link>\n  <div\n    v-else\n    class=\"bubblePadding\"\n    :aria-checked=\"selected\"\n    role=\"checkbox\"\n    tabindex=\"0\"\n    :aria-labelledby=\"id\"\n    @click=\"handleClick\"\n    @keydown.space.enter.prevent=\"handleClick\"\n  >\n    <img\n      class=\"bubble\"\n      :src=\"channelThumbnail\"\n      alt=\"\"\n    >\n    <div\n      v-if=\"selected\"\n      class=\"bubble selected\"\n    >\n      <FontAwesomeIcon\n        :icon=\"['fas', 'check']\"\n        class=\"icon\"\n      />\n    </div>\n    <div\n      :id=\"id\"\n      class=\"channelName\"\n      dir=\"auto\"\n    >\n      {{ channelName }}\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useId } from 'vue'\n\nconst props = defineProps({\n  channelId: {\n    type: String,\n    required: true\n  },\n  channelName: {\n    type: String,\n    required: true\n  },\n  channelThumbnail: {\n    type: String,\n    default: null\n  },\n  selectable: {\n    type: Boolean,\n    default: false\n  },\n  selected: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst id = useId()\n\nconst emit = defineEmits(['change'])\n\nfunction handleClick() {\n  emit('change', !props.selected)\n}\n</script>\n\n<style scoped src=\"./FtChannelBubble.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtCheckboxList/FtCheckboxList.css",
    "content": "/* stylelint-disable no-descending-specificity */\n.pure-checkbox input[type='checkbox'] {\n  border: 0;\n  clip-path: circle(0);\n  block-size: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  inline-size: 1px;\n}\n\n.pure-checkbox input[type='checkbox']:focus + label::before,\n.pure-checkbox input[type='checkbox']:hover + label::before {\n  border: 2px solid var(--primary-color);\n}\n\n.pure-checkbox input[type='checkbox']:active + label::before { transition-duration: 0s; }\n\n.pure-checkbox input[type='checkbox'] + label {\n  position: relative;\n  padding-inline-start: 2em;\n  user-select: none;\n  cursor: pointer;\n  display: block;\n  margin-block-start: 10px;\n}\n\n.pure-checkbox input[type='checkbox'] + label::before {\n  box-sizing: content-box;\n  content: '';\n  color: var(--primary-text-color);\n  position: absolute;\n  inset-block-start: 50%;\n  inset-inline-start: 0;\n  inline-size: 14px;\n  block-size: 14px;\n  margin-block-start: -9px;\n  border: 2px solid var(--primary-text-color);\n  text-align: center;\n  transition: all 0.4s ease;\n}\n\n.pure-checkbox input[type='checkbox'] + label::after {\n  box-sizing: content-box;\n  border-style: solid;\n  border-image: none;\n  border-width: 0 0 3px 3px;\n  content: '';\n  background-color: transparent;\n  position: absolute;\n  inset-block-start: 50%;\n  inset-inline-start: 4px;\n  inline-size: 8px;\n  block-size: 3px;\n  margin-block-start: -4px;\n  transform: rotate(-45deg) scale(0);\n  transform-origin: 50%;\n  transition: transform 200ms ease-out;\n}\n\n.pure-checkbox input[type='checkbox']:disabled + label::before { border-color: #ccc; }\n\n.pure-checkbox input[type='checkbox']:disabled:focus + label::before,\n.pure-checkbox input[type='checkbox']:disabled:hover + label::before { background-color: inherit; }\n\n.pure-checkbox input[type='checkbox']:disabled:checked + label::before { background-color: #ccc; }\n\n.pure-checkbox input[type='checkbox']:checked + label::after {\n  content: '';\n  transform: rotate(-45deg) scale(1);\n  transition: transform 200ms ease-out;\n}\n\n.pure-checkbox input[type='checkbox']:checked + label::before {\n  animation: borderscale 200ms ease-in;\n}\n\n@keyframes\n  borderscale {  50% {\n    box-shadow: 0 0 0 2px var(--primary-text-color);\n  }\n}\n\n.checkboxTitle {\n  margin-block: 0;\n}\n\n@media only screen and (width <= 680px) {\n  .pure-checkbox input[type='checkbox'] + label {\n    margin-block-start: 3px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtCheckboxList/FtCheckboxList.vue",
    "content": "<template>\n  <div class=\"pure-checkbox filter\">\n    <h3 class=\"checkboxTitle\">\n      {{ title }}\n    </h3>\n    <template\n      v-for=\"(label, index) in labels\"\n      :key=\"values[index]\"\n    >\n      <input\n        :id=\"id + values[index]\"\n        v-model=\"modelValue\"\n        :name=\"id\"\n        :value=\"values[index]\"\n        :disabled=\"disabled\"\n        class=\"checkbox\"\n        type=\"checkbox\"\n      >\n      <label\n        :for=\"id + values[index]\"\n      >\n        {{ label }}\n      </label>\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { useId } from 'vue'\n\nconst id = useId()\n\ndefineProps({\n  title: {\n    type: String,\n    required: true\n  },\n  labels: {\n    type: Array,\n    required: true\n  },\n  values: {\n    type: Array,\n    required: true\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n})\n\nconst modelValue = defineModel({ type: Array, required: true })\n</script>\n\n<style scoped src=\"./FtCheckboxList.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtCommunityPoll/FtCommunityPoll.css",
    "content": ".vote-count {\n  padding-block-end: 6px;\n  font-size: smaller;\n}\n\n.empty-circle {\n  background-color: transparent;\n  border-radius: 50%;\n  border-style: solid;\n  border-width: 2px;\n  display: block;\n  float: inline-start;\n  block-size: 10px;\n  position: relative;\n  inline-size: 10px;\n}\n\n.filled-circle {\n  border-radius: 50%;\n  background-color: #000;\n  float: inline-start;\n  block-size: 6px;\n  inset-inline-start: 2px;\n  inset-block-start: 2px;\n  position: relative;\n  inline-size: 6px;\n}\n\n.option-text {\n  margin-inline-start: 10px;\n}\n\n.option {\n  display: flex;\n  align-items: center;\n  padding-block: 5px;\n  border-radius: 5px;\n  border-style: solid;\n  border-width: 1px;\n  padding-inline-start: 10px;\n  margin-block-end: 10px;\n}\n\n.option > img {\n  margin-inline-start: 10px;\n  block-size: 125px;\n}\n\n.correct-option {\n  border-color: #78da71;\n  border-width: 2px;\n}\n\n.correct-option .filled-circle {\n  background-color: #78da71;\n}\n\n.incorrect-option {\n  border-color: #dd4e4e;\n  border-width: 2px;\n}\n\n.reveal-answer {\n  justify-content: center;\n  cursor: pointer;\n}\n\n.reveal-answer:hover,\n.reveal-answer:focus {\n  background-color: var(--side-nav-hover-color);\n}\n"
  },
  {
    "path": "src/renderer/components/FtCommunityPoll/FtCommunityPoll.vue",
    "content": "<template>\n  <div class=\"poll\">\n    <div\n      class=\"vote-count\"\n    >\n      <!-- Format the votes to be split by commas ie. 1000 -> 1,000 -->\n      {{ $t('Channel.Posts.votes', {votes: formattedVotes}) }}\n    </div>\n    <div\n      v-for=\"(choice, index) in data.content\"\n      :key=\"index\"\n    >\n      <div\n        v-if=\"data.type === 'quiz'\"\n        class=\"option quiz-option\"\n        :class=\"revealAnswer && choice.isCorrect ? 'correct-option' : ''\"\n      >\n        <span class=\"empty-circle\">\n          <span :class=\"revealAnswer && choice.isCorrect ? 'filled-circle' : ''\" />\n        </span>\n        <div\n          class=\"option-text\"\n          dir=\"auto\"\n        >\n          {{ choice.text }}\n        </div>\n      </div>\n      <div\n        v-else\n        class=\"option poll-option\"\n      >\n        <span class=\"empty-circle\" />\n        <img\n          v-if=\"choice.image\"\n          :src=\"findSmallestPollImage(choice.image)\"\n          alt=\"\"\n        >\n        <div\n          class=\"option-text\"\n          dir=\"auto\"\n        >\n          {{ choice.text }}\n        </div>\n      </div>\n    </div>\n    <div\n      v-if=\"data.type === 'quiz'\"\n      class=\"reveal-answer option\"\n      tabindex=\"0\"\n      role=\"button\"\n      @click=\"revealAnswer = !revealAnswer\"\n      @keydown.enter.prevent=\"revealAnswer = !revealAnswer\"\n      @keydown.space.prevent=\"revealAnswer = !revealAnswer\"\n    >\n      <div\n        v-if=\"!revealAnswer\"\n        class=\"option-text\"\n      >\n        <FontAwesomeIcon :icon=\"['fas', 'eye']\" /> {{ $t('Channel.Posts.Reveal Answers') }}\n      </div>\n      <div\n        v-else\n        class=\"option-text\"\n      >\n        <FontAwesomeIcon :icon=\"['fas', 'eye-slash']\" /> {{ $t('Channel.Posts.Hide Answers') }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\n\nimport { formatNumber } from '../../helpers/utils'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  }\n})\n\nconst formattedVotes = computed(() => {\n  return formatNumber(props.data.totalVotes)\n})\n\nconst revealAnswer = ref(false)\n\n/**\n * Use smallest as it's resized to 125px anyways and they're usually all larger than that\n * @param {{ height: number, width: number, url: string }[]} images\n */\nfunction findSmallestPollImage(images) {\n  return images.reduce((prev, img) => (img.height < prev.height) ? img : prev, images[0]).url\n}\n</script>\n\n<style scoped src=\"./FtCommunityPoll.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtCommunityPost/FtCommunityPost.scss",
    "content": "/* stylelint-disable property-no-vendor-prefix */\n@use '../../scss-partials/ft-list-item';\n\n.outside {\n  margin: auto;\n  inline-size: 40%;\n\n  @media screen and (width <= 768px) {\n    inline-size: 100%;\n  }\n}\n\n.ft-list-post {\n  box-sizing: border-box;\n}\n\n.hiddenVideo {\n  font-style: italic;\n  opacity: 0.85;\n  text-align: center;\n}\n\n.communityImage {\n  block-size: 100%;\n  inline-size: 100%;\n}\n\n.communityThumbnail {\n  border-radius: 50%;\n  block-size: 55px;\n  margin-inline-end: 5px;\n  inline-size: 55px;\n}\n\n.author-div {\n  display: flex;\n\n  .authorName {\n    font-size: 15px;\n    font-weight: bold;\n    margin-block: 5px 0;\n    margin-inline: 5px 6px;\n\n    .authorNameLink {\n      color: inherit;\n      text-decoration: none;\n    }\n  }\n\n  .publishedText {\n    font-size: 15px;\n    margin-block: 5px 0;\n    margin-inline: 5px 6px;\n  }\n}\n\n.postText {\n  overflow-wrap: anywhere;\n  white-space: pre-wrap;\n}\n\n.commentsLink {\n  color: var(--primary-text-color);\n  text-decoration: none;\n  font-weight: bold;\n}\n\n.bottomSection {\n  color: var(--tertiary-text-color);\n  display: flex;\n  align-items: center;\n  font-size: 15px;\n  margin-block-start: 4px;\n  max-inline-size: 100%;\n  text-align: start;\n\n  @media screen and (width <= 680px) {\n    margin-inline-start: 0;\n    text-align: start;\n  }\n\n  .likeBar {\n    border-radius: 4px;\n    block-size: 8px;\n    margin-block-end: 4px;\n  }\n\n  .likeCount {\n    margin-inline: 5px 6px;\n  }\n\n  .shareButton {\n    margin-inline-start: 10px;\n  }\n}\n\n.playlistWrapper {\n  display: flex;\n\n  .videoThumbnail {\n    display: flex;\n    margin-block: auto;\n    position: relative;\n    inline-size: fit-content;\n\n    .thumbnailImage {\n      display: block;\n      block-size: auto;\n      max-inline-size: 100%;\n      inline-size: auto;\n    }\n  }\n\n  .playlistText {\n    margin-inline-start: 10px;\n    inline-size: 50%;\n    overflow-wrap: break-word;\n\n    .playlistAuthor {\n      font-size: small;\n\n      .playlistVideoCount {\n        font-size: smaller;\n      }\n    }\n\n    .playlistTitle {\n      color: var(--primary-text-color);\n    }\n\n    .playlistPreviewVideos {\n      color: var(--primary-text-color);\n      display: flex;\n      font-size: small;\n      padding-block-start: 10px;\n      text-decoration-line: none;\n      inline-size: 100%;\n    }\n\n    .playlistPreviewVideoTitle {\n      display: block;\n      overflow: hidden;\n      text-overflow: ellipsis;\n      white-space: nowrap;\n      inline-size: 100%;\n    }\n  }\n}\n\n.ft-list-item.grid {\n  min-block-size: 0 !important;\n  padding-block-end: 20px;\n}\n\n.sliderContainer {\n  display: grid;\n}\n"
  },
  {
    "path": "src/renderer/components/FtCommunityPost/FtCommunityPost.vue",
    "content": "<template>\n  <div\n    class=\"ft-list-post ft-list-item outside\"\n    :appearance=\"appearance\"\n    :class=\"{ list: listType === 'list', grid: listType === 'grid' }\"\n  >\n    <div\n      class=\"author-div\"\n    >\n      <template\n        v-if=\"authorThumbnails.length > 0\"\n      >\n        <router-link\n          v-if=\"authorId\"\n          :to=\"`/channel/${authorId}`\"\n          tabindex=\"-1\"\n          aria-hidden=\"true\"\n        >\n          <img\n            :src=\"getBestQualityImage(authorThumbnails)\"\n            class=\"communityThumbnail\"\n            alt=\"\"\n          >\n        </router-link>\n        <img\n          v-else\n          :src=\"getBestQualityImage(authorThumbnails)\"\n          class=\"communityThumbnail\"\n          alt=\"\"\n        >\n      </template>\n      <p\n        class=\"authorName\"\n        dir=\"auto\"\n      >\n        <router-link\n          v-if=\"authorId\"\n          :to=\"`/channel/${authorId}`\"\n          class=\"authorNameLink\"\n        >\n          {{ author }}\n        </router-link>\n        <template\n          v-else\n        >\n          {{ author }}\n        </template>\n      </p>\n      <p\n        class=\"publishedText\"\n      >\n        {{ publishedText }}\n      </p>\n    </div>\n    <p\n      v-safer-html=\"postText\"\n      class=\"postText\"\n      dir=\"auto\"\n    />\n    <swiper-container\n      v-if=\"postType === 'multiImage' && postContent.content.length > 0\"\n      ref=\"swiperContainerRef\"\n      init=\"false\"\n      class=\"sliderContainer\"\n    >\n      <swiper-slide\n        v-for=\"(img, index) in postContent.content\"\n        :key=\"index\"\n        lazy=\"true\"\n      >\n        <img\n          :src=\"getBestQualityImage(img)\"\n          class=\"communityImage\"\n          alt=\"\"\n          loading=\"lazy\"\n        >\n      </swiper-slide>\n    </swiper-container>\n    <div\n      v-if=\"postType === 'image' && postContent.content.length > 0\"\n    >\n      <img\n        :src=\"getBestQualityImage(postContent.content)\"\n        class=\"communityImage\"\n        alt=\"\"\n      >\n    </div>\n    <div\n      v-if=\"postType === 'video'\"\n    >\n      <FtListVideo\n        v-if=\"!hideVideo\"\n        :data=\"data.postContent.content\"\n        appearance=\"\"\n      />\n      <p\n        v-else\n        class=\"hiddenVideo\"\n      >\n        {{ '[' + $t('Channel.Posts.Video hidden by FreeTube') + ']' }}\n      </p>\n    </div>\n    <div\n      v-if=\"postType === 'poll' || postType === 'quiz'\"\n    >\n      <FtCommunityPoll :data=\"postContent\" />\n    </div>\n    <div\n      v-if=\"postType === 'playlist'\"\n      class=\"playlistWrapper\"\n    >\n      <FtListPlaylist\n        :data=\"postContent.content\"\n        :appearance=\"appearance\"\n      />\n    </div>\n    <div\n      class=\"bottomSection\"\n    >\n      <span\n        class=\"likeCount\"\n        :title=\"$t('Global.Counts.Like Count', {count: formattedVoteCount}, voteCount)\"\n        :aria-label=\"$t('Global.Counts.Like Count', {count: formattedVoteCount}, voteCount)\"\n      >\n        <FontAwesomeIcon\n          class=\"thumbs-up-icon\"\n          :icon=\"['fas', 'thumbs-up']\"\n          aria-hidden=\"true\"\n        /> {{ formattedVoteCount }}</span>\n      <router-link\n        v-if=\"!singlePost\"\n        :to=\"{\n          path: `/post/${postId}`,\n          query: authorId ? { authorId } : undefined\n        }\"\n        class=\"commentsLink\"\n        :aria-label=\"$t('Channel.Posts.View Full Post')\"\n      >\n        <span\n          class=\"commentCount\"\n          :title=\"$t('Global.Counts.Comment Count', {count: formattedCommentCount}, commentCount)\"\n          :aria-label=\"$t('Global.Counts.Comment Count', {count: formattedCommentCount}, commentCount)\"\n        >\n          <FontAwesomeIcon\n            class=\"comment-count-icon\"\n            :icon=\"['fas', 'comment']\"\n            aria-hidden=\"true\"\n          /> {{ formattedCommentCount }}</span>\n      </router-link>\n      <span\n        v-else-if=\"commentCount != null\"\n        class=\"commentCount\"\n        :title=\"$t('Global.Counts.Comment Count', {count: formattedCommentCount}, commentCount)\"\n        :aria-label=\"$t('Global.Counts.Comment Count', {count: formattedCommentCount}, commentCount)\"\n      >\n        <FontAwesomeIcon\n          class=\"comment-count-icon\"\n          :icon=\"['fas', 'comment']\"\n        /> {{ commentCount }}</span>\n      <FtShareButton\n        :id=\"postId\"\n        share-target-type=\"Post\"\n        class=\"shareButton\"\n        :size=\"18\"\n      />\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport autolinker from 'autolinker'\nimport { A11y, Navigation, Pagination } from 'swiper/modules'\nimport { computed, onMounted, useTemplateRef } from 'vue'\n\nimport FtListVideo from '../ft-list-video/ft-list-video.vue'\nimport FtListPlaylist from '../FtListPlaylist/FtListPlaylist.vue'\nimport FtCommunityPoll from '../FtCommunityPoll/FtCommunityPoll.vue'\nimport FtShareButton from '../FtShareButton/FtShareButton.vue'\nimport { vSaferHtml } from '../../directives/vSaferHtml.js'\n\nimport store from '../../store/index'\n\nimport {\n  createWebURL,\n  deepCopy,\n  formatNumber,\n  getRelativeTimeFromDate,\n} from '../../helpers/utils'\nimport { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  appearance: {\n    type: String,\n    required: true\n  },\n  hideForbiddenTitles: {\n    type: Boolean,\n    default: true\n  },\n  singlePost: {\n    type: Boolean,\n    default: false\n  },\n})\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => {\n  return store.getters.getListType\n})\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst forbiddenTitles = computed(() => {\n  if (!props.hideForbiddenTitles) { return [] }\n  return JSON.parse(store.getters.getForbiddenTitles)\n})\n\nconst hideVideo = computed(() => {\n  return forbiddenTitles.value.some((text) => props.data.postContent.content.title?.toLowerCase().includes(text.toLowerCase()))\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\nlet postType = ''\nlet postText = ''\nlet postId = ''\n/** @type {string[]?} */\nlet authorThumbnails = null\nlet postContent = ''\nlet author = ''\nlet authorId = ''\nlet voteCount = 0\n/** @type {number?} */\nlet commentCount = null\n\nparseCommunityData()\n\nconst formattedCommentCount = computed(() => {\n  if (commentCount != null) {\n    return formatNumber(commentCount)\n  }\n\n  return ''\n})\n\nconst formattedVoteCount = computed(() => {\n  return formatNumber(voteCount)\n})\n\nconst publishedText = computed(() => {\n  if (props.data.publishedTime) {\n    return getRelativeTimeFromDate(props.data.publishedTime)\n  }\n\n  return ''\n})\n\nfunction parseCommunityData() {\n  if ('backstagePostThreadRenderer' in props.data) {\n    postText = 'Shared post'\n    postType = 'text'\n\n    authorThumbnails = ['', 'https://yt3.ggpht.com/ytc/AAUvwnjm-0qglHJkAHqLFsCQQO97G7cCNDuDLldsrn25Lg=s88-c-k-c0x00ffffff-no-rj']\n\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      authorThumbnails.forEach(thumbnail => {\n        thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n      })\n    }\n\n    return\n  }\n\n  postText = autolinker.link(props.data.postText)\n  postContent = props.data.postContent\n  postId = props.data.postId\n  voteCount = props.data.voteCount\n  commentCount = props.data.commentCount\n  postType = props.data.postContent?.type ?? 'text'\n  author = props.data.author\n  authorId = props.data.authorId\n\n  authorThumbnails = deepCopy(props.data.authorThumbnails)\n\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    authorThumbnails.forEach(thumbnail => {\n      thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n    })\n  } else {\n    authorThumbnails.forEach(thumbnail => {\n      if (thumbnail.url.startsWith('//')) {\n        thumbnail.url = 'https:' + thumbnail.url\n      }\n    })\n  }\n}\n\n/**\n * @param {{ width: number, height: number, url: string }[]} imageArray\n */\nfunction getBestQualityImage(imageArray) {\n  const imageArrayCopy = Array.from(imageArray)\n  imageArrayCopy.sort((a, b) => {\n    return Number.parseInt(b.width) - Number.parseInt(a.width)\n  })\n\n  // Remove cropping directives when applicable\n  return imageArrayCopy[0]?.url?.replace(/-c-fcrop64=[^-]+/i, '') ?? ''\n}\n\nconst swiperContainerRef = useTemplateRef('swiperContainerRef')\n\nif (postType === 'multiImage' && postContent.content.length > 0) {\n  onMounted(() => {\n    /** @type {import('swiper/element').SwiperContainer} */\n    const swiperOptions = {\n      modules: [A11y, Navigation, Pagination],\n\n      injectStylesUrls: [\n        // This file is created with the copy webpack plugin in the web and renderer webpack configs.\n        // If you add more modules, please remember to add their CSS files to the list in webpack config files.\n        createWebURL(`/swiper-${process.env.SWIPER_VERSION}.css`)\n      ],\n\n      a11y: true,\n      navigation: true,\n      pagination: {\n        enabled: true,\n        clickable: true\n      },\n      slidesPerView: 1\n    }\n\n    Object.assign(swiperContainerRef.value, swiperOptions)\n\n    swiperContainerRef.value.initialize()\n  })\n}\n</script>\n\n<style scoped src=\"./FtCommunityPost.scss\" lang=\"scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtCreatePlaylistPrompt/FtCreatePlaylistPrompt.css",
    "content": ".playlistNameInput {\n  inline-size: 80%;\n  max-inline-size: 600px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtCreatePlaylistPrompt/FtCreatePlaylistPrompt.vue",
    "content": "<template>\n  <FtPrompt\n    :label=\"title\"\n    @click=\"hideCreatePlaylistPrompt\"\n  >\n    <FtFlexBox>\n      <FtInput\n        ref=\"playlistNameInput\"\n        :placeholder=\"$t('User Playlists.Playlist Name')\"\n        :show-action-button=\"false\"\n        :show-label=\"false\"\n        :value=\"playlistName\"\n        :maxlength=\"255\"\n        class=\"playlistNameInput\"\n        @input=\"handlePlaylistNameInput\"\n        @click=\"createNewPlaylist\"\n      />\n    </FtFlexBox>\n    <FtFlexBox v-if=\"playlistNameBlank\">\n      <p>\n        {{ $t('User Playlists.SinglePlaylistView.Toast[\"Playlist name cannot be empty. Please input a name.\"]') }}\n      </p>\n    </FtFlexBox>\n    <FtFlexBox v-if=\"playlistWithNameExists\">\n      <p>\n        {{ $t('User Playlists.CreatePlaylistPrompt.Toast[\"There is already a playlist with this name. Please pick a different name.\"]') }}\n      </p>\n    </FtFlexBox>\n    <FtFlexBox>\n      <FtButton\n        :label=\"$t('User Playlists.CreatePlaylistPrompt.Create')\"\n        :disabled=\"playlistPersistenceDisabled\"\n        @click=\"createNewPlaylist\"\n      />\n      <FtButton\n        :label=\"$t('User Playlists.Cancel')\"\n        :text-color=\"null\"\n        :background-color=\"null\"\n        @click=\"hideCreatePlaylistPrompt\"\n      />\n    </FtFlexBox>\n  </FtPrompt>\n</template>\n\n<script setup>\nimport { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\n\nimport store from '../../store/index'\n\nimport { showToast } from '../../helpers/utils'\n\nconst { t } = useI18n()\n\nconst title = computed(() => t('User Playlists.CreatePlaylistPrompt.New Playlist Name'))\n\n/** @type {import('vue').ComputedRef<object[]>} */\nconst allPlaylists = computed(() => store.getters.getAllPlaylists)\n\n/** @type {import('vue').Ref<string>} */\nconst playlistName = ref(store.getters.getNewPlaylistVideoObject.title)\n\nconst playlistNameBlank = computed(() => {\n  return playlistName.value !== '' && playlistName.value.trim() === ''\n})\n\nconst playlistWithNameExists = computed(() => {\n  const playlistName_ = playlistName.value\n\n  if (playlistName_ === '') {\n    return false\n  }\n\n  return allPlaylists.value.some((playlist) => playlist.playlistName === playlistName_)\n})\n\nconst playlistPersistenceDisabled = computed(() => {\n  return playlistName.value === '' || playlistNameBlank.value || playlistWithNameExists.value\n})\n\nconst playlistNameInput = useTemplateRef('playlistNameInput')\n\nonMounted(() => {\n  // Faster to input required playlist name\n  nextTick(() => playlistNameInput.value?.focus())\n})\n\n/**\n * @param {string} input\n */\nfunction handlePlaylistNameInput(input) {\n  const trimmed = input.trim()\n\n  // Need to show message for blank input\n  playlistName.value = trimmed === '' ? input : trimmed\n}\n\nasync function createNewPlaylist() {\n  // It is still possible to attempt to create via pressing enter\n  if (playlistPersistenceDisabled.value) { return }\n\n  const playlistObject = {\n    playlistName: playlistName.value,\n    protected: false,\n    description: '',\n    videos: [],\n  }\n\n  try {\n    await store.dispatch('addPlaylist', playlistObject)\n    showToast(t('User Playlists.CreatePlaylistPrompt.Toast[\"Playlist {playlistName} has been successfully created.\"]', {\n      playlistName: playlistName.value,\n    }))\n  } catch (e) {\n    showToast(t('User Playlists.CreatePlaylistPrompt.Toast[\"There was an issue with creating the playlist.\"]'))\n    console.error(e)\n  } finally {\n    hideCreatePlaylistPrompt()\n  }\n}\n\nfunction hideCreatePlaylistPrompt() {\n  store.commit('setShowCreatePlaylistPrompt', false)\n}\n</script>\n\n<style scoped src=\"./FtCreatePlaylistPrompt.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtElementList/FtElementList.css",
    "content": ".maxWidth {\n  inline-size: 100%;\n}\n"
  },
  {
    "path": "src/renderer/components/FtElementList/FtElementList.vue",
    "content": "<template>\n  <FtAutoGrid\n    :grid=\"displayValue !== 'list'\"\n  >\n    <FtListLazyWrapper\n      v-for=\"(result, index) in data\"\n      :key=\"`${dataType || result.type}-${result.videoId || result.playlistId || result.postId || result.id || result._id || result.authorId || result.title}-${result.playlistItemId || index}-${result.lastUpdatedAt || 0}`\"\n      appearance=\"result\"\n      :data=\"result\"\n      :data-type=\"dataType || result.type\"\n      :first-screen=\"index < 16\"\n      :layout=\"displayValue\"\n      :show-video-with-last-viewed-playlist=\"showVideoWithLastViewedPlaylist\"\n      :use-channels-hidden-preference=\"useChannelsHiddenPreference\"\n      :hide-forbidden-titles=\"hideForbiddenTitles\"\n      :always-show-add-to-playlist-button=\"alwaysShowAddToPlaylistButton\"\n      :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n      :can-move-video-up=\"canMoveVideoUp && index > 0\"\n      :can-move-video-down=\"canMoveVideoDown && index < playlistItemsLength - 1\"\n      :can-remove-from-playlist=\"canRemoveFromPlaylist\"\n      :search-query-text=\"searchQueryText\"\n      :playlist-id=\"playlistId\"\n      :playlist-type=\"playlistType\"\n      :playlist-item-id=\"result.playlistItemId\"\n      @move-video-up=\"moveVideoUp\"\n      @move-video-down=\"moveVideoDown\"\n      @remove-from-playlist=\"removeFromPlaylist\"\n    />\n  </FtAutoGrid>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport FtAutoGrid from '../FtAutoGrid/FtAutoGrid.vue'\nimport FtListLazyWrapper from '../FtListLazyWrapper/FtListLazyWrapper.vue'\n\nimport store from '../../store/index'\n\nconst props = defineProps({\n  data: {\n    type: Array,\n    required: true\n  },\n  dataType: {\n    type: String,\n    default: null,\n  },\n  display: {\n    type: String,\n    required: false,\n    default: ''\n  },\n  showVideoWithLastViewedPlaylist: {\n    type: Boolean,\n    default: false\n  },\n  useChannelsHiddenPreference: {\n    type: Boolean,\n    default: true,\n  },\n  hideForbiddenTitles: {\n    type: Boolean,\n    default: true\n  },\n  searchQueryText: {\n    type: String,\n    required: false,\n    default: '',\n  },\n  alwaysShowAddToPlaylistButton: {\n    type: Boolean,\n    default: false,\n  },\n  quickBookmarkButtonEnabled: {\n    type: Boolean,\n    default: true,\n  },\n  canMoveVideoUp: {\n    type: Boolean,\n    default: false,\n  },\n  canMoveVideoDown: {\n    type: Boolean,\n    default: false,\n  },\n  canRemoveFromPlaylist: {\n    type: Boolean,\n    default: false,\n  },\n  playlistItemsLength: {\n    type: Number,\n    default: 0\n  },\n  playlistId: {\n    type: String,\n    default: null\n  },\n  playlistType: {\n    type: String,\n    default: null\n  },\n})\n\nconst emit = defineEmits(['move-video-down', 'move-video-up', 'remove-from-playlist'])\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => {\n  return store.getters.getListType\n})\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst displayValue = computed(() => {\n  return props.display === '' ? listType.value : props.display\n})\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoUp(videoId, playlistItemId) {\n  emit('move-video-up', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoDown(videoId, playlistItemId) {\n  emit('move-video-down', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction removeFromPlaylist(videoId, playlistItemId) {\n  emit('remove-from-playlist', videoId, playlistItemId)\n}\n</script>\n\n<style scoped src=\"./FtElementList.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtIconButton/FtIconButton.scss",
    "content": "/* stylelint-disable no-descending-specificity */\n.ftIconButton {\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: space-evenly;\n  position: relative;\n  line-height: normal;\n  user-select: none;\n}\n\n.iconButton {\n  background-color: transparent;\n  border-radius: 50%;\n  border-style: none;\n  color: inherit;\n  cursor: pointer;\n  line-height: 1em;\n  transition: background 0.15s ease-out;\n\n  &.shadow {\n    box-shadow: 0 1px 2px rgb(0 0 0 / 50%);\n  }\n\n  &.base {\n    background-color: var(--card-bg-color);\n    color: var(--primary-text-color);\n\n    &:not(.disabled) {\n      &:hover,\n      &:focus-visible,\n      &.pressed {\n        background-color: var(--side-nav-hover-color);\n        color: var(--side-nav-hover-text-color);\n      }\n\n      &.active {\n        background-color: var(--side-nav-active-color);\n        color: var(--side-nav-active-text-color);\n      }\n    }\n  }\n\n  &.base-no-default:not(.disabled) {\n    &:hover,\n    &:focus-visible,\n    &.pressed {\n      background-color: var(--side-nav-hover-color);\n      color: var(--side-nav-hover-text-color);\n    }\n\n    &.active {\n      background-color: var(--side-nav-active-color);\n      color: var(--side-nav-active-text-color);\n    }\n  }\n\n  &.primary {\n    background-color: var(--primary-color);\n    color: var(--text-with-main-color);\n\n    &:not(.disabled) {\n      &:hover,\n      &:focus-visible,\n      &.pressed {\n        background-color: var(--primary-color-hover);\n      }\n\n      &.active {\n        background-color: var(--primary-color-active);\n      }\n    }\n  }\n\n\n  &.secondary {\n    background-color: var(--accent-color);\n    color: var(--text-with-accent-color);\n\n    &:not(.disabled) {\n      &:hover,\n      &:focus-visible,\n      &.pressed {\n        background-color: var(--accent-color-hover);\n      }\n\n      &.active {\n        background-color: var(--accent-color-active);\n      }\n    }\n  }\n\n  &.destructive {\n    background-color: var(--destructive-color);\n    color: var(--destructive-text-color);\n\n    &:not(.disabled) {\n      &:hover,\n      &:focus-visible,\n      &.pressed {\n        background-color: var(--destructive-hover-color);\n      }\n\n      &.active {\n        background-color: var(--destructive-active-color);\n      }\n    }\n  }\n\n  &.favorite,\n  &.favorite:hover,\n  &.favorite:focus-visible {\n    color: var(--favorite-icon-color);\n\n    &:not(.disabled) {\n      color: var(--favorite-icon-color);\n    }\n  }\n}\n\n.icon {\n  inline-size: 1em;\n}\n\n.disabled {\n  opacity: 0.5;\n  pointer-events: auto;\n  cursor: default;\n  user-select: none;\n}\n\n.iconDropdown {\n  background-color: var(--side-nav-color);\n  box-shadow: 0 1px 2px rgb(0 0 0 / 50%);\n  color: var(--secondary-text-color);\n  display: inline;\n  font-size: 12px;\n  list-style-type: none;\n  position: absolute;\n  text-align: center;\n  user-select: none;\n  z-index: 3;\n\n  &.left {\n    inset-inline-end: calc(50% - 10px);\n  }\n\n  &.right {\n    inset-inline-start: calc(50% - 10px);\n  }\n\n  &.top {\n    inset-block-end: 45px;\n  }\n\n  &.bottom {\n    inset-block-start: 45px;\n  }\n\n  .list {\n    list-style-type: none;\n    margin: 0;\n    padding: 0;\n  }\n\n  :has(.active) {\n    .checkmarkColumn {\n      min-inline-size: 12px;\n    }\n\n    .listItem {\n      display: flex;\n      gap: 6px;\n    }\n  }\n\n  .listItem {\n    cursor: pointer;\n    margin: 0;\n    padding-block: 8px;\n    padding-inline: 10px;\n    transition: background 0.2s ease-out;\n    white-space: nowrap;\n\n    &:hover,\n    &:focus-visible,\n    &.pressed,\n    &.active {\n      background-color: var(--side-nav-hover-color);\n      color: var(--side-nav-hover-text-color);\n      transition: background 0.2s ease-in;\n    }\n\n    &.active {\n      font-weight: 600;\n      display: flex;\n      gap: 6px;\n    }\n\n    &:active {\n      background-color: var(--side-nav-active-color);\n      color: var(--side-nav-active-text-color);\n      transition: background 0.1s ease-in;\n    }\n  }\n\n  .listItemDivider {\n    border-block-start: 1px solid var(--tertiary-text-color);\n    margin-block: 1px;\n    margin-inline: auto;\n    // Too \"visible\" with current color\n    opacity: 0.5;\n    inline-size: 95%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtIconButton/FtIconButton.vue",
    "content": "<template>\n  <div\n    ref=\"ftIconButton\"\n    class=\"ftIconButton\"\n    @focusout=\"handleDropdownFocusOut\"\n  >\n    <button\n      class=\"iconButton\"\n      :aria-label=\"title\"\n      :title=\"title\"\n      :class=\"{\n        [theme]: true,\n        shadow: useShadow,\n        pressed: openOnRightOrLongClick && dropdownShown,\n        disabled\n      }\"\n      :style=\"{\n        padding: padding + 'px',\n        fontSize: size + 'px'\n      }\"\n      :aria-disabled=\"disabled\"\n      :aria-expanded=\"dropdownShown\"\n      @pointerdown=\"handleIconPointerDown\"\n      @contextmenu.prevent\n      @click=\"handleIconClick\"\n    >\n      <FontAwesomeIcon\n        class=\"icon\"\n        :icon=\"icon\"\n      />\n    </button>\n    <template\n      v-if=\"dropdownShown\"\n    >\n      <FtPrompt\n        v-if=\"useModal\"\n        :autosize=\"true\"\n        :label=\"title\"\n        @click=\"dropdownShown = false\"\n      >\n        <slot>\n          <ul\n            v-if=\"dropdownOptions.length > 0\"\n            class=\"list\"\n            role=\"listbox\"\n          >\n            <li\n              v-for=\"(option, index) in dropdownOptions\"\n              :id=\"id + '-' + index\"\n              :key=\"index\"\n              role=\"option\"\n              :aria-selected=\"option.active\"\n              tabindex=\"-1\"\n              :class=\"{\n                listItemDivider: option.type === 'divider',\n                listItem: option.type !== 'divider',\n                active: option.active\n              }\"\n              @click=\"handleDropdownClick(option.value)\"\n              @keydown.enter=\"handleDropdownClick(option.value)\"\n              @keydown.space=\"handleDropdownClick(option.value)\"\n            >\n              {{ option.type === 'divider' ? '' : option.label }}\n            </li>\n          </ul>\n        </slot>\n      </FtPrompt>\n      <div\n        v-else\n        ref=\"dropdown\"\n        tabindex=\"-1\"\n        class=\"iconDropdown\"\n        :class=\"{\n          left: dropdownPositionX === 'left',\n          right: dropdownPositionX === 'right',\n          center: dropdownPositionX === 'center',\n          bottom: dropdownPositionY === 'bottom',\n          top: dropdownPositionY === 'top'\n        }\"\n        @keydown.esc.stop=\"handleDropdownEscape\"\n      >\n        <slot>\n          <ul\n            v-if=\"dropdownOptions.length > 0\"\n            class=\"list\"\n            role=\"listbox\"\n          >\n            <li\n              v-for=\"(option, index) in dropdownOptions\"\n              :id=\"id + index\"\n              :key=\"index\"\n              :role=\"option.type === 'divider' ? 'separator' : 'option'\"\n              :aria-selected=\"option.active\"\n              :tabindex=\"option.type === 'divider' ? '-1' : '0'\"\n              :class=\"{\n                listItemDivider: option.type === 'divider',\n                listItem: option.type !== 'divider',\n                active: option.active\n              }\"\n              @click=\"handleDropdownClick(option.value)\"\n              @keydown.enter=\"handleDropdownClick(option.value)\"\n              @keydown.space=\"handleDropdownClick(option.value)\"\n            >\n              <div class=\"checkmarkColumn\">\n                <FontAwesomeIcon\n                  v-if=\"option.active\"\n                  :icon=\"['fas', 'check']\"\n                />\n              </div>\n              {{ option.type === 'divider' ? '' : option.label }}\n            </li>\n          </ul>\n        </slot>\n      </div>\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, useTemplateRef } from 'vue'\n\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\n\nconst props = defineProps({\n  title: {\n    type: String,\n    default: ''\n  },\n  icon: {\n    type: Array,\n    default: () => ['fas', 'ellipsis-v']\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n  theme: {\n    type: String,\n    default: 'base'\n  },\n  useShadow: {\n    type: Boolean,\n    default: true\n  },\n  padding: {\n    type: Number,\n    default: 10\n  },\n  size: {\n    type: Number,\n    default: 20\n  },\n  forceDropdown: {\n    type: Boolean,\n    default: false\n  },\n  dropdownPositionX: {\n    type: String,\n    default: 'center'\n  },\n  dropdownPositionY: {\n    type: String,\n    default: 'bottom'\n  },\n  dropdownOptions: {\n    // Array of objects with these properties\n    // - type: ('labelValue'|'divider', default to 'labelValue' for less typing)\n    // - label: String (if type === 'labelValue')\n    // - value: String (if type === 'labelValue')\n    // - (OPTIONAL) active: Number (if type === 'labelValue')\n    type: Array,\n    default: () => []\n  },\n  dropdownModalOnMobile: {\n    type: Boolean,\n    default: false\n  },\n  openOnRightOrLongClick: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst emit = defineEmits(['click', 'disabled-click'])\n\nconst LONG_CLICK_BOUNDARY_MS = 500\n\nconst id = useId()\n\nconst dropdownShown = ref(false)\nconst useModal = ref(false)\n\nlet blockLeftClick = false\nlet longPressTimer = null\n\nif (props.dropdownModalOnMobile) {\n  onMounted(() => {\n    useModal.value = window.innerWidth <= 900\n    window.addEventListener('resize', handleResize)\n  })\n\n  onBeforeUnmount(() => {\n    window.removeEventListener('resize', handleResize)\n  })\n}\n\nconst dropdown = useTemplateRef('dropdown')\n\n/**\n * @param {PointerEvent | null} e\n * @param {boolean} isRightOrLongClick\n */\nfunction handleIconClick(e, isRightOrLongClick = false) {\n  if (props.disabled) {\n    emit('disabled-click')\n    return\n  }\n\n  if (blockLeftClick) {\n    return\n  }\n\n  if (longPressTimer != null) {\n    clearTimeout(longPressTimer)\n    longPressTimer = null\n  }\n\n  if ((!props.openOnRightOrLongClick || (props.openOnRightOrLongClick && isRightOrLongClick)) &&\n    (props.forceDropdown || props.dropdownOptions.length > 0)) {\n    dropdownShown.value = !dropdownShown.value\n    if (dropdownShown.value && !useModal.value) {\n      // wait until the dropdown is visible\n      // then focus it so we can hide it automatically when it loses focus\n      nextTick(() => {\n        dropdown.value?.focus()\n      })\n    }\n  } else {\n    emit('click')\n  }\n}\n\n/**\n * @param {PointerEvent} event\n */\nfunction handleIconPointerDown(event) {\n  if (!props.openOnRightOrLongClick) {\n    return\n  }\n\n  if (event.button === 2) { // right button click\n    handleIconClick(null, true)\n  } else if (event.button === 0) { // left button click\n    longPressTimer = setTimeout(() => {\n      handleIconClick(null, true)\n\n      // prevent a long press that ends on the icon button from firing the handleIconClick handler\n      window.addEventListener('pointerup', preventButtonClickAfterLongPress, { once: true })\n      window.addEventListener('pointercancel', () => {\n        window.removeEventListener('pointerup', preventButtonClickAfterLongPress)\n      }, { once: true })\n    }, LONG_CLICK_BOUNDARY_MS)\n  }\n}\n\nfunction preventButtonClickAfterLongPress() {\n  blockLeftClick = true\n\n  setTimeout(() => {\n    blockLeftClick = false\n  }, 0)\n}\n\nconst ftIconButton = useTemplateRef('ftIconButton')\n\nfunction handleDropdownFocusOut() {\n  if (!useModal.value && dropdownShown.value && !ftIconButton.value?.matches(':focus-within')) {\n    dropdownShown.value = false\n  }\n}\n\nfunction handleDropdownEscape() {\n  dropdownShown.value = false\n  ftIconButton.value?.firstElementChild?.focus()\n}\n\nfunction handleDropdownClick(value) {\n  emit('click', value)\n\n  dropdownShown.value = false\n}\n\nfunction handleResize() {\n  useModal.value = window.innerWidth <= 900\n}\n\ndefineExpose({\n  dropdownShown: computed(() => dropdownShown.value),\n\n  hideDropdown: () => {\n    dropdownShown.value = false\n  }\n})\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtIconButton.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtInput/FtInput.css",
    "content": "/* stylelint-disable no-descending-specificity */\n.ft-input-component {\n  position: relative;\n}\n\nbody[dir='rtl'] .ft-input-component.search.showClearTextButton .inputAction {\n  inset-inline-end: -30px;\n}\n\nbody[dir='rtl'] .ft-input-component.search.clearTextButtonVisible .inputAction,\nbody[dir='rtl'] .ft-input-component.search.showClearTextButton:focus-within .inputAction {\n  inset-inline-end: 0;\n}\n\n.ft-input-component.search.showClearTextButton {\n  padding-inline-start: 30px;\n}\n\n.ft-input-component.search.clearTextButtonVisible,\n.ft-input-component.search.showClearTextButton:focus-within {\n  padding-inline-start: 0;\n}\n\n.ft-input-component.showClearTextButton:not(.search) .ft-input {\n  padding-inline-start: 46px;\n}\n\n/* Main search input */\n.clearTextButtonVisible.search .ft-input,\n.ft-input-component.search.showClearTextButton:focus-within .ft-input {\n  padding-inline-start: 46px;\n}\n\n.ft-input-component:focus-within .clearInputTextButton,\n.ft-input-component.showOptions .clearInputTextButton {\n  opacity: 0.5;\n}\n\n\n.ft-input-component.inputDataPresent .clearInputTextButton.visible,\n.clearTextButtonVisible:not(.showOptions) .clearInputTextButton.visible,\n.ft-input-component:focus-within:not(.showOptions) .clearInputTextButton.visible {\n  cursor: pointer;\n  opacity: 1;\n}\n\n.disabled {\n  opacity: 0.4;\n  cursor: not-allowed;\n}\n\n.clearInputTextButton {\n  position: absolute;\n  inset-block-start: 5px;\n  inset-inline-start: 0;\n\n  /* To be higher than `.inputWrapper` */\n  z-index: 1;\n  margin-block: 0;\n  margin-inline: 3px;\n  padding: 10px;\n  border-radius: 100%;\n  border-style: none;\n  background-color: transparent;\n  color: var(--primary-text-color);\n  font-size: 1em;\n  line-height: 1em;\n  opacity: 0;\n  transition: background 0.2s ease-in;\n}\n\n.clearInputTextButton.visible:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n}\n\n.forceTextColor .clearInputTextButton:hover {\n  background-color: var(--primary-color-hover);\n}\n\n.clearInputTextButton.visible:active {\n  background-color: var(--tertiary-text-color);\n  color: var(--side-nav-active-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.search .clearInputTextButton {\n  inset-block-start: 12px;\n}\n\n.forceTextColor .clearInputTextButton {\n  color: #eee;\n}\n\n.forceTextColor .clearInputTextButton:active {\n  background-color: var(--primary-color-active);\n}\n\n.ft-input {\n  box-sizing: border-box;\n  outline: none;\n  inline-size: 100%;\n  padding: 1rem;\n  border: 0;\n  margin-block-end: 10px;\n  font-size: 16px;\n  block-size: 45px;\n  color: var(--secondary-text-color);\n  border-radius: 5px;\n  background-color: var(--search-bar-color);\n}\n\n.ftcomponent ::placeholder {\n  color: var(--tertiary-text-color);\n  user-select: none;\n}\n\n.forceTextColor .ft-input {\n  color: #eee;\n  background-color: var(--primary-input-color);\n}\n\n.forceTextColor .ft-input:focus {\n  box-shadow: 0 0 1rem 0 var(--primary-input-color);\n  transition: box-shadow 0.2s ease-in-out;\n}\n\n.forceTextColor ::placeholder {\n  color: #eee;\n}\n\n.inputWrapper {\n  position: relative;\n}\n\n.buttonIcon {\n  inline-size: 1em;\n}\n\n.inputAction {\n  position: absolute;\n  margin-block: 0;\n  margin-inline: 3px;\n  padding: 10px;\n  inset-block-start: -8px;\n  inset-inline-end: 0;\n  border-style: none;\n  border-radius: 100%;\n  background-color: transparent;\n  color: var(--primary-text-color);\n  font-size: 1em;\n  line-height: 1em;\n\n  /* this should look disabled by default */\n  opacity: 0.5;\n}\n\n.inputAction.enabled {\n  opacity: 1;\n\n  /* Only look respond to cursor when enabled */\n  cursor: pointer;\n}\n\n\n.search ::-webkit-calendar-picker-indicator {\n  display: none;\n}\n\n.forceTextColor .inputAction {\n  color: #eee;\n}\n\n.ft-input-component.showActionButton .ft-input {\n  /*\n  With arrow present means\n  the text might get under the arrow with normal padding\n   */\n  padding-inline-end: calc(36px + 6px);\n}\n\n.inputAction.enabled:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.forceTextColor .inputAction.enabled:hover {\n  background-color: var(--primary-color-hover);\n}\n\n.inputAction.enabled:active {\n  background-color: var(--tertiary-text-color);\n  color: var(--side-nav-active-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.forceTextColor .inputAction.enabled:active {\n  background-color: var(--primary-color-active);\n}\n\n.list {\n  position: absolute;\n  inline-size: 100%;\n  list-style: none;\n  margin: 0;\n  padding-block: 5px;\n  padding-inline: 0;\n  z-index: 10;\n  border-radius: 0 0 5px 5px;\n  overflow-wrap: break-word;\n  box-shadow: 0 0 10px var(--scrollbar-color-hover);\n  background-color: var(--search-bar-color);\n}\n\n.list li {\n  display: flex;\n  justify-content: space-between;\n  padding-block: 0;\n  line-height: 2rem;\n  padding-inline: 15px;\n}\n\n.optionWrapper {\n  display: flex;\n  align-items: baseline;\n  overflow: hidden;\n}\n\n.optionWrapper span {\n  overflow: hidden;\n}\n\n.searchResultIcon {\n  opacity: 0.6;\n  padding-inline-end: 10px;\n  inline-size: 16px;\n  block-size: 16px;\n}\n\n.removeButton {\n  text-decoration: none;\n  float: inline-end;\n  font-size: 13px;\n}\n\n.removeButton:hover,\n.removeButtonSelected {\n  text-decoration: underline;\n  font-weight: bold;\n}\n\n.hover {\n  background-color: var(--scrollbar-color-hover);\n  color: var(--scrollbar-text-color-hover);\n}\n"
  },
  {
    "path": "src/renderer/components/FtInput/FtInput.vue",
    "content": "<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->\n<template>\n  <div\n    class=\"ft-input-component\"\n    :class=\"{\n      search: isSearch,\n      forceTextColor,\n      showActionButton,\n      showClearTextButton,\n      clearTextButtonVisible: inputDataPresent || showOptions,\n      inputDataPresent,\n      showOptions\n    }\"\n  >\n    <label\n      v-if=\"showLabel\"\n      :for=\"id\"\n      class=\"selectLabel\"\n      :class=\"{ disabled }\"\n    >\n      {{ label || placeholder }}\n      <FtTooltip\n        v-if=\"tooltip !== ''\"\n        class=\"selectTooltip\"\n        position=\"bottom\"\n        :tooltip=\"tooltip\"\n      />\n    </label>\n    <button\n      v-if=\"showClearTextButton\"\n      class=\"clearInputTextButton\"\n      :class=\"{\n        visible: inputDataPresent || showOptions\n      }\"\n      :aria-label=\"t('Search Bar.Clear Input')\"\n      :title=\"t('Search Bar.Clear Input')\"\n      @click=\"handleClearTextClick\"\n    >\n      <FontAwesomeIcon\n        class=\"buttonIcon\"\n        :icon=\"['fas', 'times-circle']\"\n      />\n    </button>\n    <span class=\"inputWrapper\">\n      <input\n        :id=\"id\"\n        ref=\"inputRef\"\n        :value=\"inputDataDisplayed\"\n        class=\"ft-input\"\n        :class=\"{ disabled }\"\n        :maxlength=\"maxlength\"\n        :type=\"inputType\"\n        :placeholder=\"placeholder\"\n        :disabled=\"disabled\"\n        :spellcheck=\"false\"\n        :aria-label=\"showLabel ? null : placeholder\"\n        @input=\"handleInput\"\n        @focus=\"handleFocus\"\n        @blur=\"handleInputBlur\"\n        @keydown=\"handleKeyDown\"\n      >\n      <button\n        v-if=\"showActionButton\"\n        class=\"inputAction\"\n        :class=\"{\n          enabled: inputDataPresent,\n          withLabel: showLabel\n        }\"\n        @click=\"handleClick\"\n      >\n        <FontAwesomeIcon\n          class=\"buttonIcon\"\n          :icon=\"actionButtonIconName\"\n        />\n      </button>\n    </span>\n    <div class=\"options\">\n      <ul\n        v-if=\"showOptions\"\n        class=\"list\"\n        @mouseenter=\"searchState.isPointerInList = true\"\n        @mouseleave=\"searchState.isPointerInList = false\"\n      >\n        <!-- eslint-disable vuejs-accessibility/click-events-have-key-events -->\n        <li\n          v-for=\"(entry, index) in visibleDataList\"\n          :key=\"index\"\n          :class=\"{ hover: searchState.selectedOption === index }\"\n          @click=\"handleOptionClick(index)\"\n          @mouseenter=\"searchState.selectedOption = index\"\n          @mouseleave=\"resetSelectedOption\"\n        >\n          <div class=\"optionWrapper\">\n            <FontAwesomeIcon\n              v-if=\"dataListProperties[index]?.iconName\"\n              :icon=\"['fas', dataListProperties[index].iconName]\"\n              class=\"searchResultIcon\"\n            />\n            <bdi>{{ entry }}</bdi>\n          </div>\n          <a\n            v-if=\"dataListProperties[index]?.isRemoveable\"\n            class=\"removeButton\"\n            :class=\"{ removeButtonSelected: removeButtonSelectedIndex === index }\"\n            role=\"button\"\n            :aria-label=\"t('Search Bar.Remove')\"\n            href=\"javascript:void(0)\"\n            @click.prevent.stop=\"handleRemoveClick(index)\"\n          >\n            {{ t('Search Bar.Remove') }}\n          </a>\n        </li>\n        <!-- skipped -->\n      </ul>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, reactive, ref, shallowRef, useId, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtTooltip from '../FtTooltip/FtTooltip.vue'\n\nimport store from '../../store/index'\n\nimport { isKeyboardEventKeyPrintableChar, isNullOrEmpty } from '../../helpers/strings'\n\nconst { t } = useI18n()\n\nconst props = defineProps({\n  inputType: {\n    type: String,\n    default: 'text'\n  },\n  placeholder: {\n    type: String,\n    required: true\n  },\n  label: {\n    type: String,\n    default: null\n  },\n  maxlength: {\n    type: Number,\n    default: null\n  },\n  value: {\n    type: String,\n    default: ''\n  },\n  showActionButton: {\n    type: Boolean,\n    default: true\n  },\n  forceActionButtonIconName: {\n    type: Array,\n    default: null\n  },\n  showClearTextButton: {\n    type: Boolean,\n    default: false\n  },\n  showLabel: {\n    type: Boolean,\n    default: false\n  },\n  isSearch: {\n    type: Boolean,\n    default: false\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n  dataList: {\n    type: Array,\n    default: () => []\n  },\n  dataListProperties: {\n    type: Array,\n    default: () => []\n  },\n  searchResultIconNames: {\n    type: Array,\n    default: null\n  },\n  showDataWhenEmpty: {\n    type: Boolean,\n    default: false\n  },\n  tooltip: {\n    type: String,\n    default: ''\n  }\n})\n\nconst emit = defineEmits(['clear', 'click', 'input', 'remove'])\n\nconst id = useId()\n\nconst inputRef = useTemplateRef('inputRef')\n\nconst inputData = ref(props.value)\nconst searchState = reactive({\n  showOptions: false,\n  selectedOption: -1,\n  isPointerInList: false,\n  keyboardSelectedOptionIndex: -1\n})\nconst visibleDataList = ref(props.dataList)\nconst removeButtonSelectedIndex = ref(-1)\nconst removalMade = ref(false)\nconst actionButtonIconName = shallowRef(props.forceActionButtonIconName ?? ['fas', 'search'])\n\nconst showOptions = computed(() => {\n  return (inputData.value !== '' || props.showDataWhenEmpty) && visibleDataList.value.length > 0 && searchState.showOptions\n})\n\nconst forceTextColor = computed(() => props.isSearch && store.getters.getBarColor)\n\nconst searchStateKeyboardSelectedOptionValue = computed(() => {\n  return searchState.keyboardSelectedOptionIndex === -1\n    ? null\n    : visibleDataList.value[searchState.keyboardSelectedOptionIndex]\n})\n\nconst inputDataDisplayed = computed(() => {\n  if (!props.isSearch) { return inputData.value }\n\n  /** @type {string | null | undefined} */\n  const selectedOptionValue = searchStateKeyboardSelectedOptionValue.value\n  if (selectedOptionValue != null && selectedOptionValue !== '') {\n    return selectedOptionValue\n  }\n\n  return inputData.value\n})\n\nconst inputDataPresent = computed(() => inputDataDisplayed.value.length > 0)\n\nwatch(() => props.dataList, updateVisibleDataList, { deep: true })\nwatch(inputData, updateVisibleDataList)\nwatch(() => props.value, (value) => {\n  inputData.value = value\n})\n\nupdateVisibleDataList()\n\n/**\n * @param {KeyboardEvent | MouseEvent} [event]\n */\nfunction handleClick(event) {\n  const selectedValue = searchStateKeyboardSelectedOptionValue.value\n  const query = (selectedValue != null && selectedValue !== '') ? selectedValue : inputData.value\n  inputData.value = query\n\n  // No action if no input text\n  if (!inputDataPresent.value) {\n    return\n  }\n\n  searchState.showOptions = false\n  searchState.selectedOption = -1\n  searchState.keyboardSelectedOptionIndex = -1\n  removeButtonSelectedIndex.value = -1\n\n  emit('input', query)\n  emit('click', query, { event })\n}\n\n/**\n * @param {string | InputEvent} data\n */\nfunction handleInput(data) {\n  const text = typeof data === 'string' ? data : inputRef.value.value\n  inputData.value = text\n\n  if (\n    props.isSearch &&\n    searchState.selectedOption !== -1 &&\n    inputData.value === visibleDataList.value[searchState.selectedOption]\n  ) {\n    return\n  }\n\n  handleActionIconChange()\n  emit('input', text)\n}\n\nfunction handleClearTextClick() {\n  // No action if no input text\n  if (!inputDataPresent.value) { return }\n\n  inputData.value = ''\n  handleActionIconChange()\n  updateVisibleDataList()\n  searchState.isPointerInList = false\n\n  inputRef.value.value = ''\n\n  // Focus on input element after text is clear for better UX\n  inputRef.value.focus()\n\n  emit('clear')\n}\n\nasync function handleActionIconChange() {\n  // Only need to update icon if visible\n  if (!props.showActionButton) { return }\n\n  if (!inputDataPresent.value && props.forceActionButtonIconName === null) {\n    // Change back to default icon if text is blank\n    actionButtonIconName.value = ['fas', 'search']\n    return\n  }\n\n  // Update action button icon according to input\n  try {\n    const result = await store.dispatch('getYoutubeUrlInfo', inputData.value)\n\n    let isYoutubeLink = false\n\n    switch (result.urlType) {\n      case 'video':\n      case 'playlist':\n      case 'search':\n      case 'channel':\n      case 'hashtag':\n      case 'post':\n      case 'trending':\n      case 'subscriptions':\n      case 'history':\n      case 'userplaylists':\n        isYoutubeLink = true\n        break\n\n      case 'invalid_url':\n      default: {\n        // isYoutubeLink is already `false`\n      }\n    }\n\n    if (props.forceActionButtonIconName === null) {\n      if (isYoutubeLink) {\n        // Go to URL (i.e. Video/Playlist/Channel\n        actionButtonIconName.value = ['fas', 'arrow-right']\n      } else {\n        // Search with text\n        actionButtonIconName.value = ['fas', 'search']\n      }\n    }\n  } catch (ex) {\n    // On exception, consider text as invalid URL\n    if (props.forceActionButtonIconName === null) {\n      actionButtonIconName.value = ['fas', 'search']\n    }\n\n    // Rethrow exception\n    throw ex\n  }\n}\n\n/**\n * @param {number} index\n */\nfunction handleOptionClick(index) {\n  if (removeButtonSelectedIndex.value !== -1) {\n    handleRemoveClick(index)\n    return\n  }\n\n  searchState.showOptions = false\n  inputData.value = visibleDataList.value[index]\n  emit('input', inputData.value)\n  handleClick()\n}\n\nfunction resetSelectedOption() {\n  searchState.selectedOption = -1\n  removeButtonSelectedIndex.value = -1\n}\n\n/**\n * @param {number} index\n */\nfunction handleRemoveClick(index) {\n  if (!props.dataListProperties[index]?.isRemoveable) { return }\n\n  // keep input in focus even when the to-be-removed \"Remove\" button was clicked\n  inputRef.value.focus()\n  removalMade.value = true\n  emit('remove', visibleDataList.value[index])\n}\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction handleKeyDown(event) {\n// Update Input box value if enter key was pressed and option selected\n  if (event.key === 'Enter' && !event.isComposing) {\n    if (removeButtonSelectedIndex.value !== -1) {\n      handleRemoveClick(removeButtonSelectedIndex.value)\n    } else if (searchState.selectedOption !== -1) {\n      searchState.showOptions = false\n      event.preventDefault()\n      inputData.value = visibleDataList.value[searchState.selectedOption]\n      handleOptionClick(searchState.selectedOption)\n    } else {\n      handleClick(event)\n    }\n\n    return\n  }\n\n  if (visibleDataList.value.length === 0) { return }\n\n  searchState.showOptions = true\n\n  // \"select\" the Remove button through right arrow navigation, and unselect it with the left arrow\n  if (event.key === 'ArrowRight') {\n    removeButtonSelectedIndex.value = searchState.selectedOption\n  } else if (event.key === 'ArrowLeft') {\n    removeButtonSelectedIndex.value = -1\n  } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n    event.preventDefault()\n    const newIndex = searchState.selectedOption + (event.key === 'ArrowDown' ? 1 : -1)\n    updateSelectedOptionIndex(newIndex)\n  } else {\n    const selectedOptionValue = searchStateKeyboardSelectedOptionValue.value\n\n    // Keyboard selected & is char\n    if (!isNullOrEmpty(selectedOptionValue) && isKeyboardEventKeyPrintableChar(event.key)) {\n      // Update input based on KB selected suggestion value instead of current input value\n      event.preventDefault()\n      handleInput(`${selectedOptionValue}${event.key}`)\n    }\n  }\n}\n\n/**\n * Updates the selected dropdown option index and handles the under/over-flow behavior\n * @param {number} index\n */\nfunction updateSelectedOptionIndex(index) {\n  searchState.selectedOption = index\n\n  // unset selection of \"Remove\" button\n  removeButtonSelectedIndex.value = -1\n\n  // Allow deselecting suggestion\n  if (searchState.selectedOption < -1) {\n    searchState.selectedOption = visibleDataList.value.length - 1\n  } else if (searchState.selectedOption > visibleDataList.value.length - 1) {\n    searchState.selectedOption = -1\n  }\n\n  // Update displayed value\n  searchState.keyboardSelectedOptionIndex = searchState.selectedOption\n}\n\nfunction handleInputBlur() {\n  if (!searchState.isPointerInList) {\n    searchState.showOptions = false\n  }\n}\n\nfunction handleFocus() {\n  searchState.showOptions = true\n}\n\nfunction updateVisibleDataList() {\n  // Reset selected option before it's updated\n  // Block resetting if it was just the \"Remove\" button that was pressed\n  if (!removalMade.value || searchState.selectedOption >= props.dataList.length) {\n    searchState.selectedOption = -1\n    searchState.keyboardSelectedOptionIndex = -1\n    removeButtonSelectedIndex.value = -1\n  }\n\n  removalMade.value = false\n\n  if (inputData.value.trim() === '') {\n    visibleDataList.value = props.dataList\n    return\n  }\n  // get list of items that match input\n  const lowerCaseInputData = inputData.value.toLowerCase()\n\n  visibleDataList.value = props.dataList.filter(x => {\n    return x.toLowerCase().includes(lowerCaseInputData)\n  })\n}\n\ndefineExpose({\n  focus: () => {\n    inputRef.value?.focus()\n  },\n  blur: () => {\n    inputRef.value?.blur()\n  },\n  select: () => {\n    inputRef.value?.select()\n  },\n\n  /**\n   * @param {string} text\n   */\n  setText: (text) => {\n    inputData.value = text\n  },\n\n  clear: () => {\n    handleClearTextClick()\n  }\n})\n</script>\n\n<style scoped src=\"./FtInput.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtInputTags/FtInputTags.css",
    "content": ".ft-input-tags-component {\n  position: relative;\n  background-color: var(--bg-color);\n  padding: 20px;\n  border-radius: 5px;\n  display: block;\n  inline-size: 60%;\n}\n\n.disabledMsg {\n  color: rgb(233 255 108);\n  padding-block-end: 10px;\n}\n\n.ft-tag-box ul {\n  overflow: visible;\n  display: block;\n  padding: 0;\n  margin: 0;\n}\n\n.ft-tag-box li {\n  list-style: none;\n  background-color: var(--card-bg-color);\n  margin: 5px;\n  border-radius: 5px;\n  display: flex;\n  float: inline-start;\n}\n\n.ft-tag-box li>span {\n  padding-block: 10px;\n  padding-inline: 10px;\n  overflow-wrap: break-word;\n  word-break: break-all;\n  hyphens: auto;\n  user-select: text;\n}\n\n.checkbox-container {\n  display: flex;\n  align-items: center;\n  font-size: 12px;\n  accent-color: var(--accent-color);\n}\n\n.tag-icon {\n  border-radius: 50%;\n  vertical-align: middle;\n}\n\n.tag-icon-link {\n  margin: auto;\n  margin-inline-start: 10px;\n}\n\n.removeTagButton {\n  background-color: transparent;\n  border-style: none;\n  color: var(--primary-text-color);\n  font-size: 1em;\n  line-height: 1em;\n  opacity: 0.5;\n  padding: 10px;\n  padding-inline-start: 0;\n}\n\n.removeTagButton:hover {\n  cursor: pointer;\n}\n\n:deep(.ft-input-component .ft-input) {\n  margin-block-start: 10px;\n}\n\n@media only screen and (width <= 576px) {\n  .ft-input-tags-component {\n    inline-size: 100%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtInputTags/FtInputTags.vue",
    "content": "<template>\n  <div\n    class=\"ft-input-tags-component\"\n  >\n    <div\n      v-if=\"disabled\"\n      class=\"disabledMsg\"\n    >\n      {{ disabledMsg }}\n    </div>\n    <FtInput\n      ref=\"tagNameInput\"\n      :disabled=\"disabled\"\n      :placeholder=\"tagNamePlaceholder\"\n      :label=\"label\"\n      :min-input-length=\"minInputLength\"\n      :show-label=\"true\"\n      :tooltip=\"tooltip\"\n      :show-action-button=\"true\"\n      :select-on-focus=\"true\"\n      :force-action-button-icon-name=\"['fas', 'arrow-right']\"\n      @click=\"updateTags\"\n    />\n    <div\n      v-if=\"tagList.length >= 1\"\n      class=\"checkbox-container\"\n    >\n      <input\n        :id=\"id\"\n        type=\"checkbox\"\n        :checked=\"showTags\"\n        @change=\"toggleShowTags\"\n      >\n      <label :for=\"id\">\n        {{ t('Settings.Distraction Free Settings.Show Added Items') }}\n      </label>\n    </div>\n    <div\n      v-if=\"showTags\"\n      class=\"ft-tag-box\"\n    >\n      <ul>\n        <li\n          v-for=\"tag in tagList\"\n          :key=\"tag.id\"\n        >\n          <template v-if=\"areChannelTags\">\n            <RouterLink\n              v-if=\"tag.icon\"\n              :to=\"tag.iconHref ?? ''\"\n              class=\"tag-icon-link\"\n            >\n              <img\n                :src=\"tag.icon\"\n                alt=\"\"\n                class=\"tag-icon\"\n                height=\"24\"\n                width=\"24\"\n                loading=\"lazy\"\n              >\n            </RouterLink>\n            <bdi>{{ (tag.preferredName) ? tag.preferredName : tag.name }}</bdi>\n          </template>\n          <bdi v-else>{{ tag }}</bdi>\n          <button\n            v-if=\"!disabled\"\n            class=\"removeTagButton\"\n            @click=\"removeTag(tag)\"\n          >\n            <FontAwesomeIcon\n              :icon=\"['fas', 'fa-times']\"\n            />\n          </button>\n        </li>\n      </ul>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useId, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtInput from '../FtInput/FtInput.vue'\n\nimport { showToast } from '../../helpers/utils'\n\nconst props = defineProps({\n  areChannelTags: {\n    type: Boolean,\n    default: false\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n  disabledMsg: {\n    type: String,\n    default: ''\n  },\n  tagNamePlaceholder: {\n    type: String,\n    required: true\n  },\n  label: {\n    type: String,\n    required: true\n  },\n  minInputLength: {\n    type: Number,\n    default: 1\n  },\n  showTags: {\n    type: Boolean,\n    default: true\n  },\n  tagList: {\n    type: Array,\n    default: () => []\n  },\n  tooltip: {\n    type: String,\n    default: ''\n  },\n  validateTagName: {\n    type: Function,\n    default: (_) => true\n  },\n  findTagInfo: {\n    type: Function,\n    default: (_) => ({ preferredName: '', icon: '' }),\n  }\n})\n\nconst emit = defineEmits(['already-exists', 'change', 'error-find-tag-info', 'invalid-name', 'toggle-show-tags'])\n\nconst { t } = useI18n()\n\nconst id = useId()\n\nconst tagNameInput = useTemplateRef('tagNameInput')\n\n/**\n * @param {string} text\n */\nasync function updateTags(text) {\n  if (props.areChannelTags) {\n    await updateChannelTags(text)\n    return\n  }\n\n  // add tag and update tag list\n  const trimmedText = text.trim()\n\n  if (props.minInputLength > trimmedText.length) {\n    showToast(t('Trimmed input must be at least N characters long', { length: props.minInputLength }, props.minInputLength))\n    return\n  }\n\n  if (props.tagList.includes(trimmedText)) {\n    showToast(t('Tag already exists', { tagName: trimmedText }))\n    return\n  }\n\n  const newList = props.tagList.slice()\n  newList.push(trimmedText)\n  emit('change', newList)\n  // clear input box\n  tagNameInput.value.clear()\n}\n\n/**\n * @param {string} text\n */\nasync function updateChannelTags(text) {\n  // get text without spaces after last '/' in url, if any\n  const name = text.split('/').at(-1).trim()\n\n  if (!props.validateTagName(name)) {\n    emit('invalid-name')\n    return\n  }\n\n  if (!props.tagList.some((tag) => tag.name === name)) {\n    // tag info searching allow api calls to be used\n    const { preferredName, icon, iconHref, err } = await props.findTagInfo(name)\n\n    if (err) {\n      emit('error-find-tag-info')\n      return\n    }\n\n    const newTag = { name, preferredName, icon, iconHref }\n    emit('change', [...props.tagList, newTag])\n  } else {\n    emit('already-exists')\n  }\n\n  // clear input box\n  tagNameInput.value.clear()\n}\n\nfunction removeTag(tag) {\n  if (props.areChannelTags) {\n    removeChannelTag(tag)\n    return\n  }\n\n  // Remove tag from list\n  const tagName = tag.trim()\n  const index = props.tagList.indexOf(tagName)\n\n  if (index !== -1) {\n    const newList = props.tagList.slice(0)\n    newList.splice(index, 1)\n    emit('change', newList)\n  }\n}\n\nfunction removeChannelTag(tag) {\n  // Remove tag from list\n  if (props.tagList.some((tmpTag) => tmpTag.name === tag.name)) {\n    const newList = props.tagList.filter((tmpTag) => tmpTag.name !== tag.name)\n    emit('change', newList)\n  }\n}\n\nfunction toggleShowTags() {\n  emit('toggle-show-tags')\n}\n</script>\n\n<style scoped src=\"./FtInputTags.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtKeyboardShortcutPrompt/FtKeyboardShortcutPrompt.css",
    "content": "\n\n.keyboardShortcutPrompt {\n  max-inline-size: 80%;\n}\n\n.titleAndCloseButton {\n  display: flex;\n  justify-content: space-between;\n  margin-block: 20px;\n  margin-inline-start: 10px;\n}\n\nh2 {\n  font-size: 25px;\n}\n\nh3 {\n  font-size: 20px;\n}\n\nh2,\nh3 {\n  margin-block: 0.25em;\n  inline-size: fit-content;\n  font-weight: bold;\n}\n\n.center {\n  text-align: center;\n}\n\n.primarySection {\n  inline-size: 100%;\n}\n\n.primarySections,\n.primarySection {\n  display: flex;\n  flex-flow: row wrap;\n  gap: 30px;\n  justify-content: space-evenly;\n}\n\n.secondarySection {\n  flex: 0 0 500px;\n}\n\n.labelsAndShortcuts {\n  display: table;\n  table-layout: auto;\n  border-collapse: collapse;\n}\n\n.labelAndShortcut {\n  display: table-row;\n  font-size: 16px;\n}\n\n.labelAndShortcut + .labelAndShortcut {\n  border-block-start: 1px solid var(--primary-shadow-color);\n}\n\n.label,\n.shortcut {\n  padding-block: 0.25em;\n}\n\n.label {\n  display: table-cell;\n  padding-inline-end: 2em;\n  inline-size: 300px;\n  min-inline-size: 300px;\n}\n\n.shortcut {\n  font-family: monospace;\n  display: table-cell;\n  vertical-align: middle;\n  text-transform: capitalize;\n}\n\n:deep(.promptCard) {\n  overflow-x: hidden;\n}\n\n@media only screen and (width <= 600px) {\n  .label {\n    min-inline-size: 200px;\n    inline-size: 200px;\n  }\n\n  .secondarySection {\n    flex: 0;\n  }\n\n  .primarySection {\n    justify-content: flex-start;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtKeyboardShortcutPrompt/FtKeyboardShortcutPrompt.vue",
    "content": "<template>\n  <FtPrompt\n    :label=\"$t('KeyboardShortcutPrompt.Keyboard Shortcuts')\"\n    @click=\"hideKeyboardShortcutPrompt\"\n  >\n    <template #label=\"{ labelId }\">\n      <div class=\"titleAndCloseButton\">\n        <h2 :id=\"labelId\">\n          {{ $t('KeyboardShortcutPrompt.Keyboard Shortcuts') }}\n        </h2>\n        <FtIconButton\n          :title=\"$t('Close')\"\n          :icon=\"['fas', 'xmark']\"\n          theme=\"destructive\"\n          @click=\"hideKeyboardShortcutPrompt\"\n        />\n      </div>\n    </template>\n\n    <div class=\"primarySections\">\n      <div\n        v-for=\"(primarySection, index) of primarySections\"\n        :key=\"index\"\n        class=\"primarySection\"\n      >\n        <div\n          v-for=\"secondarySection in primarySection\"\n          :key=\"secondarySection.title\"\n          class=\"secondarySection\"\n        >\n          <h3 class=\"center\">\n            {{ secondarySection.title }}\n          </h3>\n          <div class=\"labelsAndShortcuts\">\n            <div\n              v-for=\"[label, shortcut] in secondarySection.shortcutDictionary\"\n              :key=\"label\"\n              class=\"labelAndShortcut\"\n            >\n              <p\n                class=\"label\"\n              >\n                {{ label }}\n              </p>\n              <p class=\"shortcut\">\n                {{ shortcut }}\n              </p>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </FtPrompt>\n</template>\n\n<script setup>\n\nimport { computed } from 'vue'\nimport { KeyboardShortcuts } from '../../../constants'\nimport { getLocalizedShortcut } from '../../helpers/utils'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport store from '../../store/index'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\n\nconst { t } = useI18n()\n\nconst generalPlayerShortcuts = computed(() =>\n  getLocalizedShortcutNamesAndValues(KeyboardShortcuts.VIDEO_PLAYER.GENERAL)\n)\n\nconst playbackPlayerShortcuts = computed(() =>\n  getLocalizedShortcutNamesAndValues(KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK)\n)\n\nconst generalAppShortcuts = computed(() =>\n  getLocalizedShortcutNamesAndValues(KeyboardShortcuts.APP.GENERAL)\n)\n\nconst situationalAppShortcuts = computed(() =>\n  getLocalizedShortcutNamesAndValues(KeyboardShortcuts.APP.SITUATIONAL)\n)\n\nconst primarySections = computed(() => [\n  [\n    {\n      title: t('KeyboardShortcutPrompt.Sections.Video.Playback'),\n      shortcutDictionary: playbackPlayerShortcuts.value\n    },\n    {\n      title: t('KeyboardShortcutPrompt.Sections.Video.General'),\n      shortcutDictionary: generalPlayerShortcuts.value\n    },\n  ],\n  [\n    {\n      title: t('KeyboardShortcutPrompt.Sections.App.General'),\n      shortcutDictionary: generalAppShortcuts.value\n    },\n    {\n      title: t('KeyboardShortcutPrompt.Sections.App.Situational'),\n      shortcutDictionary: situationalAppShortcuts.value\n    }\n  ]\n])\n\nconst isMac = process.platform === 'darwin'\n\nconst localizedShortcutNameToShortcutsMappings = computed(() => {\n  return [\n    [t('KeyboardShortcutPrompt.Show Keyboard Shortcuts'), ['SHOW_SHORTCUTS']],\n    [t('KeyboardShortcutPrompt.History Backward'), [\n      'HISTORY_BACKWARD',\n      ...isMac ? ['HISTORY_BACKWARD_ALT_MAC'] : [],\n    ]],\n    [t('KeyboardShortcutPrompt.History Forward'), [\n      'HISTORY_FORWARD',\n      ...isMac ? ['HISTORY_FORWARD_ALT_MAC'] : [],\n    ]],\n    [t('KeyboardShortcutPrompt.Navigate to Settings'), ['NAVIGATE_TO_SETTINGS']],\n    [t('KeyboardShortcutPrompt.Navigate to History'), [\n      isMac ? 'NAVIGATE_TO_HISTORY_MAC' : 'NAVIGATE_TO_HISTORY',\n    ]],\n    [t('KeyboardShortcutPrompt.New Window'), ['NEW_WINDOW']],\n    [t('KeyboardShortcutPrompt.Minimize Window'), ['MINIMIZE_WINDOW']],\n    [t('KeyboardShortcutPrompt.Close Window'), ['CLOSE_WINDOW']],\n    [t('KeyboardShortcutPrompt.Toggle Developer Tools'), ['TOGGLE_DEVTOOLS']],\n    [t('KeyboardShortcutPrompt.Reset Zoom'), ['RESET_ZOOM']],\n    [t('KeyboardShortcutPrompt.Zoom In'), ['ZOOM_IN']],\n    [t('KeyboardShortcutPrompt.Zoom Out'), ['ZOOM_OUT']],\n    [t('KeyboardShortcutPrompt.Focus Search'), ['FOCUS_SEARCH']],\n    [t('KeyboardShortcutPrompt.Search in New Window'), ['SEARCH_IN_NEW_WINDOW']],\n\n    [t('KeyboardShortcutPrompt.Refresh'), ['REFRESH']],\n    [t('KeyboardShortcutPrompt.Focus Secondary Search'), ['FOCUS_SECONDARY_SEARCH']],\n\n    [t('KeyboardShortcutPrompt.Captions'), ['CAPTIONS']],\n    [t('KeyboardShortcutPrompt.Theatre Mode'), ['THEATRE_MODE']],\n    [t('KeyboardShortcutPrompt.Fullscreen'), ['FULLSCREEN']],\n    [t('KeyboardShortcutPrompt.Full Window'), ['FULLWINDOW']],\n    [t('KeyboardShortcutPrompt.Picture in Picture'), ['PICTURE_IN_PICTURE']],\n    [t('KeyboardShortcutPrompt.Mute'), ['MUTE']],\n    [t('KeyboardShortcutPrompt.Volume Up'), ['VOLUME_UP']],\n    [t('KeyboardShortcutPrompt.Volume Down'), ['VOLUME_DOWN']],\n    [t('KeyboardShortcutPrompt.Take Screenshot'), ['TAKE_SCREENSHOT']],\n    [t('KeyboardShortcutPrompt.Stats'), ['STATS']],\n\n    [t('KeyboardShortcutPrompt.Play'), ['PLAY']],\n    [t('KeyboardShortcutPrompt.Large Rewind'), ['LARGE_REWIND']],\n    [t('KeyboardShortcutPrompt.Large Fast Forward'), ['LARGE_FAST_FORWARD']],\n    [t('KeyboardShortcutPrompt.Small Rewind'), ['SMALL_REWIND']],\n    [t('KeyboardShortcutPrompt.Small Fast Forward'), ['SMALL_FAST_FORWARD']],\n    [t('KeyboardShortcutPrompt.Decrease Video Speed'), ['DECREASE_VIDEO_SPEED', 'DECREASE_VIDEO_SPEED_ALT']],\n    [t('KeyboardShortcutPrompt.Increase Video Speed'), ['INCREASE_VIDEO_SPEED', 'INCREASE_VIDEO_SPEED_ALT']],\n    [t('KeyboardShortcutPrompt.Home'), ['HOME']],\n    [t('KeyboardShortcutPrompt.End'), ['END']],\n    [t('KeyboardShortcutPrompt.Skip by Tenths'), ['SKIP_N_TENTHS']],\n    [t('KeyboardShortcutPrompt.Last Chapter'), ['LAST_CHAPTER']],\n    [t('KeyboardShortcutPrompt.Next Chapter'), ['NEXT_CHAPTER']],\n    [t('KeyboardShortcutPrompt.Last Frame'), ['LAST_FRAME']],\n    [t('KeyboardShortcutPrompt.Next Frame'), ['NEXT_FRAME']],\n    [t('KeyboardShortcutPrompt.Skip to Next Video'), ['SKIP_TO_NEXT']],\n    [t('KeyboardShortcutPrompt.Skip to Previous Video'), ['SKIP_TO_PREV']],\n  ]\n})\n\nfunction hideKeyboardShortcutPrompt() {\n  store.dispatch('hideKeyboardShortcutPrompt')\n}\n\nfunction getLocalizedShortcutNamesAndValues(dictionary) {\n  const shortcutNameToShortcutsMappings = localizedShortcutNameToShortcutsMappings.value\n  const shortcutLabelSeparator = t('shortcutLabelSeparator')\n\n  return shortcutNameToShortcutsMappings\n    .filter(([_localizedShortcutName, shortcutCodes]) =>\n      shortcutCodes.some(shortcutCode => Object.hasOwn(dictionary, shortcutCode))\n    )\n    .map(([localizedShortcutName, shortcutCodes]) => {\n      const localizedShortcuts = shortcutCodes.map(code => getLocalizedShortcut(dictionary[code]))\n      return [localizedShortcutName, localizedShortcuts.join(shortcutLabelSeparator)]\n    })\n}\n\n</script>\n\n<style scoped src=\"./FtKeyboardShortcutPrompt.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtListChannel/FtListChannel.scss",
    "content": "@use '../../scss-partials/ft-list-item';\n\n.infoAndSubscribe {\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: center;\n  inline-size: 100%;\n}\n\n.ft-list-channel {\n  &.grid {\n    align-items: center;\n    text-align: center;\n\n    .infoAndSubscribe {\n      flex-flow: column wrap;\n      align-items: center;\n\n      .info {\n        margin-block-end: 12px;\n\n        .infoLine {\n          text-align: center;\n        }\n      }\n    }\n  }\n\n  &.list {\n    .infoAndSubscribe {\n      .channelSubscribeButton {\n        margin-block: auto;\n        margin-inline: 7px;\n      }\n    }\n  }\n}\n\n.handle {\n  color: inherit;\n  text-decoration: none;\n}\n"
  },
  {
    "path": "src/renderer/components/FtListChannel/FtListChannel.vue",
    "content": "<template>\n  <div\n    class=\"ft-list-channel ft-list-item\"\n    :class=\"{\n      list: listType === 'list',\n      grid: listType === 'grid',\n      [appearance]: true\n    }\"\n  >\n    <div class=\"channelThumbnail\">\n      <router-link\n        :to=\"`/channel/${id}`\"\n        class=\"channelThumbnailLink\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n      >\n        <img\n          :src=\"thumbnail\"\n          :class=\"!isGame ? 'channelImage' : 'gameImage'\"\n          alt=\"\"\n        >\n      </router-link>\n    </div>\n    <div class=\"infoAndSubscribe\">\n      <div class=\"info\">\n        <router-link\n          class=\"title\"\n          :to=\"`/channel/${id}`\"\n        >\n          <h3\n            class=\"h3Title\"\n            dir=\"auto\"\n          >\n            {{ name }}\n          </h3>\n        </router-link>\n        <div class=\"infoLine\">\n          <router-link\n            v-if=\"handle !== null\"\n            class=\"handle\"\n            dir=\"auto\"\n            :to=\"`/channel/${id}`\"\n          >\n            {{ handle }}\n          </router-link>\n          <span\n            v-if=\"subscriberCount !== null && !hideChannelSubscriptions\"\n            class=\"subscriberCount\"\n          >\n            <template v-if=\"handle !== null\"> • </template>\n            {{ $t('Global.Counts.Subscriber Count', {count: formattedSubscriberCount}, subscriberCount) }}\n          </span>\n          <span\n            v-if=\"handle == null && videoCount != null\"\n            class=\"videoCount\"\n          >\n            <template v-if=\"subscriberCount !== null && !hideChannelSubscriptions\"> • </template>\n            {{ $t('Global.Counts.Video Count', {count: formattedVideoCount}, videoCount) }}\n          </span>\n        </div>\n        <p\n          v-if=\"listType !== 'grid'\"\n          v-safer-html=\"description\"\n          class=\"description\"\n          dir=\"auto\"\n        />\n      </div>\n      <FtSubscribeButton\n        v-if=\"!hideUnsubscribeButton\"\n        class=\"channelSubscribeButton\"\n        :channel-id=\"id\"\n        :channel-name=\"name\"\n        :channel-thumbnail=\"thumbnail\"\n      />\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport FtSubscribeButton from '../FtSubscribeButton/FtSubscribeButton.vue'\nimport { vSaferHtml } from '../../directives/vSaferHtml'\n\nimport store from '../../store/index'\n\nimport { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\nimport { formatNumber } from '../../helpers/utils'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  appearance: {\n    type: String,\n    required: true\n  }\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => {\n  return store.getters.getListType\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelSubscriptions = computed(() => {\n  return store.getters.getHideChannelSubscriptions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUnsubscribeButton = computed(() => {\n  return store.getters.getHideUnsubscribeButton\n})\n\nlet id = ''\nlet thumbnail = ''\nlet name = ''\n/** @type {number?} */\nlet subscriberCount = null\n/** @type {number?} */\nlet videoCount = null\n/** @type {string?} */\nlet handle = null\nlet description = ''\nlet isGame = null\n\nif (process.env.SUPPORTS_LOCAL_API && props.data.dataSource === 'local') {\n  parseLocalData()\n} else {\n  parseInvidiousData()\n}\n\nconst formattedSubscriberCount = computed(() => {\n  if (subscriberCount != null) {\n    return formatNumber(subscriberCount)\n  }\n\n  return ''\n})\n\nconst formattedVideoCount = computed(() => {\n  if (videoCount != null) {\n    return formatNumber(videoCount)\n  }\n\n  return ''\n})\n\nfunction parseLocalData() {\n  thumbnail = props.data.thumbnail\n  name = props.data.name\n  id = props.data.id\n\n  if (props.data.subscribers != null) {\n    subscriberCount = props.data.subscribers\n  }\n\n  if (props.data.videos != null) {\n    videoCount = props.data.videos\n  }\n\n  if (props.data.handle) {\n    handle = props.data.handle\n  }\n\n  description = props.data.descriptionShort\n  isGame = props.data.isGame\n}\n\nfunction parseInvidiousData() {\n  // Can be prefixed with `https://` or `//` (protocol relative)\n  /** @type {string} */\n  const thumbnailUrl = props.data.authorThumbnails[2].url\n\n  thumbnail = youtubeImageUrlToInvidious(thumbnailUrl, currentInvidiousInstanceUrl.value)\n\n  name = props.data.author\n  id = props.data.authorId\n  subscriberCount = props.data.subCount\n\n  if (props.data.channelHandle != null) {\n    handle = props.data.channelHandle\n  } else {\n    videoCount = props.data.videoCount\n  }\n\n  description = props.data.description\n}\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtListChannel.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtListHashtag/FtListHashtag.scss",
    "content": "@use '../../scss-partials/ft-list-item';\n\n.hashtagImage {\n  color: var(--primary-text-color);\n  font-size: 150px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtListHashtag/FtListHashtag.vue",
    "content": "<template>\n  <div\n    class=\"ft-list-hashtag ft-list-item\"\n    :class=\"{\n      list: listType === 'list',\n      grid: listType === 'grid',\n      [appearance]: true\n    }\"\n  >\n    <div class=\"channelThumbnail\">\n      <router-link\n        class=\"channelThumbnailLink\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n        :to=\"url\"\n      >\n        <FontAwesomeIcon\n          class=\"hashtagImage\"\n          :icon=\"['fas', 'hashtag']\"\n        />\n      </router-link>\n    </div>\n    <div class=\"info\">\n      <router-link\n        class=\"title\"\n        :to=\"url\"\n      >\n        <h3\n          class=\"h3Title\"\n          dir=\"auto\"\n        >\n          {{ title }}\n        </h3>\n      </router-link>\n      <div class=\"infoLine\">\n        <span\n          v-if=\"channelCount\"\n          class=\"channelCount\"\n        >\n          {{ $t('Global.Counts.Channel Count', {count: formattedChannelCount}, channelCount) }}\n        </span>\n        <span\n          v-if=\"videoCount\"\n          class=\"videoCount\"\n        >\n          <template v-if=\"channelCount\"> • </template>\n          {{ $t('Global.Counts.Video Count', {count: formattedVideosCount}, videoCount) }}\n        </span>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed } from 'vue'\n\nimport store from '../../store/index'\n\nimport { formatNumber } from '../../helpers/utils'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  appearance: {\n    type: String,\n    required: true\n  }\n})\n\n/** @type {import('vue').ComputedRef<'list'| 'grid'>} */\nconst listType = computed(() => {\n  return store.getters.getListType\n})\n\n/** @type {string} */\nconst title = props.data.title\n/** @type {number} */\nconst channelCount = props.data.channelCount\n/** @type {number} */\nconst videoCount = props.data.videoCount\n/** @type {string} */\nconst url = `/hashtag/${encodeURIComponent(title.substring(1))}`\n\nconst formattedChannelCount = computed(() => {\n  return formatNumber(channelCount)\n})\n\nconst formattedVideosCount = computed(() => {\n  return formatNumber(videoCount)\n})\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtListHashtag.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtListLazyWrapper/FtListLazyWrapper.css",
    "content": ".grid {\n  min-block-size: 264px;\n}\n\n.list {\n  min-block-size: 131px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtListLazyWrapper/FtListLazyWrapper.vue",
    "content": "<template>\n  <div\n    v-if=\"showResult\"\n    v-observe-visibility=\"visible ? false : {\n      callback: onVisibilityChanged\n    }\"\n    :class=\"{\n      grid: layout === 'grid',\n      list: layout === 'list'\n    }\"\n  >\n    <template\n      v-if=\"visible\"\n    >\n      <FtListVideo\n        v-if=\"finalDataType === 'video' || finalDataType === 'shortVideo'\"\n        :appearance=\"appearance\"\n        :data=\"data\"\n        :playlist-id=\"playlistId\"\n        :playlist-type=\"playlistType\"\n        :playlist-item-id=\"playlistItemId\"\n        :show-video-with-last-viewed-playlist=\"showVideoWithLastViewedPlaylist\"\n        :always-show-add-to-playlist-button=\"alwaysShowAddToPlaylistButton\"\n        :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n        :can-move-video-up=\"canMoveVideoUp\"\n        :can-move-video-down=\"canMoveVideoDown\"\n        :can-remove-from-playlist=\"canRemoveFromPlaylist\"\n        @move-video-up=\"moveVideoUp\"\n        @move-video-down=\"moveVideoDown\"\n        @remove-from-playlist=\"removeFromPlaylist\"\n      />\n      <FtListChannel\n        v-else-if=\"finalDataType === 'channel'\"\n        :appearance=\"appearance\"\n        :data=\"data\"\n      />\n      <FtListPlaylist\n        v-else-if=\"finalDataType === 'playlist'\"\n        :appearance=\"appearance\"\n        :data=\"data\"\n        :search-query-text=\"searchQueryText\"\n      />\n      <FtCommunityPost\n        v-else-if=\"finalDataType === 'community'\"\n        :hide-forbidden-titles=\"hideForbiddenTitles\"\n        :appearance=\"appearance\"\n        :data=\"data\"\n      />\n      <FtListHashtag\n        v-else-if=\"data.type === 'hashtag'\"\n        :appearance=\"appearance\"\n        :data=\"data\"\n      />\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\n\nimport FtListVideo from '../ft-list-video/ft-list-video.vue'\nimport FtListChannel from '../FtListChannel/FtListChannel.vue'\nimport FtListPlaylist from '../FtListPlaylist/FtListPlaylist.vue'\nimport FtCommunityPost from '../FtCommunityPost/FtCommunityPost.vue'\nimport FtListHashtag from '../FtListHashtag/FtListHashtag.vue'\n\nimport store from '../../store/index'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  dataType: {\n    type: String,\n    default: null,\n  },\n  appearance: {\n    type: String,\n    required: true\n  },\n  firstScreen: {\n    type: Boolean,\n    required: true\n  },\n  layout: {\n    type: String,\n    default: 'grid'\n  },\n  showVideoWithLastViewedPlaylist: {\n    type: Boolean,\n    default: false\n  },\n  useChannelsHiddenPreference: {\n    type: Boolean,\n    default: true,\n  },\n  hideForbiddenTitles: {\n    type: Boolean,\n    default: true\n  },\n  searchQueryText: {\n    type: String,\n    required: false,\n    default: '',\n  },\n  playlistId: {\n    type: String,\n    default: null\n  },\n  playlistType: {\n    type: String,\n    default: null\n  },\n  playlistItemId: {\n    type: String,\n    default: null\n  },\n  alwaysShowAddToPlaylistButton: {\n    type: Boolean,\n    default: false,\n  },\n  quickBookmarkButtonEnabled: {\n    type: Boolean,\n    default: true,\n  },\n  canMoveVideoUp: {\n    type: Boolean,\n    default: false,\n  },\n  canMoveVideoDown: {\n    type: Boolean,\n    default: false,\n  },\n  canRemoveFromPlaylist: {\n    type: Boolean,\n    default: false,\n  },\n})\n\nconst emit = defineEmits(['move-video-down', 'move-video-up', 'remove-from-playlist'])\n\n/** @type {import('vue').ComputedRef<'video' | 'shortVideo' | 'channel' | 'playlist' | 'community'>} */\nconst finalDataType = computed(() => {\n  return props.data.type ?? props.dataType\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLiveStreams = computed(() => {\n  return store.getters.getHideLiveStreams\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUpcomingPremieres = computed(() => {\n  return store.getters.getHideUpcomingPremieres\n})\n\n/** @type {import('vue').ComputedRef<{name : string, preferredName: string, icon: string}[]>} */\nconst channelsHidden = computed(() => {\n  // Some component users like channel view will have this disabled\n  if (!props.useChannelsHiddenPreference) { return [] }\n\n  return JSON.parse(store.getters.getChannelsHidden).map((ch) => {\n    // Legacy support\n    if (typeof ch === 'string') {\n      return { name: ch, preferredName: '', icon: '' }\n    }\n    return ch\n  })\n})\n\n/** @type {string[]} */\nconst forbiddenTitles = computed(() => {\n  if (!props.hideForbiddenTitles) { return [] }\n  return JSON.parse(store.getters.getForbiddenTitles.toLowerCase())\n})\n\nconst showResult = computed(() => {\n  const dataType = finalDataType.value\n\n  if (!dataType) {\n    return false\n  }\n\n  if (dataType === 'video' || dataType === 'shortVideo') {\n    if (hideLiveStreams.value && (props.data.liveNow || props.data.lengthSeconds == null)) {\n      // hide livestreams\n      return false\n    }\n\n    if (hideUpcomingPremieres.value &&\n        // Observed for premieres in Local API Channels.\n        (props.data.premiereDate != null ||\n          // Invidious API\n          // `premiereTimestamp` only available on premiered videos\n          // https://docs.invidious.io/api/common_types/#videoobject\n          props.data.premiereTimestamp != null ||\n          // viewCount is our only method of detecting premieres in RSS\n          // data without sending an additional request.\n          // If we ever get a better flag, use it here instead.\n          (props.data.isRSS && props.data.viewCount === '0'))) {\n      // hide upcoming\n      return false\n    }\n\n    const lowerCaseAuthor = props.data.author?.toLowerCase()\n\n    if (channelsHidden.value.some(ch => ch.name === props.data.authorId) || channelsHidden.value.some(ch => ch.name === props.data.author) || (forbiddenTitles.value.some((text) => lowerCaseAuthor.includes(text)))) {\n      // hide videos by author\n      return false\n    }\n\n    const lowerCaseTitle = props.data.title?.toLowerCase()\n\n    if (forbiddenTitles.value.some((text) => lowerCaseTitle.includes(text))) {\n      return false\n    }\n  } else if (dataType === 'channel') {\n    const attrsToCheck = [\n      // Local API\n      props.data.id,\n      props.data.name,\n      // Invidious API\n      // https://docs.invidious.io/api/common_types/#channelobject\n      props.data.author,\n      props.data.authorId,\n    ]\n\n    const lowerCaseName = props.data.name?.toLowerCase()\n\n    if ((attrsToCheck.some(a => a != null && channelsHidden.value.some(ch => ch.name === a))) ||\n      (forbiddenTitles.value.some((text) => lowerCaseName.includes(text)))) {\n      // hide channels by author\n      return false\n    }\n  } else if (dataType === 'playlist') {\n    const lowerCaseTitle = props.data.title?.toLowerCase()\n    const lowerCaseChannelName = props.data.channelName?.toLowerCase()\n\n    if ((forbiddenTitles.value.some((text) => lowerCaseTitle.includes(text))) ||\n      (forbiddenTitles.value.some((text) => lowerCaseChannelName.includes(text)))) {\n      return false\n    }\n\n    const attrsToCheck = [\n      // Local API\n      props.data.channelId,\n      props.data.channelName,\n      // Invidious API\n      // https://docs.invidious.io/api/common_types/#playlistobject\n      props.data.author,\n      props.data.authorId,\n    ]\n\n    if (attrsToCheck.some(a => a != null && channelsHidden.value.some(ch => ch.name === a))) {\n      // hide playlists by author\n      return false\n    }\n  }\n  return true\n})\n\nconst visible = ref(props.firstScreen)\n\n/**\n * @param {boolean} isVisible\n */\nfunction onVisibilityChanged(isVisible) {\n  if (isVisible) {\n    visible.value = isVisible\n  }\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoUp(videoId, playlistItemId) {\n  emit('move-video-up', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoDown(videoId, playlistItemId) {\n  emit('move-video-down', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction removeFromPlaylist(videoId, playlistItemId) {\n  emit('remove-from-playlist', videoId, playlistItemId)\n}\n</script>\n\n<style scoped src=\"./FtListLazyWrapper.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtListPlaylist/FtListPlaylist.scss",
    "content": "@use '../../scss-partials/ft-list-item';\n\n.blur {\n  filter: blur(20px);\n}\n"
  },
  {
    "path": "src/renderer/components/FtListPlaylist/FtListPlaylist.vue",
    "content": "<template>\n  <div\n    class=\"ft-list-video ft-list-item\"\n    :class=\"{\n      [appearance]: true,\n      list: listType === 'list',\n      grid: listType === 'grid'\n    }\"\n  >\n    <div\n      class=\"videoThumbnail\"\n    >\n      <RouterLink\n        class=\"thumbnailLink\"\n        :to=\"playlistPageLinkTo\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n      >\n        <img\n          alt=\"\"\n          :src=\"thumbnailForDisplay\"\n          class=\"thumbnailImage\"\n          :class=\"{ blur: blurThumbnails }\"\n        >\n      </RouterLink>\n      <div\n        class=\"videoCountContainer\"\n      >\n        <div class=\"background\" />\n        <div class=\"inner\">\n          <div>{{ videoCount }}</div>\n          <div><FontAwesomeIcon :icon=\"['fas','list']\" /></div>\n        </div>\n      </div>\n    </div>\n    <div class=\"info\">\n      <RouterLink\n        class=\"title\"\n        :to=\"playlistPageLinkTo\"\n      >\n        <h3\n          class=\"h3Title\"\n          dir=\"auto\"\n        >\n          {{ titleForDisplay }}\n        </h3>\n      </RouterLink>\n      <div class=\"infoLine\">\n        <RouterLink\n          v-if=\"channelId\"\n          class=\"channelName\"\n          dir=\"auto\"\n          :to=\"`/channel/${channelId}`\"\n        >\n          {{ channelName }}\n        </RouterLink>\n        <bdi\n          v-else\n          class=\"channelName\"\n        >\n          {{ channelName }}\n        </bdi>\n      </div>\n      <FtIconButton\n        v-if=\"externalPlayer !== '' && !isUserPlaylist\"\n        :title=\"t('Video.External Player.OpenInTemplate', { externalPlayer })\"\n        :icon=\"['fas', 'external-link-alt']\"\n        class=\"externalPlayerButton\"\n        theme=\"base-no-default\"\n        :size=\"16\"\n        :use-shadow=\"false\"\n        @click=\"handleExternalPlayer\"\n      />\n      <span\n        v-if=\"isUserPlaylist\"\n        class=\"playlistIcons\"\n      >\n        <FtIconButton\n          :title=\"markedAsQuickBookmarkTarget ? t('User Playlists.Quick Bookmark Enabled') : t('User Playlists.Enable Quick Bookmark With This Playlist')\"\n          :icon=\"markedAsQuickBookmarkTarget ? ['fas', 'bookmark'] : ['far', 'bookmark']\"\n          :disabled=\"markedAsQuickBookmarkTarget\"\n          :theme=\"markedAsQuickBookmarkTarget ? 'secondary' : 'base-no-default'\"\n          :size=\"16\"\n          @disabled-click=\"handleQuickBookmarkEnabledDisabledClick\"\n          @click=\"enableQuickBookmarkForThisPlaylist\"\n        />\n      </span>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\n\nimport store from '../../store/index'\n\nimport { showToast } from '../../helpers/utils'\nimport thumbnailPlaceholder from '../../assets/img/thumbnail_placeholder.svg'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  appearance: {\n    type: String,\n    required: true\n  },\n  searchQueryText: {\n    type: String,\n    default: ''\n  },\n})\n\nconst { t } = useI18n()\n\nlet playlistId = ''\nlet title = ''\n/** @type {string} */\nlet thumbnail = thumbnailPlaceholder\n/** @type {string | null} */\nlet channelId = null\nlet channelName = ''\nlet videoCount = 0\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => store.getters.getListType)\n\nconst titleForDisplay = computed(() => {\n  if (typeof title !== 'string') {\n    return ''\n  }\n  if (title.length <= 255) {\n    return title\n  }\n\n  return `${title.slice(0, 255)}...`\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst blurThumbnails = computed(() => store.getters.getBlurThumbnails)\n\n/** @type {import('vue').ComputedRef<'' | 'start' | 'middle' | 'end' | 'hidden' | 'blur'>} */\nconst thumbnailPreference = computed(() => store.getters.getThumbnailPreference)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst thumbnailForDisplay = computed(() => {\n  return thumbnailPreference.value !== 'hidden' ? thumbnail : thumbnailPlaceholder\n})\n\nconst isUserPlaylist = computed(() => props.data._id != null)\n\n// For `router-link` attribute `to`\nconst playlistPageLinkTo = computed(() => ({\n  path: `/playlist/${playlistId}`,\n  query: {\n    playlistType: isUserPlaylist.value ? 'user' : '',\n    searchQueryText: props.searchQueryText,\n  },\n}))\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\nif (isUserPlaylist.value) {\n  parseUserData()\n} else if (props.data.dataSource === 'local') {\n  parseLocalData()\n} else {\n  parseInvidiousData()\n}\n\nfunction parseInvidiousData() {\n  title = props.data.title\n\n  thumbnail = props.data.playlistThumbnail\n    .replace('https://i.ytimg.com', currentInvidiousInstanceUrl.value)\n    .replace('hqdefault', 'mqdefault')\n\n  channelName = props.data.author\n  channelId = props.data.authorId\n  playlistId = props.data.playlistId\n  videoCount = props.data.videoCount\n\n  if (props.data.proxyThumbnail === false) {\n    thumbnail = props.data.playlistThumbnail\n  }\n}\n\nfunction parseLocalData() {\n  title = props.data.title\n\n  thumbnail = props.data.thumbnail\n\n  channelName = props.data.channelName\n  channelId = props.data.channelId\n  playlistId = props.data.playlistId\n  videoCount = props.data.videoCount\n}\n\nfunction parseUserData() {\n  title = props.data.playlistName\n\n  if (props.data.videos.length > 0) {\n    const origin = backendPreference.value === 'invidious'\n      ? currentInvidiousInstanceUrl.value\n      : 'https://i.ytimg.com'\n\n    thumbnail = `${origin}/vi/${props.data.videos[0].videoId}/mqdefault.jpg`\n  }\n\n  channelName = ''\n  channelId = ''\n  playlistId = props.data._id\n  videoCount = props.data.videos.length\n}\n\n/** @type {import('vue').ComputedRef<string | null>} */\nconst quickBookmarkPlaylistId = computed(() => store.getters.getQuickBookmarkTargetPlaylistId)\n\nconst markedAsQuickBookmarkTarget = computed(() => {\n  // Only user playlists can be target\n  return playlistId != null &&\n    quickBookmarkPlaylistId.value != null &&\n    quickBookmarkPlaylistId.value === playlistId\n})\n\nfunction handleQuickBookmarkEnabledDisabledClick() {\n  showToast(t('User Playlists.SinglePlaylistView.Toast[\"This playlist is already being used for quick bookmark.\"]'))\n}\n\nasync function enableQuickBookmarkForThisPlaylist() {\n  const currentQuickBookmarkTargetPlaylist = store.getters.getQuickBookmarkPlaylist\n\n  store.dispatch('updateQuickBookmarkTargetPlaylistId', playlistId)\n\n  if (currentQuickBookmarkTargetPlaylist != null) {\n    showToast(\n      t('User Playlists.SinglePlaylistView.Toast[\"This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo\"]', {\n        oldPlaylistName: currentQuickBookmarkTargetPlaylist.playlistName,\n      }),\n      5000,\n      () => {\n        store.dispatch('updateQuickBookmarkTargetPlaylistId', currentQuickBookmarkTargetPlaylist._id)\n        showToast(\n          t('User Playlists.SinglePlaylistView.Toast[\"Reverted to use {oldPlaylistName} for quick bookmark\"]', {\n            oldPlaylistName: currentQuickBookmarkTargetPlaylist.playlistName,\n          }),\n          5000,\n        )\n      },\n    )\n  } else {\n    showToast(t('User Playlists.SinglePlaylistView.Toast.This playlist is now used for quick bookmark'))\n  }\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst externalPlayer = computed(() => store.getters.getExternalPlayer)\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultPlayback = computed(() => store.getters.getDefaultPlayback)\n\nfunction handleExternalPlayer() {\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.openInExternalPlayer({\n      playlistId: playlistId,\n      playbackRate: defaultPlayback.value,\n    })\n  }\n}\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtListPlaylist.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtListVideoLazy.vue",
    "content": "<template>\n  <div\n    v-observe-visibility=\"visible ? false : {\n      callback: onVisibilityChanged\n    }\"\n    :style=\"{ display }\"\n  >\n    <FtListVideo\n      v-if=\"visible\"\n      :data=\"data\"\n      :playlist-id=\"playlistId\"\n      :playlist-type=\"playlistType\"\n      :playlist-index=\"playlistIndex\"\n      :playlist-reverse=\"playlistReverse\"\n      :playlist-shuffle=\"playlistShuffle\"\n      :playlist-loop=\"playlistLoop\"\n      :playlist-item-id=\"playlistItemId\"\n      :force-list-type=\"forceListType\"\n      :appearance=\"appearance\"\n      :always-show-add-to-playlist-button=\"alwaysShowAddToPlaylistButton\"\n      :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n      :can-move-video-up=\"canMoveVideoUp\"\n      :can-move-video-down=\"canMoveVideoDown\"\n      :can-remove-from-playlist=\"canRemoveFromPlaylist\"\n      @pause-player=\"pausePlayer\"\n      @move-video-up=\"moveVideoUp\"\n      @move-video-down=\"moveVideoDown\"\n      @remove-from-playlist=\"removeFromPlaylist\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\n\nimport FtListVideo from './ft-list-video/ft-list-video.vue'\n\nimport store from '../store/index'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  playlistId: {\n    type: String,\n    default: null\n  },\n  playlistType: {\n    type: String,\n    default: null\n  },\n  playlistIndex: {\n    type: Number,\n    default: null\n  },\n  playlistReverse: {\n    type: Boolean,\n    default: false\n  },\n  playlistShuffle: {\n    type: Boolean,\n    default: false\n  },\n  playlistLoop: {\n    type: Boolean,\n    default: false\n  },\n  playlistItemId: {\n    type: String,\n    default: null,\n  },\n  forceListType: {\n    type: String,\n    default: null\n  },\n  appearance: {\n    type: String,\n    required: true\n  },\n  initialVisibleState: {\n    type: Boolean,\n    default: false,\n  },\n  alwaysShowAddToPlaylistButton: {\n    type: Boolean,\n    default: false,\n  },\n  quickBookmarkButtonEnabled: {\n    type: Boolean,\n    default: true,\n  },\n  canMoveVideoUp: {\n    type: Boolean,\n    default: false,\n  },\n  canMoveVideoDown: {\n    type: Boolean,\n    default: false,\n  },\n  canRemoveFromPlaylist: {\n    type: Boolean,\n    default: false,\n  },\n  useChannelsHiddenPreference: {\n    type: Boolean,\n    default: false,\n  },\n  hideForbiddenTitles: {\n    type: Boolean,\n    default: true\n  }\n})\n\nconst visible = ref(props.initialVisibleState)\nconst display = ref('block')\n\nconst channelsHidden = computed(() => {\n  // Some component users like channel view will have this disabled\n  if (!props.useChannelsHiddenPreference) { return [] }\n\n  return JSON.parse(store.getters.getChannelsHidden).map((ch) => {\n    // Legacy support\n    if (typeof ch === 'string') {\n      return { name: ch, preferredName: '', icon: '' }\n    }\n    return ch\n  })\n})\n\nconst forbiddenTitles = computed(() => {\n  if (!props.hideForbiddenTitles) { return [] }\n  return JSON.parse(store.getters.getForbiddenTitles.toLowerCase())\n})\n\nconst hideChannelsBasedOnText = computed(() => {\n  return store.getters.getHideChannelsBasedOnText\n})\n\nconst shouldBeVisible = computed(() => {\n  const lowerCaseTitle = props.data.title?.toLowerCase()\n  const lowerCaseAuthor = props.data.author?.toLowerCase()\n\n  return !(channelsHidden.value.some(ch => ch.name === props.data.authorId) ||\n    channelsHidden.value.some(ch => ch.name === props.data.author) ||\n    (lowerCaseTitle && forbiddenTitles.value.some((text) => lowerCaseTitle.includes(text))) ||\n    (hideChannelsBasedOnText.value && lowerCaseAuthor && forbiddenTitles.value.some((text) => lowerCaseAuthor.includes(text))))\n})\n\n/**\n * @param {boolean} isVisible\n */\nfunction onVisibilityChanged(isVisible) {\n  if (isVisible && shouldBeVisible.value) {\n    visible.value = isVisible\n  } else if (isVisible) {\n    display.value = 'none'\n  }\n}\n\nconst emit = defineEmits(['pause-player', 'move-video-up', 'move-video-down', 'remove-from-playlist'])\n\nfunction pausePlayer() {\n  emit('pause-player')\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoUp(videoId, playlistItemId) {\n  emit('move-video-up', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoDown(videoId, playlistItemId) {\n  emit('move-video-down', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction removeFromPlaylist(videoId, playlistItemId) {\n  emit('remove-from-playlist', videoId, playlistItemId)\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/FtListVideoNumbered/FtListVideoNumbered.css",
    "content": "/*\n  Set a height to invisible/unloaded elements, so that lazy loading actually works.\n  If we don't set a height, they all get a height of 0px (because they have no content),\n  so they all bunch up together and end up loading all of them in one go.\n */\n.placeholder {\n  block-size: 40px;\n}\n\n.videoIndex {\n  color: var(--tertiary-text-color);\n  text-align: center;\n}\n\n.videoIndexIcon {\n  font-size: 14px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtListVideoNumbered/FtListVideoNumbered.vue",
    "content": "<template>\n  <div\n    v-observe-visibility=\"visible ? false : {\n      callback: onVisibilityChanged\n    }\"\n    :class=\"{ placeholder: !visible }\"\n  >\n    <template\n      v-if=\"visible\"\n    >\n      <p\n        class=\"videoIndex\"\n      >\n        <FontAwesomeIcon\n          v-if=\"isCurrentVideo\"\n          class=\"videoIndexIcon\"\n          :icon=\"['fas', 'play']\"\n        />\n        <template\n          v-else\n        >\n          {{ videoIndex + 1 }}\n        </template>\n      </p>\n      <FtListVideo\n        :data=\"data\"\n        :playlist-id=\"playlistId\"\n        :playlist-type=\"playlistType\"\n        :playlist-index=\"playlistIndex\"\n        :playlist-reverse=\"playlistReverse\"\n        :playlist-shuffle=\"playlistShuffle\"\n        :playlist-loop=\"playlistLoop\"\n        :playlist-item-id=\"playlistItemId\"\n        force-list-type=\"list\"\n        :appearance=\"appearance\"\n        :always-show-add-to-playlist-button=\"alwaysShowAddToPlaylistButton\"\n        :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n        :can-move-video-up=\"canMoveVideoUp\"\n        :can-move-video-down=\"canMoveVideoDown\"\n        :can-remove-from-playlist=\"canRemoveFromPlaylist\"\n        @pause-player=\"pausePlayer\"\n        @move-video-up=\"moveVideoUp\"\n        @move-video-down=\"moveVideoDown\"\n        @remove-from-playlist=\"removeFromPlaylist\"\n      />\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { ref, watch } from 'vue'\n\nimport FtListVideo from '../ft-list-video/ft-list-video.vue'\n\nconst props = defineProps({\n  data: {\n    type: Object,\n    required: true\n  },\n  playlistId: {\n    type: String,\n    default: null\n  },\n  playlistType: {\n    type: String,\n    default: null\n  },\n  playlistIndex: {\n    type: Number,\n    default: null\n  },\n  playlistReverse: {\n    type: Boolean,\n    default: false\n  },\n  playlistShuffle: {\n    type: Boolean,\n    default: false\n  },\n  playlistLoop: {\n    type: Boolean,\n    default: false\n  },\n  playlistItemId: {\n    type: String,\n    default: null,\n  },\n  appearance: {\n    type: String,\n    required: true\n  },\n  initialVisibleState: {\n    type: Boolean,\n    default: false,\n  },\n  alwaysShowAddToPlaylistButton: {\n    type: Boolean,\n    default: false,\n  },\n  quickBookmarkButtonEnabled: {\n    type: Boolean,\n    default: true,\n  },\n  canMoveVideoUp: {\n    type: Boolean,\n    default: false,\n  },\n  canMoveVideoDown: {\n    type: Boolean,\n    default: false,\n  },\n  canRemoveFromPlaylist: {\n    type: Boolean,\n    default: false,\n  },\n  videoIndex: {\n    type: Number,\n    default: -1\n  },\n  isCurrentVideo: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst emit = defineEmits(['move-video-down', 'move-video-up', 'pause-player', 'remove-from-playlist'])\n\nconst visible = ref(props.initialVisibleState)\n\nlet stopWatchingInitialVisibleState = null\n\nif (!props.initialVisibleState) {\n  stopWatchingInitialVisibleState = watch(() => props.initialVisibleState, (newValue) => {\n    visible.value = newValue\n    stopWatchingInitialVisibleState()\n    stopWatchingInitialVisibleState = null\n  })\n}\n\n/**\n * @param {boolean} isVisible\n */\nfunction onVisibilityChanged(isVisible) {\n  if (isVisible) {\n    visible.value = isVisible\n\n    if (stopWatchingInitialVisibleState) {\n      stopWatchingInitialVisibleState()\n      stopWatchingInitialVisibleState = null\n    }\n  }\n}\n\nfunction pausePlayer() {\n  emit('pause-player')\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoUp(videoId, playlistItemId) {\n  emit('move-video-up', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoDown(videoId, playlistItemId) {\n  emit('move-video-down', videoId, playlistItemId)\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction removeFromPlaylist(videoId, playlistItemId) {\n  emit('remove-from-playlist', videoId, playlistItemId)\n}\n</script>\n\n<style scoped src=\"./FtListVideoNumbered.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtLoader/FtLoader.css",
    "content": "/*\n    This file is part of FreeTube.\n\n    FreeTube is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    FreeTube is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with FreeTube.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n.container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  inline-size: 100%;\n  block-size: 100%;\n  padding: 0;\n  margin: 0;\n}\n\n.fullscreen {\n  block-size: 85vh;\n}\n\n/*\n* Thanks to @tobiasahlin for the loading animation.\n* Find it here: http://tobiasahlin.com/spinkit/\n* Twitter: https://twitter.com/tobiasahlin\n*/\n\n.spinner {\n  inline-size: 40px;\n  block-size: 40px;\n  position: relative;\n  margin-block: 100px;\n  margin-inline: auto;\n}\n\n.double-bounce1,\n.double-bounce2 {\n  inline-size: 100%;\n  block-size: 100%;\n  border-radius: 50%;\n  opacity: 0.6;\n  position: absolute;\n  inset-block-start: 0;\n  inset-inline-start: 0;\n  background-color: var(--primary-color);\n  animation: sk-bounce 2s infinite ease-in-out;\n}\n\n.double-bounce2 {\n  animation-delay: -1s;\n}\n\n@keyframes sk-bounce {\n  0%,\n  100% {\n    transform: scale(0);\n  }\n\n  50% {\n    transform: scale(1);\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtLoader/FtLoader.vue",
    "content": "<template>\n  <div\n    class=\"container\"\n    :class=\"{ fullscreen }\"\n  >\n    <div class=\"spinner\">\n      <div class=\"double-bounce1\" />\n      <div class=\"double-bounce2\" />\n    </div>\n  </div>\n</template>\n\n<script setup>\ndefineProps({\n  fullscreen: {\n    type: Boolean,\n    default: false\n  }\n})\n</script>\n\n<style scoped src=\"./FtLoader.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtLogoFull/FtLogoFull.css",
    "content": ".primary-color {\n  fill: var(--logo-primary-color);\n}\n\n.secondary-color {\n  fill: var(--logo-secondary-color);\n}\n\n.tertiary-color {\n  fill: var(--logo-tertiary-color);\n}\n"
  },
  {
    "path": "src/renderer/components/FtLogoFull/FtLogoFull.vue",
    "content": "<template>\n  <svg\n    viewBox=\"0 0 640 200\"\n    version=\"1.1\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xml:space=\"preserve\"\n  >\n    <g>\n      <path\n        class=\"tertiary-color\"\n        d=\"M610.803,154.398c0.141,0.306 0.212,0.603 0.212,0.893c-0,0.53 -0.208,0.98 -0.623,1.35c-0.415,0.37 -0.89,0.555 -1.422,0.555c-0.361,-0 -0.69,-0.097 -0.988,-0.29c-0.297,-0.192 -0.533,-0.482 -0.705,-0.868l-1.058,-2.435l-7.616,-0l-1.082,2.435c-0.172,0.386 -0.411,0.676 -0.717,0.868c-0.305,0.193 -0.638,0.29 -0.999,0.29c-0.533,-0 -1.015,-0.185 -1.446,-0.555c-0.431,-0.37 -0.646,-0.82 -0.646,-1.35c0,-0.29 0.071,-0.587 0.212,-0.893l6.206,-13.07c0.203,-0.435 0.505,-0.768 0.905,-1.001c0.399,-0.233 0.842,-0.35 1.328,-0.35c0.47,0 0.909,0.117 1.316,0.35c0.408,0.233 0.713,0.566 0.917,1.001l6.206,13.07Zm-6.041,-4.123l-2.351,-5.378l-2.351,5.378l4.702,-0Z\"\n      />\n      <path\n        class=\"tertiary-color\"\n        d=\"M620.206,144.969c0.988,0 1.869,0.261 2.645,0.784c0.776,0.522 1.379,1.258 1.81,2.206c0.431,0.949 0.647,2.034 0.647,3.256c-0,1.222 -0.216,2.295 -0.647,3.22c-0.431,0.924 -1.03,1.635 -1.798,2.134c-0.768,0.498 -1.654,0.747 -2.657,0.747c-0.736,0 -1.414,-0.152 -2.033,-0.458c-0.619,-0.305 -1.101,-0.715 -1.446,-1.23l0,4.1c0,0.563 -0.188,1.013 -0.564,1.351c-0.376,0.337 -0.87,0.506 -1.481,0.506c-0.643,0 -1.16,-0.181 -1.551,-0.543c-0.392,-0.361 -0.588,-0.824 -0.588,-1.386l-0,-12.661c-0,-0.595 0.184,-1.073 0.552,-1.435c0.369,-0.362 0.866,-0.543 1.493,-0.543c0.596,0 1.077,0.161 1.446,0.483c0.368,0.321 0.576,0.747 0.623,1.278c0.329,-0.563 0.811,-1.005 1.445,-1.327c0.635,-0.321 1.336,-0.482 2.104,-0.482Zm-1.269,9.14c0.721,0 1.273,-0.249 1.657,-0.748c0.384,-0.498 0.576,-1.213 0.576,-2.146c0,-0.981 -0.196,-1.732 -0.588,-2.255c-0.391,-0.522 -0.948,-0.784 -1.669,-0.784c-0.72,0 -1.277,0.258 -1.669,0.772c-0.391,0.515 -0.587,1.254 -0.587,2.219c-0,0.948 0.196,1.676 0.587,2.182c0.392,0.507 0.956,0.76 1.693,0.76Z\"\n      />\n      <path\n        class=\"tertiary-color\"\n        d=\"M634.899,144.969c0.987,0 1.869,0.261 2.644,0.784c0.776,0.522 1.38,1.258 1.811,2.206c0.431,0.949 0.646,2.034 0.646,3.256c0,1.222 -0.215,2.295 -0.646,3.22c-0.431,0.924 -1.031,1.635 -1.799,2.134c-0.768,0.498 -1.653,0.747 -2.656,0.747c-0.737,0 -1.415,-0.152 -2.034,-0.458c-0.619,-0.305 -1.101,-0.715 -1.445,-1.23l-0,4.1c-0,0.563 -0.188,1.013 -0.565,1.351c-0.376,0.337 -0.869,0.506 -1.481,0.506c-0.642,0 -1.159,-0.181 -1.551,-0.543c-0.392,-0.361 -0.588,-0.824 -0.588,-1.386l0,-12.661c0,-0.595 0.184,-1.073 0.553,-1.435c0.368,-0.362 0.866,-0.543 1.492,-0.543c0.596,0 1.078,0.161 1.446,0.483c0.368,0.321 0.576,0.747 0.623,1.278c0.329,-0.563 0.811,-1.005 1.446,-1.327c0.635,-0.321 1.336,-0.482 2.104,-0.482Zm-1.27,9.14c0.721,0 1.274,-0.249 1.658,-0.748c0.384,-0.498 0.576,-1.213 0.576,-2.146c-0,-0.981 -0.196,-1.732 -0.588,-2.255c-0.392,-0.522 -0.948,-0.784 -1.669,-0.784c-0.721,0 -1.277,0.258 -1.669,0.772c-0.392,0.515 -0.588,1.254 -0.588,2.219c0,0.948 0.196,1.676 0.588,2.182c0.392,0.507 0.956,0.76 1.692,0.76Z\"\n      />\n    </g>\n    <path\n      class=\"primary-color\"\n      d=\"M242.417,136.617c-1.853,0 -3.339,-0.575 -4.457,-1.725c-1.118,-1.15 -1.677,-2.652 -1.677,-4.504l-0,-56.063c-0,-1.853 0.527,-3.29 1.582,-4.312c1.054,-1.023 2.507,-1.534 4.36,-1.534l33.638,0c3.897,0 5.845,1.661 5.845,4.984c-0,3.258 -1.948,4.887 -5.845,4.887l-27.409,0l-0,18.4l25.492,0c3.897,0 5.846,1.661 5.846,4.983c-0,3.259 -1.949,4.888 -5.846,4.888l-25.492,0l-0,23.767c-0,1.852 -0.543,3.354 -1.629,4.504c-1.086,1.15 -2.556,1.725 -4.408,1.725Z\"\n    />\n    <path\n      class=\"primary-color\"\n      d=\"M309.673,88.221c1.503,-0.128 2.688,0.223 3.555,1.054c0.868,0.831 1.301,2.076 1.301,3.737c-0,1.725 -0.376,3.003 -1.127,3.834c-0.752,0.83 -2.11,1.373 -4.076,1.629l-2.601,0.287c-3.411,0.384 -5.911,1.662 -7.501,3.834c-1.59,2.172 -2.385,4.887 -2.385,8.146l-0,20.125c-0,1.852 -0.52,3.274 -1.561,4.264c-1.04,0.991 -2.341,1.486 -3.902,1.486c-1.561,0 -2.847,-0.495 -3.858,-1.486c-1.012,-0.99 -1.518,-2.412 -1.518,-4.264l-0,-37.088c-0,-1.789 0.506,-3.162 1.518,-4.121c1.011,-0.958 2.269,-1.437 3.772,-1.437c1.503,0 2.717,0.463 3.642,1.389c0.925,0.927 1.387,2.252 1.387,3.977l-0,3.834c1.098,-2.811 2.732,-4.984 4.899,-6.517c2.168,-1.533 4.582,-2.396 7.241,-2.587l1.214,-0.096Z\"\n    />\n    <path\n      class=\"primary-color\"\n      d=\"M360.691,123.2c1.136,0 2.054,0.415 2.756,1.246c0.701,0.83 1.052,1.948 1.052,3.354c-0,1.981 -1.236,3.642 -3.708,4.983c-2.272,1.214 -4.844,2.189 -7.717,2.923c-2.873,0.735 -5.612,1.102 -8.218,1.102c-7.884,0 -14.131,-2.172 -18.741,-6.516c-4.61,-4.345 -6.915,-10.286 -6.915,-17.825c-0,-4.792 1.002,-9.041 3.007,-12.746c2.004,-3.706 4.827,-6.581 8.468,-8.625c3.641,-2.045 7.767,-3.067 12.377,-3.067c4.41,0 8.252,0.927 11.525,2.779c3.274,1.853 5.813,4.473 7.617,7.859c1.804,3.386 2.706,7.379 2.706,11.979c-0,2.747 -1.269,4.121 -3.808,4.121l-29.565,0c0.401,4.408 1.704,7.65 3.909,9.727c2.204,2.076 5.411,3.114 9.621,3.114c2.138,0 4.025,-0.255 5.662,-0.766c1.637,-0.511 3.491,-1.214 5.562,-2.109c2.005,-1.022 3.474,-1.533 4.41,-1.533Zm-17.338,-26.738c-3.408,0 -6.13,1.023 -8.168,3.067c-2.038,2.045 -3.257,4.983 -3.658,8.817l22.65,0c-0.134,-3.897 -1.136,-6.852 -3.007,-8.865c-1.871,-2.012 -4.477,-3.019 -7.817,-3.019Z\"\n    />\n    <path\n      class=\"primary-color\"\n      d=\"M415.049,123.2c1.136,0 2.055,0.415 2.756,1.246c0.702,0.83 1.052,1.948 1.052,3.354c-0,1.981 -1.236,3.642 -3.708,4.983c-2.271,1.214 -4.844,2.189 -7.717,2.923c-2.872,0.735 -5.612,1.102 -8.218,1.102c-7.883,0 -14.13,-2.172 -18.741,-6.516c-4.61,-4.345 -6.915,-10.286 -6.915,-17.825c-0,-4.792 1.003,-9.041 3.007,-12.746c2.004,-3.706 4.827,-6.581 8.468,-8.625c3.642,-2.045 7.767,-3.067 12.378,-3.067c4.409,0 8.251,0.927 11.525,2.779c3.274,1.853 5.812,4.473 7.616,7.859c1.804,3.386 2.706,7.379 2.706,11.979c-0,2.747 -1.269,4.121 -3.808,4.121l-29.565,0c0.401,4.408 1.704,7.65 3.909,9.727c2.205,2.076 5.412,3.114 9.621,3.114c2.138,0 4.025,-0.255 5.662,-0.766c1.637,-0.511 3.491,-1.214 5.562,-2.109c2.005,-1.022 3.475,-1.533 4.41,-1.533Zm-17.338,-26.738c-3.407,0 -6.13,1.023 -8.168,3.067c-2.037,2.045 -3.257,4.983 -3.658,8.817l22.65,0c-0.134,-3.897 -1.136,-6.852 -3.007,-8.865c-1.87,-2.012 -4.476,-3.019 -7.817,-3.019Z\"\n    />\n    <path\n      class=\"secondary-color\"\n      d=\"M452.658,136.617c-2.137,0 -4.861,-0.672 -6.173,-2.016c-1.313,-1.343 -1.969,-3.135 -1.969,-5.374l-0,-48.56l-13.833,0c-4.517,0 -6.775,-2.047 -6.775,-6.142c-0,-4.03 2.258,-6.046 6.775,-6.046l43.949,0c4.517,0 6.776,2.016 6.776,6.046c-0,4.095 -2.259,6.142 -6.776,6.142l-13.833,0l0,48.56c0,2.239 -0.64,4.031 -1.922,5.374c-1.282,1.344 -4.022,2.016 -6.219,2.016Z\"\n    />\n    <path\n      class=\"secondary-color\"\n      d=\"M515.741,88.529c2.236,0 4.009,0.607 5.319,1.821c1.31,1.214 1.964,2.875 1.964,4.983l-0,35.171c-0,1.981 -0.686,3.578 -2.06,4.792c-1.374,1.214 -3.147,1.821 -5.319,1.821c-2.044,0 -3.673,-0.575 -4.887,-1.725c-1.214,-1.15 -1.821,-2.684 -1.821,-4.6l-0,-0.959c-1.47,2.428 -3.402,4.281 -5.798,5.559c-2.396,1.277 -5.095,1.916 -8.098,1.916c-5.942,0 -10.366,-1.645 -13.273,-4.935c-2.907,-3.29 -4.36,-8.258 -4.36,-14.902l-0,-22.138c-0,-2.108 0.655,-3.769 1.964,-4.983c1.31,-1.214 3.083,-1.821 5.319,-1.821c2.236,0 3.993,0.607 5.271,1.821c1.278,1.214 1.917,2.875 1.917,4.983l-0,22.425c-0,2.811 0.591,4.888 1.772,6.23c1.182,1.341 2.987,2.012 5.415,2.012c2.811,0 5.095,-0.958 6.852,-2.875c1.757,-1.917 2.636,-4.44 2.636,-7.571l-0,-20.221c-0,-2.108 0.638,-3.769 1.916,-4.983c1.278,-1.214 3.035,-1.821 5.271,-1.821Z\"\n    />\n    <path\n      class=\"secondary-color\"\n      d=\"M563.858,88.338c4.171,-0.001 7.853,0.99 11.046,2.97c3.193,1.981 5.686,4.808 7.478,8.482c1.792,3.673 2.688,7.938 2.688,12.793c-0,4.856 -0.896,9.152 -2.688,12.89c-1.792,3.737 -4.301,6.644 -7.527,8.721c-3.226,2.076 -6.891,3.114 -10.997,3.114c-3.324,-0 -6.321,-0.686 -8.993,-2.06c-2.672,-1.374 -4.725,-3.274 -6.159,-5.702l-0,0.766c-0,2.045 -0.651,3.69 -1.955,4.936c-1.303,1.246 -3.063,1.869 -5.278,1.869c-2.216,-0 -3.992,-0.623 -5.328,-1.869c-1.336,-1.246 -2.004,-2.891 -2.004,-4.936l0,-55.2c0,-1.98 0.701,-3.577 2.102,-4.791c1.401,-1.214 3.242,-1.821 5.523,-1.821c2.15,-0 3.877,0.575 5.181,1.725c1.303,1.15 1.955,2.683 1.955,4.6l-0,20.987c1.433,-2.363 3.47,-4.2 6.109,-5.51c2.64,-1.31 5.588,-1.965 8.847,-1.965l-0,0.001Zm-4.301,37.95c3.454,-0 6.126,-1.197 8.016,-3.593c1.889,-2.396 2.834,-5.766 2.834,-10.111c0,-4.28 -0.945,-7.555 -2.834,-9.823c-1.89,-2.268 -4.562,-3.402 -8.016,-3.402c-3.454,0 -6.126,1.166 -8.016,3.498c-1.89,2.332 -2.835,5.638 -2.835,9.919c-0,4.344 0.945,7.683 2.835,10.015c1.89,2.332 4.562,3.498 8.016,3.498l0,-0.001Z\"\n    />\n    <path\n      class=\"secondary-color\"\n      d=\"M635.013,122.55c1.385,0 2.511,0.511 3.377,1.533c0.865,1.023 1.298,2.332 1.298,3.929c-0,1.087 -0.346,2.093 -1.039,3.019c-0.692,0.927 -1.662,1.709 -2.909,2.348c-2.354,1.15 -5.09,2.093 -8.207,2.827c-3.117,0.735 -5.991,1.102 -8.623,1.102c-5.541,0 -10.372,-0.99 -14.493,-2.971c-4.121,-1.98 -7.289,-4.807 -9.506,-8.481c-2.216,-3.673 -3.324,-8.002 -3.324,-12.985c0,-4.792 1.073,-9.04 3.221,-12.746c2.147,-3.706 5.125,-6.597 8.934,-8.673c3.809,-2.076 8.138,-3.115 12.986,-3.115c4.641,0 8.71,0.943 12.208,2.828c3.497,1.884 6.216,4.568 8.155,8.05c1.939,3.482 2.909,7.554 2.909,12.218c0,1.406 -0.364,2.476 -1.091,3.211c-0.727,0.734 -1.749,1.102 -3.065,1.102l-29.089,0c0.485,3.769 1.731,6.501 3.74,8.194c2.009,1.693 4.883,2.539 8.623,2.539c2.009,0 3.809,-0.223 5.402,-0.671c1.593,-0.447 3.359,-1.054 5.299,-1.821c0.969,-0.383 1.904,-0.718 2.805,-1.006c0.9,-0.287 1.697,-0.431 2.389,-0.431Zm-17.869,-24.246c-2.978,-0 -5.368,0.879 -7.168,2.636c-1.801,1.757 -2.875,4.296 -3.221,7.618l20.051,-0c-0.208,-3.386 -1.126,-5.941 -2.753,-7.666c-1.628,-1.725 -3.931,-2.588 -6.909,-2.588Z\"\n    />\n    <path\n      class=\"primary-color\"\n      d=\"M39.222,0c7.499,0 13.578,6.079 13.578,13.578l0,186.422l-18.639,0c-9.06,0 -17.749,-3.599 -24.155,-10.006c-6.407,-6.406 -10.006,-15.095 -10.006,-24.155l0,-152.261c0,-7.499 6.079,-13.578 13.578,-13.578l25.644,0Zm160.778,-0l0,16.174c0,9.713 -3.859,19.029 -10.728,25.898c-6.869,6.869 -16.185,10.728 -25.898,10.728l-88.33,0c-7.425,0 -13.444,-6.019 -13.444,-13.444l0,-25.912c0,-7.425 6.019,-13.444 13.444,-13.444l124.956,-0Z\"\n    />\n    <path\n      class=\"secondary-color\"\n      d=\"M143.486,97.784c1.755,0.87 2.864,2.658 2.864,4.616c0,1.958 -1.109,3.746 -2.864,4.616l-74.185,36.767c-1.653,0.819 -3.612,0.726 -5.179,-0.246c-1.568,-0.973 -2.522,-2.687 -2.522,-4.532l0,-73.21c0,-1.845 0.954,-3.559 2.522,-4.532c1.567,-0.972 3.526,-1.065 5.179,-0.246l74.185,36.767Z\"\n    />\n  </svg>\n</template>\n\n<style scoped src=\"./FtLogoFull.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtNotificationBanner/FtNotificationBanner.css",
    "content": ".ftNotificationBanner {\n  background-color: var(--primary-color);\n  color: var(--text-with-main-color);\n\n  /*\n  background-color: var(--accent-color);\n  color: var(--text-with-accent-color);\n  */\n  margin: 4px;\n  padding-block: 3px 5px;\n  padding-inline: 16px;\n  box-shadow: 0 1px 2px rgb(0 0 0 / 10%);\n  position: relative;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n}\n\n.ftNotificationBanner:focus {\n  box-shadow: 20px 20px 20px rgb(0 0 0 / 10%);\n}\n\n.message {\n  flex-grow: 1;\n}\n\n.closeButton {\n  background-color: transparent;\n  border-style: none;\n  color: inherit;\n  cursor: pointer;\n  font-size: 1em;\n  line-height: 1em;\n  padding: 0.4em;\n}\n\n.closeIcon {\n  inline-size: 1em;\n}\n\n@media only screen and (width <= 680px) {\n  .closeButton {\n    font-size: 1.6em;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtNotificationBanner/FtNotificationBanner.vue",
    "content": "<template>\n  <div\n    class=\"ftNotificationBanner\"\n    tabindex=\"0\"\n    role=\"link\"\n    :title=\"message\"\n    :aria-describedby=\"id\"\n    @click=\"handleClick\"\n    @keydown.enter.prevent=\"handleClick\"\n    @keydown.space.prevent=\"handleClick\"\n  >\n    <p\n      :id=\"id\"\n      class=\"message\"\n    >\n      {{ message }}\n    </p>\n    <button\n      class=\"closeButton\"\n      :aria-label=\"$t('Close Banner')\"\n      :title=\"$t('Close Banner')\"\n      @click.stop=\"handleClose\"\n      @keydown.enter.space.stop\n    >\n      <FontAwesomeIcon\n        class=\"closeIcon\"\n        :icon=\"['fas', 'times']\"\n      />\n    </button>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useId } from 'vue'\n\ndefineProps({\n  message: {\n    type: String,\n    required: true\n  }\n})\n\nconst emit = defineEmits(['click'])\n\nconst id = useId()\n\nfunction handleClick() {\n  emit('click', true)\n}\n\nfunction handleClose() {\n  emit('click', false)\n}\n</script>\n\n<style scoped src=\"./FtNotificationBanner.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtPlaylistAddVideoPrompt/FtPlaylistAddVideoPrompt.css",
    "content": ".selected-count {\n  text-align: center;\n}\n\n.searchInputsRow {\n  display: grid;\n\n  /* 2 columns */\n  grid-template-columns: 1fr auto;\n  column-gap: 16px;\n}\n\n@media only screen and (width <= 800px) {\n  .searchInputsRow {\n    /* Switch to 2 rows from 2 columns */\n    grid-template-columns: auto;\n    grid-template-rows: auto auto;\n  }\n}\n\n.optionsRow {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));\n  align-items: center;\n}\n\n.tightOptions {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(100px, max-content));\n  column-gap: 16px;\n  align-items: center;\n}\n\n@media only screen and (width <= 800px) {\n  .optionsRow {\n    /* Switch to rows from columns */\n    grid-template-columns: auto;\n    align-items: stretch;\n  }\n\n  .tightOptions {\n    /* Switch to rows from columns */\n    grid-template-columns: auto;\n    align-items: stretch;\n  }\n}\n\n.sortSelect {\n  /* Put it on the right */\n  margin-inline-start: auto;\n}\n\n.playlists-container {\n  box-shadow: inset 0 0 5px rgb(0 0 0 / 50%);\n\n  /* Use remaining height */\n  flex-grow: 1;\n  overflow-y: scroll;\n}\n\n.playlist-selector-container:not(.disabled) {\n  /* Make them look selectable */\n  cursor: pointer;\n}\n\n.playlist-selector-container.disabled {\n  opacity: 0.5;\n}\n"
  },
  {
    "path": "src/renderer/components/FtPlaylistAddVideoPrompt/FtPlaylistAddVideoPrompt.vue",
    "content": "<template>\n  <FtPrompt\n    theme=\"flex-column\"\n    :label=\"title\"\n    :inert=\"showingCreatePlaylistPrompt\"\n    @click=\"hide\"\n  >\n    <p class=\"selected-count\">\n      {{ t('User Playlists.AddVideoPrompt.N playlists selected', {\n        playlistCount: selectedPlaylistCount,\n      }, selectedPlaylistCount) }}\n    </p>\n    <div\n      v-if=\"allPlaylists.length > 1\"\n      class=\"searchInputsRow\"\n    >\n      <FtInput\n        ref=\"searchBar\"\n        :placeholder=\"t('User Playlists.AddVideoPrompt.Search in Playlists')\"\n        :show-clear-text-button=\"true\"\n        :show-action-button=\"false\"\n        :maxlength=\"255\"\n        @input=\"updateQueryDebounce\"\n        @clear=\"updateQueryDebounce('')\"\n      />\n    </div>\n    <div\n      v-if=\"allPlaylists.length > 1\"\n      class=\"optionsRow\"\n    >\n      <div\n        class=\"tightOptions\"\n      >\n        <FtToggleSwitch\n          class=\"matchingVideoToggle\"\n          :label=\"t('User Playlists.Playlists with Matching Videos')\"\n          :compact=\"true\"\n          :default-value=\"doSearchPlaylistsWithMatchingVideos\"\n          @change=\"doSearchPlaylistsWithMatchingVideos = !doSearchPlaylistsWithMatchingVideos\"\n        />\n        <FtToggleSwitch\n          v-if=\"anyPlaylistContainsVideosToBeAdded\"\n          class=\"allowDuplicateToggle\"\n          :label=\"t('User Playlists.AddVideoPrompt.Allow Adding Duplicate Video(s)')\"\n          :compact=\"true\"\n          :default-value=\"addingDuplicateVideosEnabled\"\n          @change=\"addingDuplicateVideosEnabled = !addingDuplicateVideosEnabled\"\n        />\n      </div>\n      <FtSelect\n        class=\"sortSelect\"\n        :value=\"sortBy\"\n        :select-names=\"sortBySelectNames\"\n        :select-values=\"SORT_BY_SELECT_VALUES\"\n        :placeholder=\"t('Global.Sort By')\"\n        :icon=\"sortBySelectIcon\"\n        @change=\"sortBy = $event\"\n      />\n    </div>\n    <div class=\"playlists-container\">\n      <FtFlexBox>\n        <div\n          v-for=\"playlist in activePlaylists\"\n          :key=\"playlist._id\"\n          class=\"playlist-selector-container\"\n          :class=\"{\n            disabled: playlistDisabled(playlist._id),\n          }\"\n          :aria-disabled=\"playlistDisabled(playlist._id)\"\n        >\n          <FtPlaylistSelector\n            :tabindex=\"playlistDisabled(playlist._id) ? -1 : 0\"\n            :playlist=\"playlist\"\n            :selected=\"selectedPlaylistIdList.includes(playlist._id)\"\n            :disabled=\"playlistDisabled(playlist._id)\"\n            :adding-duplicate-videos-enabled=\"addingDuplicateVideosEnabled\"\n            @selected=\"countSelected\"\n          />\n        </div>\n      </FtFlexBox>\n    </div>\n    <div class=\"actions-container\">\n      <FtFlexBox>\n        <FtButton\n          :label=\"t('User Playlists.Create New Playlist')\"\n          @click=\"openCreatePlaylistPrompt\"\n        />\n        <FtButton\n          :label=\"t('User Playlists.AddVideoPrompt.Save')\"\n          @click=\"addSelectedToPlaylists\"\n        />\n        <FtButton\n          :label=\"t('User Playlists.Cancel')\"\n          :text-color=\"null\"\n          :background-color=\"null\"\n          @click=\"hide\"\n        />\n      </FtFlexBox>\n    </div>\n  </FtPrompt>\n</template>\n\n<script setup>\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtPlaylistSelector from '../FtPlaylistSelector/FtPlaylistSelector.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../../store/index'\n\nimport {\n  debounce,\n  showToast,\n  ctrlFHandler,\n  getIconForSortPreference\n} from '../../helpers/utils'\n\nconst { locale, t } = useI18n()\n\nconst SORT_BY_VALUES = {\n  NameAscending: 'name_ascending',\n  NameDescending: 'name_descending',\n\n  LatestCreatedFirst: 'latest_created_first',\n  EarliestCreatedFirst: 'earliest_created_first',\n\n  LatestUpdatedFirst: 'latest_updated_first',\n  EarliestUpdatedFirst: 'earliest_updated_first',\n}\n\nconst SORT_BY_SELECT_VALUES = Object.values(SORT_BY_VALUES)\n\nconst sortBySelectNames = computed(() => {\n  return SORT_BY_SELECT_VALUES.map((k) => {\n    switch (k) {\n      case SORT_BY_VALUES.NameAscending:\n        return t('User Playlists.Sort By.NameAscending')\n      case SORT_BY_VALUES.NameDescending:\n        return t('User Playlists.Sort By.NameDescending')\n      case SORT_BY_VALUES.LatestCreatedFirst:\n        return t('User Playlists.Sort By.LatestCreatedFirst')\n      case SORT_BY_VALUES.EarliestCreatedFirst:\n        return t('User Playlists.Sort By.EarliestCreatedFirst')\n      case SORT_BY_VALUES.LatestUpdatedFirst:\n        return t('User Playlists.Sort By.LatestUpdatedFirst')\n      case SORT_BY_VALUES.EarliestUpdatedFirst:\n        return t('User Playlists.Sort By.EarliestUpdatedFirst')\n      default:\n        console.error(`Unknown sortBy: ${k}`)\n        return k\n    }\n  })\n})\n\n/** @type {import('vue').Ref<'name_ascending' | 'name_descending' | 'latest_created_first' | 'earliest_created_first' | 'latest_updated_first' | 'earliest_updated_first'>} */\nconst sortBy = ref(SORT_BY_VALUES.LatestUpdatedFirst)\n\nconst sortBySelectIcon = computed(() => getIconForSortPreference(sortBy.value))\n\n/** @type {Set<string>} */\nconst createdSincePromptShownPlaylistIdList = new Set()\n\n/** @type {import('vue').Ref<string[]>} */\nconst selectedPlaylistIdList = ref([])\nconst query = ref('')\nconst doSearchPlaylistsWithMatchingVideos = ref(false)\nconst lastShownAt = Date.now()\nconst addingDuplicateVideosEnabled = ref(false)\n\nconst title = computed(() => {\n  return t('User Playlists.AddVideoPrompt.Select a playlist to add your N videos to', {\n    videoCount: toBeAddedToPlaylistVideoCount.value,\n  }, toBeAddedToPlaylistVideoCount.value)\n})\n\nconst selectedPlaylistCount = computed(() => selectedPlaylistIdList.value.length)\n\n/** @type {import('vue').ComputedRef<{ videoId: string, [key: string]: any }[]>} */\nconst toBeAddedToPlaylistVideoList = computed(() => store.getters.getToBeAddedToPlaylistVideoList)\n\nconst toBeAddedToPlaylistVideoCount = computed(() => toBeAddedToPlaylistVideoList.value.length)\n\nconst toBeAddedToPlaylistVideoIdList = computed(() => {\n  return toBeAddedToPlaylistVideoList.value.map((v) => v.videoId)\n})\n\nconst cachedCollator = computed(() => new Intl.Collator([locale.value, 'en'], { sensitivity: 'base' }))\n\n/** @type {import('vue').ComputedRef<object[]>} */\nconst allPlaylists = computed(() => {\n  const collator = cachedCollator.value\n\n  return store.getters.getAllPlaylists.toSorted((a, b) => {\n    switch (sortBy.value) {\n      case SORT_BY_VALUES.NameAscending:\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_VALUES.NameDescending:\n        return collator.compare(b.playlistName, a.playlistName)\n      case SORT_BY_VALUES.LatestCreatedFirst: {\n        if (a.createdAt > b.createdAt) { return -1 }\n        if (a.createdAt < b.createdAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      }\n      case SORT_BY_VALUES.EarliestCreatedFirst: {\n        if (a.createdAt < b.createdAt) { return -1 }\n        if (a.createdAt > b.createdAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      }\n      case SORT_BY_VALUES.LatestUpdatedFirst: {\n        if (a.lastUpdatedAt > b.lastUpdatedAt) { return -1 }\n        if (a.lastUpdatedAt < b.lastUpdatedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      }\n      case SORT_BY_VALUES.EarliestUpdatedFirst: {\n        if (a.lastUpdatedAt < b.lastUpdatedAt) { return -1 }\n        if (a.lastUpdatedAt > b.lastUpdatedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      }\n      default:\n        console.error(`Unknown sortBy: ${sortBy.value}`)\n        return 0\n    }\n  })\n})\n\nconst allPlaylistsLength = computed(() => allPlaylists.value.length)\n\nconst processedQuery = computed(() => query.value.trim().toLowerCase())\n\nconst activePlaylists = computed(() => {\n  const processedQuery_ = processedQuery.value\n\n  // Very rare that a playlist name only has 1 char\n  if (processedQuery_.length === 0) { return allPlaylists.value }\n\n  return allPlaylists.value.filter((playlist) => {\n    if (typeof playlist.playlistName !== 'string') {\n      return false\n    }\n\n    if (\n      doSearchPlaylistsWithMatchingVideos.value &&\n      playlist.videos.some((v) => {\n        return v.author?.toLowerCase().includes(processedQuery_) || v.title.toLowerCase().includes(processedQuery_)\n      })\n    ) {\n      return true\n    }\n\n    return playlist.playlistName.toLowerCase().includes(processedQuery_)\n  })\n})\n\nconst playlistIdsContainingVideosToBeAdded = computed(() => {\n  /** @type {Set<string>} */\n  const ids = new Set()\n\n  const toBeAddedToPlaylistVideoIdList_ = toBeAddedToPlaylistVideoIdList.value\n\n  allPlaylists.value.forEach((playlist) => {\n    const playlistVideoIdSet = playlist.videos.reduce((s, v) => s.add(v.videoId), new Set())\n\n    if (toBeAddedToPlaylistVideoIdList_.some((vid) => playlistVideoIdSet.has(vid))) {\n      ids.add(playlist._id)\n    }\n  })\n\n  return ids\n})\n\nconst anyPlaylistContainsVideosToBeAdded = computed(() => {\n  return playlistIdsContainingVideosToBeAdded.value.size > 0\n})\n\nconst searchBar = useTemplateRef('searchBar')\n\nwatch(allPlaylistsLength, (val, oldVal) => {\n  const allPlaylistIds = new Set()\n\n  // Add new playlists to selected\n  allPlaylists.value.forEach((playlist) => {\n    allPlaylistIds.add(playlist._id)\n\n    if (\n      // Old playlists don't have `createdAt`\n      playlist.createdAt == null ||\n      // Only playlists created after this prompt shown should be considered\n      playlist.createdAt < lastShownAt ||\n      // Only playlists not auto added to selected yet should be considered\n      createdSincePromptShownPlaylistIdList.has(playlist._id)\n    ) {\n      return\n    }\n\n    // Add newly created playlists to selected ONCE\n    createdSincePromptShownPlaylistIdList.add(playlist._id)\n    selectedPlaylistIdList.value.push(playlist._id)\n  })\n\n  // Remove  deleted playlist from deleted\n  selectedPlaylistIdList.value = selectedPlaylistIdList.value.filter(playlistId => {\n    return allPlaylistIds.has(playlistId)\n  })\n\n  if (val > oldVal) {\n    // Only move focus back to search input when a playlist was added,\n    // to allow searching for and deselecting the new created playlist more easily.\n    nextTick(() => {\n      searchBar.value?.focus()\n    })\n  }\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showingCreatePlaylistPrompt = computed(() => store.getters.getShowCreatePlaylistPrompt)\n\nwatch(showingCreatePlaylistPrompt, (val) => {\n  if (!val) {\n    // Only care when CreatePlaylistPrompt hidden\n    // Shift focus from button to prevent unwanted click event\n    // due to enter key press in CreatePlaylistPrompt\n    nextTick(() => {\n      searchBar.value?.focus()\n    })\n  }\n})\n\nwatch(addingDuplicateVideosEnabled, (val) => {\n  if (!val) {\n    // Only care when addingDuplicateVideosEnabled disabled\n    // Remove disabled playlists\n    selectedPlaylistIdList.value = selectedPlaylistIdList.value.filter(playlistId => {\n      return !playlistIdsContainingVideosToBeAdded.value.has(playlistId)\n    })\n  }\n})\n\nfunction hide() {\n  store.dispatch('hideAddToPlaylistPrompt')\n}\n\n/**\n * @param {string} playlistId\n */\nfunction countSelected(playlistId) {\n  const index = selectedPlaylistIdList.value.indexOf(playlistId)\n\n  if (index !== -1) {\n    selectedPlaylistIdList.value.splice(index, 1)\n  } else {\n    selectedPlaylistIdList.value.push(playlistId)\n  }\n}\n\nfunction addSelectedToPlaylists() {\n  const addedPlaylistIds = new Set()\n\n  if (selectedPlaylistIdList.value.length === 0) {\n    showToast(t('User Playlists.AddVideoPrompt.Toast[\"You haven\\'t selected any playlist yet.\"]'))\n    return\n  }\n\n  const allPlaylists_ = allPlaylists.value\n  const toBeAddedToPlaylistVideoList_ = toBeAddedToPlaylistVideoList.value\n\n  selectedPlaylistIdList.value.forEach((selectedPlaylistId) => {\n    const playlist = allPlaylists_.find((list) => list._id === selectedPlaylistId)\n    if (playlist == null) { return }\n\n    let videosToBeAdded\n\n    if (!addingDuplicateVideosEnabled.value) {\n      const playlistVideoIds = playlist.videos.map((v) => v.videoId)\n      videosToBeAdded = toBeAddedToPlaylistVideoList_.filter((v) => !playlistVideoIds.includes(v.videoId))\n    } else {\n      // Use slice() to avoid `do not mutate vuex store state outside mutation handlers`\n      videosToBeAdded = toBeAddedToPlaylistVideoList_.slice()\n    }\n\n    store.dispatch('addVideos', {\n      _id: playlist._id,\n      videos: videosToBeAdded,\n    })\n\n    addedPlaylistIds.add(playlist._id)\n  })\n\n  showToast(t('User Playlists.AddVideoPrompt.Toast.Video(s) added to {playlistCount} playlists', {\n    playlistCount: addedPlaylistIds.size,\n  }, addedPlaylistIds.size))\n\n  hide()\n}\n\n/** @type {import('vue').ComputedRef<object>} */\nconst newPlaylistDefaultProperties = computed(() => store.getters.getNewPlaylistDefaultProperties)\n\nfunction openCreatePlaylistPrompt() {\n  store.dispatch('showCreatePlaylistPrompt', {\n    title: newPlaylistDefaultProperties.value.title || '',\n  })\n}\n\nconst updateQueryDebounce = debounce(/** @param {string} query_ */(query_) => {\n  query.value = query_\n}, 500)\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n\n  // User might want to search first if they have many playlists\n  nextTick(() => {\n    searchBar.value?.focus()\n  })\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchBar.value)\n}\n\n/**\n * @param {string} playlistId\n */\nfunction playlistDisabled(playlistId) {\n  if (addingDuplicateVideosEnabled.value) {\n    return false\n  }\n\n  return playlistIdsContainingVideosToBeAdded.value.has(playlistId)\n}\n</script>\n\n<style scoped src=\"./FtPlaylistAddVideoPrompt.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtPlaylistSelector/FtPlaylistSelector.scss",
    "content": ".ft-playlist-selector {\n  padding: 6px;\n\n  &:hover ,\n  &.selected {\n    background-color: var(--bg-color);\n\n    .thumbnailImage {\n      opacity: 0.3;\n    }\n  }\n\n  .thumbnail {\n    position: relative;\n\n    .videoCountContainer {\n      position: absolute;\n      inset-inline-end: 0;\n      inset-block: 0;\n      inline-size: 60px;\n      font-size: 20px;\n\n      .background,\n      .inner {\n        position: absolute;\n        inset: 0;\n      }\n\n      .background {\n        background-color: var(--bg-color);\n        opacity: 0.9;\n      }\n\n      .inner {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        align-items: center;\n        color: var(--primary-text-color);\n      }\n    }\n  }\n\n  .info {\n    flex: 1;\n    position: relative;\n\n    .title {\n      font-size: 20px;\n      text-decoration: none;\n      overflow-wrap: break-word;\n    }\n\n    .videoPresenceCount {\n      margin-block-start: 4px;\n    }\n  }\n\n  &.grid {\n    display: flex;\n    flex-direction: column;\n    inline-size: 245px;\n    min-block-size: 230px;\n    padding-block-end: 20px;\n\n    .thumbnail {\n      margin-block-end: 12px;\n\n      .thumbnailImage {\n        inline-size: 100%;\n        // Ensure placeholder image displayed at same aspect ratio as most other images\n        aspect-ratio: 16/9;\n      }\n    }\n\n    .title {\n      font-size: 22px;\n    }\n  }\n}\n\n.selectedIcon {\n  position: absolute;\n  inset-block-start: calc(50% - 25px);\n  inset-inline-start: calc(50% - 25px);\n  font-size: 50px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtPlaylistSelector/FtPlaylistSelector.vue",
    "content": "<template>\n  <div\n    class=\"ft-playlist-selector grid\"\n    :class=\"{ selected }\"\n    @click=\"toggleSelection\"\n    @keydown.enter.prevent=\"toggleSelection\"\n    @keydown.space.prevent=\"toggleSelection\"\n  >\n    <div\n      class=\"thumbnail\"\n    >\n      <FontAwesomeIcon\n        v-if=\"selected\"\n        class=\"selectedIcon\"\n        :icon=\"['fas', 'check']\"\n      />\n      <img\n        alt=\"\"\n        :src=\"thumbnail\"\n        class=\"thumbnailImage\"\n      >\n      <div\n        class=\"videoCountContainer\"\n      >\n        <div class=\"background\" />\n        <div class=\"inner\">\n          <div>{{ playlist.videos.length }}</div>\n          <div><FontAwesomeIcon :icon=\"['fas', 'list']\" /></div>\n        </div>\n      </div>\n    </div>\n    <div\n      v-observe-visibility=\"{\n        callback: onVisibilityChanged,\n        once: true,\n      }\"\n      class=\"info\"\n    >\n      <div\n        class=\"title\"\n        dir=\"auto\"\n      >\n        {{ titleForDisplay }}\n      </div>\n      <div\n        v-if=\"videoPresenceCountInPlaylistTextVisible\"\n        class=\"videoPresenceCount\"\n      >\n        {{ videoPresenceCountInPlaylistText }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, ref } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport store from '../../store/index'\n\nimport thumbnailPlaceholder from '../../assets/img/thumbnail_placeholder.svg'\n\nconst props = defineProps({\n  playlist: {\n    type: Object,\n    required: true,\n  },\n  appearance: {\n    type: String,\n    default: 'grid',\n  },\n  selected: {\n    type: Boolean,\n    required: true,\n  },\n  disabled: {\n    type: Boolean,\n    required: true,\n  },\n  addingDuplicateVideosEnabled: {\n    type: Boolean,\n    required: true,\n  },\n})\n\nconst emit = defineEmits(['selected'])\n\nconst { t } = useI18n()\n\nconst videoPresenceCountInPlaylistTextShouldBeVisible = ref(false)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<object[]>} */\nconst toBeAddedToPlaylistVideoList = computed(() => store.getters.getToBeAddedToPlaylistVideoList)\n\nconst titleForDisplay = computed(() => {\n  const title = props.playlist.playlistName\n\n  if (typeof title !== 'string') {\n    return ''\n  } else if (title.length <= 255) {\n    return title\n  } else {\n    return `${title.substring(0, 255)}...`\n  }\n})\n\n/** @type {import('vue').ComputedRef<number>} */\nconst loneVideoPresenceCountInPlaylist = computed(() => {\n  if (toBeAddedToPlaylistVideoList.value.length !== 1) { return 0 }\n\n  const loneToBeAddedToPlaylistVideoVideoId = toBeAddedToPlaylistVideoList.value[0].videoId\n\n  return props.playlist.videos.reduce((accumulator, video) => {\n    return video.videoId === loneToBeAddedToPlaylistVideoVideoId\n      ? accumulator + 1\n      : accumulator\n  }, 0)\n})\n\nconst loneVideoPresenceCountInPlaylistText = computed(() => {\n  const count = loneVideoPresenceCountInPlaylist.value\n\n  if (count === 0) { return null }\n\n  return t('User Playlists.AddVideoPrompt.Added {count} Times', {\n    count: count,\n  }, count)\n})\n\n/** @type {import('vue').ComputedRef<number>} */\nconst multiVideoPresenceCountInPlaylist = computed(() => {\n  if (toBeAddedToPlaylistVideoList.value.length < 2) { return 0 }\n\n  // Count of to be added videos already present in this playlist\n  return toBeAddedToPlaylistVideoList.value.reduce((accumulator, toBeAddedToVideo) => {\n    return props.playlist.videos.some((pv) => pv.videoId === toBeAddedToVideo.videoId)\n      ? accumulator + 1\n      : accumulator\n  }, 0)\n})\n\nconst multiVideoPresenceCountInPlaylistText = computed(() => {\n  if (multiVideoPresenceCountInPlaylist.value === 0) { return null }\n\n  if (\n    props.addingDuplicateVideosEnabled ||\n    toBeAddedToPlaylistVideoList.value.length === multiVideoPresenceCountInPlaylist.value\n  ) {\n    return t('User Playlists.AddVideoPrompt.{videoCount}/{totalVideoCount} Videos Already Added', {\n      videoCount: multiVideoPresenceCountInPlaylist.value,\n      totalVideoCount: toBeAddedToPlaylistVideoList.value.length,\n    })\n  } else {\n    return t('User Playlists.AddVideoPrompt.{videoCount}/{totalVideoCount} Videos Will Be Added', {\n      videoCount: toBeAddedToPlaylistVideoList.value.length - multiVideoPresenceCountInPlaylist.value,\n      totalVideoCount: toBeAddedToPlaylistVideoList.value.length,\n    })\n  }\n})\n\nconst videoPresenceCountInPlaylistText = computed(() => {\n  return loneVideoPresenceCountInPlaylistText.value ?? multiVideoPresenceCountInPlaylistText.value\n})\n\nconst videoPresenceCountInPlaylistTextVisible = computed(() => {\n  return videoPresenceCountInPlaylistTextShouldBeVisible.value &&\n    videoPresenceCountInPlaylistText.value != null\n})\n\nconst thumbnail = ref(thumbnailPlaceholder)\n\nif (props.playlist.videos.length > 0) {\n  const origin = backendPreference.value === 'invidious'\n    ? currentInvidiousInstanceUrl.value\n    : 'https://i.ytimg.com'\n\n  thumbnail.value = `${origin}/vi/${props.playlist.videos[0].videoId}/mqdefault.jpg`\n}\n\nfunction toggleSelection() {\n  if (!props.disabled) {\n    emit('selected', props.playlist._id)\n  }\n}\n\n/**\n * @param {boolean} visible\n */\nfunction onVisibilityChanged(visible) {\n  if (visible) {\n    videoPresenceCountInPlaylistTextShouldBeVisible.value = true\n  }\n}\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtPlaylistSelector.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtProfileBubble/FtProfileBubble.css",
    "content": ".bubblePadding {\n  inline-size: 100px;\n  block-size: 115px;\n  padding-block: 10px 30px;\n  padding-inline: 10px;\n  cursor: pointer;\n  transition: background 0.2s ease-out;\n}\n\n.bubblePadding:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.bubble {\n  inline-size: 70px;\n  block-size: 70px;\n  margin-block: 20px 5px;\n  margin-inline: auto;\n  border-radius: 50%;\n}\n\n.initial {\n  font-size: 35px;\n  line-height: 1em;\n  text-align: center;\n  padding-block: 17.5px;\n  padding-inline: 0;\n  user-select: none;\n}\n\n.profileName {\n  font-size: 14px;\n  line-height: 1.5em;\n  overflow: hidden;\n  text-align: center;\n}\n"
  },
  {
    "path": "src/renderer/components/FtProfileBubble/FtProfileBubble.vue",
    "content": "<template>\n  <div\n    class=\"bubblePadding\"\n    tabindex=\"0\"\n    role=\"button\"\n    :aria-labelledby=\"id\"\n    @click=\"click\"\n    @keydown.space.enter.prevent=\"click\"\n  >\n    <div\n      class=\"bubble\"\n      :style=\"{ background: backgroundColor, color: textColor }\"\n    >\n      <div\n        class=\"initial\"\n        dir=\"auto\"\n      >\n        {{ profileInitial }}\n      </div>\n    </div>\n    <div\n      :id=\"id\"\n      class=\"profileName\"\n      dir=\"auto\"\n    >\n      {{ translatedProfileName }}\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed, useId } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport { getFirstCharacter } from '../../helpers/strings'\n\nconst props = defineProps({\n  profileName: {\n    type: String,\n    required: true\n  },\n  isMainProfile: {\n    type: Boolean,\n    required: true\n  },\n  backgroundColor: {\n    type: String,\n    required: true\n  },\n  textColor: {\n    type: String,\n    required: true\n  }\n})\n\nconst { locale, t } = useI18n()\n\nconst id = useId()\n\nconst translatedProfileName = computed(() => {\n  return props.isMainProfile ? t('Profile.All Channels') : props.profileName\n})\n\nconst profileInitial = computed(() => {\n  return props.profileName\n    ? getFirstCharacter(translatedProfileName.value, locale.value)\n    : ''\n})\n\nconst emit = defineEmits(['click'])\n\nfunction click() {\n  emit('click')\n}\n</script>\n\n<style scoped src=\"./FtProfileBubble.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtProfileChannelList/FtProfileChannelList.css",
    "content": "h2,\n.selectedCount {\n  text-align: center;\n}\n\n.card {\n  inline-size: 85%;\n  margin-block: 0 15px;\n  margin-inline: auto;\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtProfileChannelList/FtProfileChannelList.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>\n        {{ $t(\"Profile.Subscription List\") }}\n      </h2>\n      <p class=\"selectedCount\">\n        {{ selectedText }}\n      </p>\n      <FtFlexBox>\n        <FtChannelBubble\n          v-for=\"channel in subscriptions\"\n          :key=\"channel.id\"\n          :channel-id=\"channel.id\"\n          :channel-name=\"channel.name\"\n          :channel-thumbnail=\"channel.thumbnail\"\n          selectable\n          :selected=\"selected.includes(channel.id)\"\n          @change=\"handleChannelToggle(channel.id)\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <FtButton\n          :label=\"$t('Profile.Select All')\"\n          @click=\"selectAll\"\n        />\n        <FtButton\n          :label=\"$t('Profile.Select None')\"\n          @click=\"selectNone\"\n        />\n        <FtButton\n          :label=\"$t('Profile.Delete Selected')\"\n          text-color=\"var(--destructive-text-color)\"\n          background-color=\"var(--destructive-color)\"\n          @click=\"displayDeletePrompt\"\n        />\n      </FtFlexBox>\n    </FtCard>\n    <FtPrompt\n      v-if=\"showDeletePrompt\"\n      :label=\"deletePromptMessage\"\n      :option-names=\"deletePromptNames\"\n      :option-values=\"DELTE_PROMPT_VALUES\"\n      :is-first-option-destructive=\"true\"\n      @click=\"handleDeletePromptClick\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtChannelBubble from '../FtChannelBubble/FtChannelBubble.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\n\nimport store from '../../store/index'\n\nimport { deepCopy, showToast } from '../../helpers/utils'\nimport { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\nconst { locale, t } = useI18n()\n\nconst props = defineProps({\n  profile: {\n    type: Object,\n    required: true\n  },\n  isMainProfile: {\n    type: Boolean,\n    required: true\n  }\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\nconst intlCollator = computed(() => {\n  return new Intl.Collator([locale.value, 'en'], { sensitivity: 'base' })\n})\n\n/** @type {import('vue').Ref<Profile['subscriptions']>} */\nconst subscriptions = ref([])\n\nfunction loadSubscriptions() {\n  /** @type {Profile['subscriptions']} */\n  const subscriptions_ = deepCopy(props.profile.subscriptions)\n\n  const collator = intlCollator.value\n\n  subscriptions_.sort((a, b) => collator.compare(a.name, b.name))\n\n  if (backendPreference.value === 'invidious') {\n    const instanceUrl = currentInvidiousInstanceUrl.value\n\n    subscriptions_.forEach((channel) => {\n      channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, instanceUrl)\n    })\n  }\n\n  subscriptions.value = subscriptions_\n}\n\nif (typeof props.profile.subscriptions !== 'undefined') {\n  loadSubscriptions()\n}\n\nwatch(() => props.profile, () => {\n  loadSubscriptions()\n  selectNone()\n}, { deep: true })\n\n/**\n * TODO: Replace with a Set with Vue 3\n *\n * @type {import('vue').Ref<string[]>}\n */\nconst selected = ref([])\n\nconst selectedText = computed(() => {\n  return t('Profile.{number} selected', { number: selected.value.length })\n})\n\nfunction selectAll() {\n  selected.value = subscriptions.value.map(channel => channel.id)\n}\n\nfunction selectNone() {\n  selected.value = []\n}\n\n/**\n * @param {string} channelId\n */\nfunction handleChannelToggle(channelId) {\n  const index = selected.value.indexOf(channelId)\n\n  if (index === -1) {\n    selected.value.push(channelId)\n  } else {\n    selected.value.splice(index, 1)\n  }\n}\n\nconst DELTE_PROMPT_VALUES = ['delete', 'cancel']\n\nconst deletePromptNames = computed(() => [\n  t('Yes, Delete'),\n  t('Cancel')\n])\n\n/** @type {import('vue').ComputedRef<Profile[]>} */\nconst profileList = computed(() => {\n  return store.getters.getProfileList\n})\n\nconst showDeletePrompt = ref(false)\n\nconst deletePromptMessage = computed(() => {\n  if (props.isMainProfile) {\n    return t('Profile[\"This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\"]')\n  } else {\n    return t('Profile[\"Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.\"]')\n  }\n})\n\nfunction displayDeletePrompt() {\n  if (selected.value.length === 0) {\n    showToast(t('Profile.No channel(s) have been selected'))\n  } else {\n    showDeletePrompt.value = true\n  }\n}\n\n/**\n * @param {'delete' | 'cancel' | null} value\n */\nfunction handleDeletePromptClick(value) {\n  if (value === 'delete') {\n    const selected_ = selected.value\n\n    if (props.isMainProfile) {\n      subscriptions.value = subscriptions.value.filter((channel) => {\n        return !selected_.includes(channel.id)\n      })\n\n      profileList.value.forEach((x) => {\n        const profile = deepCopy(x)\n\n        profile.subscriptions = profile.subscriptions.filter((channel) => {\n          return !selected_.includes(channel.id)\n        })\n\n        // Only update changed profiles\n        if (x.subscriptions.length !== profile.subscriptions.length) {\n          store.dispatch('updateProfile', profile)\n        }\n      })\n\n      showToast(t('Profile.Profile has been updated'))\n      selectNone()\n    } else {\n      subscriptions.value = subscriptions.value.filter((channel) => {\n        return !selected_.includes(channel.id)\n      })\n\n      /** @type {Profile} */\n      const profile = {\n        ...props.profile,\n        subscriptions: deepCopy(subscriptions.value)\n      }\n\n      store.dispatch('updateProfile', profile)\n\n      showToast(t('Profile.Profile has been updated'))\n      selectNone()\n    }\n  }\n\n  showDeletePrompt.value = false\n}\n</script>\n\n<style scoped src=\"./FtProfileChannelList.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtProfileEdit/FtProfileEdit.css",
    "content": "h2 {\n  text-align: center;\n}\n\nh3 {\n  margin-block: 0 10px;\n  text-align: center;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.profileName,\n.colorSelection {\n  margin: auto;\n  inline-size: 350px;\n}\n\n.profileEdit {\n  flex-direction: column;\n  column-gap: 10px;\n}\n\n.profileEdit > * {\n  flex: 1;\n}\n\n.colorOptions {\n  margin-inline: auto;\n  justify-content: center;\n  min-inline-size: 250px;\n}\n\n.customColorSection {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 5px;\n  margin-block-start: 5px;\n}\n\n.colorOption {\n  inline-size: 40px;\n  block-size: 40px;\n  margin: 2px;\n  cursor: pointer;\n  border-radius: 50%;\n}\n\n.initial {\n  font-size: 37.5px;\n  text-align: center;\n  user-select: none;\n}\n\n.colorOption:has(.initial) {\n  inline-size: 75px;\n  block-size: 75px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  cursor: default;\n}\n\n.profilePreviewSection {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  gap: 5px;\n}\n\n.secondEditRow {\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: space-evenly;\n}\n\n.card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtProfileEdit/FtProfileEdit.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>{{ editOrCreateProfileLabel }}</h2>\n      <FtFlexBox class=\"profileEdit\">\n        <div>\n          <h3>{{ $t(\"Profile.Color Picker\") }}</h3>\n          <FtFlexBox\n            class=\"colorOptions\"\n          >\n            <div\n              v-for=\"color in COLOR_VALUES\"\n              :key=\"color\"\n              class=\"colorOption\"\n              :title=\"color + ' ' + $t('Profile.Custom Color')\"\n              :style=\"{ background: color }\"\n              tabindex=\"0\"\n              role=\"button\"\n              @click=\"profileBgColor = color\"\n              @keydown.space.prevent=\"profileBgColor = color\"\n              @keydown.enter.prevent=\"profileBgColor = color\"\n            />\n          </FtFlexBox>\n          <div class=\"customColorSection\">\n            <label for=\"colorPicker\">{{ $t(\"Profile.Custom Color\") }}</label>\n            <input\n              id=\"colorPicker\"\n              v-model=\"profileBgColor\"\n              type=\"color\"\n            >\n          </div>\n          <FtInput\n            class=\"colorSelection\"\n            placeholder=\"\"\n            :value=\"profileBgColor\"\n            :show-action-button=\"false\"\n            :disabled=\"true\"\n          />\n        </div>\n        <div class=\"secondEditRow\">\n          <div>\n            <h3>{{ editOrCreateProfileNameLabel }}</h3>\n            <FtInput\n              class=\"profileName\"\n              :placeholder=\"$t('Profile.Profile Name')\"\n              :disabled=\"isMainProfile\"\n              :value=\"translatedProfileName\"\n              :show-action-button=\"false\"\n              :maxlength=\"100\"\n              @input=\"profileName = $event\"\n              @keydown.enter=\"saveProfile\"\n            />\n          </div>\n          <div>\n            <h3>{{ $t(\"Profile.Profile Preview\") }}</h3>\n            <div class=\"profilePreviewSection\">\n              <div\n                class=\"colorOption\"\n                :style=\"{ background: profileBgColor, color: profileTextColor }\"\n              >\n                <div\n                  class=\"initial\"\n                  dir=\"auto\"\n                >\n                  {{ profileInitial }}\n                </div>\n              </div>\n              <FtFlexBox>\n                <FtButton\n                  v-if=\"isNew\"\n                  :label=\"$t('Profile.Create Profile')\"\n                  @click=\"saveProfile\"\n                />\n                <template\n                  v-else\n                >\n                  <FtButton\n                    :label=\"$t('Profile.Update Profile')\"\n                    @click=\"saveProfile\"\n                  />\n                  <FtButton\n                    :label=\"$t('Profile.Make Default Profile')\"\n                    @click=\"setDefaultProfile\"\n                  />\n                  <FtButton\n                    v-if=\"!isMainProfile\"\n                    :label=\"$t('Profile.Delete Profile')\"\n                    text-color=\"var(--destructive-text-color)\"\n                    background-color=\"var(--destructive-color)\"\n                    :icon=\"['fas', 'trash']\"\n                    @click=\"showDeletePrompt = true\"\n                  />\n                </template>\n              </FtFlexBox>\n            </div>\n          </div>\n        </div>\n      </FtFlexBox>\n    </FtCard>\n    <FtPrompt\n      v-if=\"showDeletePrompt\"\n      :label=\"deletePromptLabel\"\n      :option-names=\"deletePromptNames\"\n      :option-values=\"DELETE_PROMPT_VALUES\"\n      :is-first-option-destructive=\"true\"\n      @click=\"handleDeletePrompt\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtButton from '../FtButton/FtButton.vue'\n\nimport store from '../../store/index'\n\nimport { MAIN_PROFILE_ID } from '../../../constants'\nimport { calculateColorLuminance, colors } from '../../helpers/colors'\nimport { deepCopy, showToast } from '../../helpers/utils'\nimport { getFirstCharacter } from '../../helpers/strings'\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\nconst { locale, t } = useI18n()\n\nconst props = defineProps({\n  isMainProfile: {\n    type: Boolean,\n    required: true\n  },\n  isNew: {\n    type: Boolean,\n    required: true\n  },\n  profile: {\n    type: Object,\n    required: true\n  }\n})\n\nconst emit = defineEmits(['new-profile-created', 'profile-deleted'])\n\nconst COLOR_VALUES = colors.map(color => color.value)\n\n/** @type {import('vue').ComputedRef<Profile>} */\nconst activeProfile = computed(() => store.getters.getActiveProfile)\n\n/** @type {import('vue').Ref<string | undefined>} */\nconst profileId = ref(props.profile._id)\n\n/** @type {import('vue').Ref<string>} */\nconst profileName = ref(props.profile.name)\n\n/** @type {import('vue').Ref<string>} */\nconst profileBgColor = ref(props.profile.bgColor)\n\n/** @type {import('vue').Ref<string>} */\nconst profileTextColor = ref(props.profile.textColor)\n\nwatch(profileBgColor, (value) => {\n  profileTextColor.value = calculateColorLuminance(value)\n})\n\nconst translatedProfileName = computed(() => {\n  return props.isMainProfile ? t('Profile.All Channels') : profileName.value\n})\n\nconst profileInitial = computed(() => {\n  return profileName.value\n    ? getFirstCharacter(translatedProfileName.value, locale.value)\n    : ''\n})\n\nconst editOrCreateProfileLabel = computed(() => {\n  return props.isNew ? t('Profile.Create Profile') : t('Profile.Edit Profile')\n})\n\nconst editOrCreateProfileNameLabel = computed(() => {\n  return props.isNew ? t('Profile.Create Profile Name') : t('Profile.Edit Profile Name')\n})\n\nfunction saveProfile() {\n  if (profileName.value === '') {\n    showToast(t('Profile.Your profile name cannot be empty'))\n    return\n  }\n\n  const profile = {\n    name: profileName.value,\n    bgColor: profileBgColor.value,\n    textColor: profileTextColor.value,\n    subscriptions: deepCopy(props.profile.subscriptions)\n  }\n\n  if (!props.isNew) {\n    profile._id = profileId.value\n  }\n\n  if (props.isNew) {\n    store.dispatch('createProfile', profile)\n    showToast(t('Profile.Profile has been created'))\n    emit('new-profile-created')\n  } else {\n    store.dispatch('updateProfile', profile)\n    showToast(t('Profile.Profile has been updated'))\n  }\n}\n\nfunction setDefaultProfile() {\n  store.dispatch('updateDefaultProfile', profileId.value)\n  showToast(t('Profile.Your default profile has been set to {profile}', { profile: translatedProfileName.value }))\n}\n\nconst DELETE_PROMPT_VALUES = ['delete', 'cancel']\n\nconst deletePromptNames = computed(() => [\n  t('Yes, Delete'),\n  t('Cancel')\n])\n\nconst deletePromptLabel = computed(() => {\n  return `${t('Profile.Are you sure you want to delete this profile?')} ${t('Profile[\"All subscriptions will also be deleted.\"]')}`\n})\n\nconst showDeletePrompt = ref(false)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst defaultProfile = computed(() => store.getters.getDefaultProfile)\n\n/**\n * @param {'delete' | 'cancel' | null} response\n */\nfunction handleDeletePrompt(response) {\n  if (response === 'delete') {\n    if (activeProfile.value._id === profileId.value) {\n      store.dispatch('updateActiveProfile', MAIN_PROFILE_ID)\n    }\n\n    store.dispatch('removeProfile', profileId.value)\n\n    showToast(t('Profile.Removed {profile} from your profiles', { profile: translatedProfileName.value }))\n\n    if (defaultProfile.value === profileId.value) {\n      store.dispatch('updateDefaultProfile', MAIN_PROFILE_ID)\n      showToast(t('Profile.Your default profile has been changed to your primary profile'))\n    }\n\n    emit('profile-deleted')\n  } else {\n    showDeletePrompt.value = false\n  }\n}\n</script>\n\n<style scoped src=\"./FtProfileEdit.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtProfileFilterChannelsList/FtProfileFilterChannelsList.css",
    "content": "h2 {\n  text-align: center;\n}\n\n.selected {\n  text-align: center;\n}\n\n.card {\n  inline-size: 85%;\n  margin-block: 0 15px;\n  margin-inline: auto;\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtProfileFilterChannelsList/FtProfileFilterChannelsList.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>\n        {{ $t(\"Profile.Other Channels\") }}\n      </h2>\n      <FtFlexBox>\n        <FtSelect\n          :placeholder=\"$t('Profile.Profile Filter')\"\n          :value=\"profileIdList[filteredProfileIndex]\"\n          :select-names=\"profileNameList\"\n          :select-values=\"profileIdList\"\n          :icon=\"['fas', 'filter']\"\n          @change=\"handleProfileFilterChange\"\n        />\n      </FtFlexBox>\n      <p class=\"selected\">\n        {{ selectedText }}\n      </p>\n      <FtFlexBox>\n        <FtChannelBubble\n          v-for=\"channel in channels\"\n          :key=\"channel.id\"\n          :channel-id=\"channel.id\"\n          :channel-name=\"channel.name\"\n          :channel-thumbnail=\"channel.thumbnail\"\n          selectable\n          :selected=\"selected.includes(channel.id)\"\n          @change=\"handleChannelToggle(channel.id)\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <FtButton\n          :label=\"$t('Profile.Select All')\"\n          @click=\"selectAll\"\n        />\n        <FtButton\n          :label=\"$t('Profile.Select None')\"\n          @click=\"selectNone\"\n        />\n        <FtButton\n          :label=\"$t('Profile.Add Selected To Profile')\"\n          text-color=\"var(--text-with-main-color)\"\n          background-color=\"var(--primary-color)\"\n          @click=\"addChannelsToProfile\"\n        />\n      </FtFlexBox>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtChannelBubble from '../FtChannelBubble/FtChannelBubble.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\n\nimport store from '../../store/index'\n\nimport { deepCopy, showToast } from '../../helpers/utils'\nimport { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\nimport { MAIN_PROFILE_ID } from '../../../constants'\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\nconst { locale, t } = useI18n()\n\nconst props = defineProps({\n  profile: {\n    type: Object,\n    required: true\n  }\n})\n\n/** @type {import('vue').ComputedRef<Profile[]>} */\nconst profileList = computed(() => {\n  return store.getters.getProfileList\n})\n\n/** @type {import('vue').ShallowRef<string[]>} */\nconst profileIdList = shallowRef([])\n\n/** @type {import('vue').ShallowRef<string[]>} */\nconst profileNameList = shallowRef([])\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\nconst intlCollator = computed(() => {\n  return new Intl.Collator([locale.value, 'en'], { sensitivity: 'base' })\n})\n\nconst filteredProfileIndex = ref(0)\n\n/** @type {import('vue').Ref<Profile['subscriptions']>} */\nconst channels = ref([])\n\nfunction loadChannels() {\n  const profileId = profileIdList.value[filteredProfileIndex.value]\n  const profile = profileList.value.find((profile) => profile._id === profileId)\n\n  /** @type {Profile['subscriptions']} */\n  let channels_ = deepCopy(profile.subscriptions)\n\n  channels_ = channels_.filter((channel) => {\n    return !props.profile.subscriptions.some((sub) => sub.id === channel.id)\n  })\n\n  const collator = intlCollator.value\n\n  channels_.sort((a, b) => collator.compare(a.name, b.name))\n\n  if (backendPreference.value === 'invidious') {\n    const instanceUrl = currentInvidiousInstanceUrl.value\n\n    channels_.forEach((channel) => {\n      channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, instanceUrl)\n    })\n  }\n\n  channels.value = channels_\n}\n\nfillProfileList()\n\nif (typeof props.profile.subscriptions !== 'undefined') {\n  loadChannels()\n}\n\nwatch(() => props.profile, () => {\n  loadChannels()\n  selectNone()\n}, { deep: true })\n\nwatch(filteredProfileIndex, loadChannels)\n\n/**\n * TODO: Replace with a Set with Vue 3\n *\n * @type {import('vue').Ref<string[]>}\n */\nconst selected = ref([])\n\nconst selectedText = computed(() => {\n  return t('Profile.{number} selected', { number: selected.value.length })\n})\n\nfunction selectAll() {\n  selected.value = channels.value.map(channel => channel.id)\n}\n\nfunction selectNone() {\n  selected.value = []\n}\n\n/**\n * @param {string} channelId\n */\nfunction handleChannelToggle(channelId) {\n  const index = selected.value.indexOf(channelId)\n\n  if (index === -1) {\n    selected.value.push(channelId)\n  } else {\n    selected.value.splice(index, 1)\n  }\n}\n\nwatch(profileList, fillProfileList, { deep: true })\nwatch(() => props.profile, fillProfileList, { deep: true })\n\nfunction fillProfileList() {\n  const profiles = profileList.value.filter((profile) => profile._id !== props.profile._id)\n\n  profileIdList.value = profiles.map((profile) => profile._id)\n  profileNameList.value = profiles.map(translateProfileName)\n}\n\n/**\n * @param {Profile} profile\n */\nfunction translateProfileName(profile) {\n  return profile._id === MAIN_PROFILE_ID ? t('Profile.All Channels') : profile.name\n}\n\n/**\n * @param {string} profileId\n */\nfunction handleProfileFilterChange(profileId) {\n  selectNone()\n  filteredProfileIndex.value = profileIdList.value.indexOf(profileId)\n}\n\nfunction addChannelsToProfile() {\n  if (selected.value.length === 0) {\n    showToast(t('Profile.No channel(s) have been selected'))\n  } else {\n    const selected_ = selected.value\n\n    const profileId = profileIdList.value[filteredProfileIndex.value]\n    const subscriptions = profileList.value\n      .find((profile) => profile._id === profileId)\n      .subscriptions\n      .filter((channel) => selected_.includes(channel.id))\n\n    const profile = deepCopy(props.profile)\n    profile.subscriptions.push(...deepCopy(subscriptions))\n\n    store.dispatch('updateProfile', profile)\n    showToast(t('Profile.Profile has been updated'))\n    selectNone()\n  }\n}\n</script>\n\n<style scoped src=\"./FtProfileFilterChannelsList.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtProfileSelector/FtProfileSelector.css",
    "content": ".colorOption {\n  inline-size: 40px;\n  block-size: 40px;\n  cursor: pointer;\n  align-items: center;\n  display: flex;\n  justify-content: center;\n  border-radius: 50%;\n}\n\n.colorOption:hover {\n  box-shadow: 0 0 0 2px var(--side-nav-hover-color);\n}\n\n.initial {\n  font-size: 20px;\n  line-height: 1em;\n  text-align: center;\n  user-select: none;\n}\n\n.profileList {\n  display: inline;\n  position: absolute;\n  inset-block-start: 60px;\n  inset-inline-end: 10px;\n  min-inline-size: 250px;\n  block-size: auto;\n  padding: 5px;\n  background-color: var(--card-bg-color);\n  box-shadow: 0 0 4px var(--scrollbar-color-hover);\n}\n\n.profileWrapper {\n  margin-block-start: 60px;\n  block-size: auto;\n  overflow-y: auto;\n\n  /*\n  profile list max height: 90% of window size - 100 px. It's scaled to be 340px on 800x600 resolution.\n  Offset of 100px is to compensate for the fixed size of elements above the list, which takes more screen space on lower resolutions\n  */\n  max-block-size: calc(90vh - 100px);\n  min-block-size: 340px;\n}\n\n/* Navbar changes position to horizontal with this media rule.\nHeight adjust for profile list so it won't cover navbar.  */\n@media only screen and (width <= 680px) {\n  .profileWrapper {\n    max-block-size: calc(95vh - 180px);\n  }\n}\n\n.profile {\n  cursor: pointer;\n  block-size: 50px;\n  transition: background 0.2s ease-out;\n}\n\n.profile:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.profile .colorOption {\n  float: inline-start;\n  position: relative;\n  inset-block-end: 5px;\n  margin: 10px;\n}\n\n.profileName {\n  display: flex;\n  align-items: center;\n  block-size: 50px;\n  padding-inline-end: 10px;\n}\n\n.profileListTitle {\n  position: absolute;\n  margin: 0;\n  inset-inline-start: 10px;\n}\n\n.profileSettings {\n  float: inline-end;\n  position: absolute;\n  inset-block-start: 10px;\n  inset-inline-end: 5px;\n}\n"
  },
  {
    "path": "src/renderer/components/FtProfileSelector/FtProfileSelector.vue",
    "content": "<template>\n  <div>\n    <div\n      ref=\"iconButton\"\n      class=\"colorOption\"\n      :title=\"$t('Profile.Toggle Profile List')\"\n      :style=\"{ background: activeProfile.bgColor, color: activeProfile.textColor }\"\n      tabindex=\"0\"\n      role=\"button\"\n      :aria-expanded=\"profileListShown\"\n      :aria-controls=\"id + 'list'\"\n      @click=\"toggleProfileList\"\n      @mousedown=\"handleIconMouseDown\"\n      @keydown.space.prevent=\"toggleProfileList\"\n      @keydown.enter.prevent=\"toggleProfileList\"\n    >\n      <div\n        class=\"initial\"\n        dir=\"auto\"\n      >\n        {{ activeProfileInitial }}\n      </div>\n    </div>\n    <FtCard\n      v-show=\"profileListShown\"\n      :id=\"id + 'list'\"\n      ref=\"profileListRef\"\n      class=\"profileList\"\n      tabindex=\"-1\"\n      @focusout=\"handleProfileListFocusOut\"\n      @keydown.esc.stop=\"handleProfileListEscape\"\n    >\n      <h3\n        :id=\"id + 'title'\"\n        class=\"profileListTitle\"\n      >\n        {{ $t(\"Profile.Profile Select\") }}\n      </h3>\n      <FtIconButton\n        class=\"profileSettings\"\n        :icon=\"['fas', 'sliders-h']\"\n        @click=\"openProfileSettings\"\n      />\n      <div\n        class=\"profileWrapper\"\n        role=\"listbox\"\n        :aria-labelledby=\"id + 'title'\"\n      >\n        <div\n          v-for=\"profile in profileList\"\n          :key=\"profile._id\"\n          class=\"profile\"\n          :aria-labelledby=\"id + profile._id\"\n          :aria-selected=\"isActiveProfile(profile)\"\n          tabindex=\"0\"\n          role=\"option\"\n          :data-profile-id=\"profile._id\"\n          @click=\"setActiveProfile\"\n          @keydown.enter.prevent=\"setActiveProfile\"\n        >\n          <div\n            class=\"colorOption\"\n            :style=\"{ background: profile.bgColor, color: profile.textColor }\"\n          >\n            <div\n              class=\"initial\"\n              dir=\"auto\"\n            >\n              {{ profileInitials[profile._id] }}\n            </div>\n          </div>\n          <p\n            :id=\"id + profile._id\"\n            class=\"profileName\"\n            dir=\"auto\"\n          >\n            {{ translateProfileName(profile) }}\n          </p>\n        </div>\n      </div>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, ref, useId, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRouter } from 'vue-router'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\n\nimport store from '../../store/index'\n\nimport { showToast } from '../../helpers/utils'\nimport { MAIN_PROFILE_ID } from '../../../constants'\nimport { getFirstCharacter } from '../../helpers/strings'\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\nconst { locale, t } = useI18n()\n\nconst id = useId()\n\nconst profileListShown = ref(false)\nlet mouseDownOnIcon = false\n\n/** @type {import('vue').ComputedRef<Profile[]>} */\nconst profileList = computed(() => store.getters.getProfileList)\n/** @type {import('vue').ComputedRef<Profile>} */\nconst activeProfile = computed(() => store.getters.getActiveProfile)\n\nconst activeProfileInitial = computed(() => {\n  return activeProfile.value?.name\n    ? getFirstCharacter(translateProfileName(activeProfile.value), locale.value)\n    : ''\n})\n\n/** @type {import('vue').ComputedRef<Record<Profile['_id'], string>>} */\nconst profileInitials = computed(() => {\n  const locale_ = locale.value\n\n  return profileList.value.reduce((initials, profile) => {\n    initials[profile._id] = profile?.name\n      ? getFirstCharacter(translateProfileName(profile), locale_)\n      : ''\n\n    return initials\n  }, {})\n})\n\n/**\n * @param {Profile} profile\n */\nfunction isActiveProfile(profile) {\n  return profile._id === activeProfile.value._id\n}\n\nconst profileListRef = useTemplateRef('profileListRef')\n\nfunction toggleProfileList() {\n  profileListShown.value = !profileListShown.value\n\n  if (profileListShown.value) {\n    // wait until the profile list is visible\n    // then focus it so we can hide it automatically when it loses focus\n    nextTick(() => {\n      profileListRef.value?.$el?.focus()\n    })\n  }\n}\n\nconst router = useRouter()\n\nfunction openProfileSettings() {\n  router.push({ path: '/settings/profile' })\n  profileListShown.value = false\n}\n\nfunction handleIconMouseDown() {\n  if (profileListShown.value) {\n    mouseDownOnIcon = true\n  }\n}\n\nfunction handleProfileListFocusOut() {\n  if (mouseDownOnIcon) {\n    mouseDownOnIcon = false\n  } else if (!profileListRef.value?.$el.matches(':focus-within')) {\n    profileListShown.value = false\n  }\n}\n\nconst iconButton = useTemplateRef('iconButton')\n\nfunction handleProfileListEscape() {\n  iconButton.value?.focus()\n  // handleProfileListFocusOut will hide the dropdown for us\n}\n\n/**\n * @param {MouseEvent | KeyboardEvent} event\n */\nfunction setActiveProfile(event) {\n  /** @type {string} */\n  const profileId = event.currentTarget.dataset.profileId\n\n  if (activeProfile.value._id !== profileId) {\n    const targetProfile = profileList.value.find((x) => {\n      return x._id === profileId\n    })\n\n    if (targetProfile) {\n      store.commit('setActiveProfile', profileId)\n\n      showToast(t('Profile.{profile} is now the active profile', { profile: translateProfileName(targetProfile) }))\n    }\n  }\n\n  profileListShown.value = false\n}\n\n/**\n * @param {Profile} profile\n */\nfunction translateProfileName(profile) {\n  return profile._id === MAIN_PROFILE_ID ? t('Profile.All Channels') : profile.name\n}\n</script>\n\n<style scoped src=\"./FtProfileSelector.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtProgressBar/FtProgressBar.css",
    "content": ".progressBar {\n  position: fixed;\n  block-size: 3px;\n  inset-block-end: 0;\n  inset-inline-start: 0;\n  background-color: var(--primary-color);\n  z-index: 4;\n}\n"
  },
  {
    "path": "src/renderer/components/FtProgressBar/FtProgressBar.vue",
    "content": "<template>\n  <div\n    class=\"progressBar\"\n    :style=\"{ inlineSize: progressBarPercentage + '%' }\"\n  />\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport store from '../../store/index'\n\nconst progressBarPercentage = computed(() => {\n  return store.getters.getProgressBarPercentage\n})\n</script>\n\n<style scoped src=\"./FtProgressBar.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtPrompt/FtPrompt.css",
    "content": ".prompt {\n  position: fixed;\n  inset-block-start: 0;\n  inset-inline-start: 0;\n  inline-size: 100%;\n  block-size: 100%;\n  background-color: rgb(0 0 0 / 70%);\n\n  /* Higher than components like playlist info */\n  z-index: 201;\n  padding: 15px;\n  box-sizing: border-box;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n\n.promptCard {\n  overflow-y: scroll;\n  max-block-size: 95%;\n}\n\n.promptCard.autosize {\n  box-sizing: border-box;\n  margin-block: 0;\n  margin-inline: auto;\n  max-inline-size: 95%;\n}\n\n.promptCard:not(.autosize) {\n  inline-size: 95%;\n  margin: 0;\n  position: absolute;\n  inset-inline-start: 2.5%;\n  box-sizing: border-box;\n}\n\n.promptCard.flex-column {\n  /* Some child(ren) will grow vertically */\n  display: flex;\n  flex-direction: column;\n}\n\n.promptCard.slim {\n  max-inline-size: 70%;\n  inset-inline-start: 15%;\n  padding-block: 10px;\n}\n\n.promptCard.readable-width {\n  max-inline-size: 50em;\n  margin-inline: auto;\n  inset-inline: 0;\n  padding-inline: 0;\n}\n\n.center {\n  text-align: center;\n}\n\n@media only screen and (width <= 680px) {\n  .promptCard.slim {\n    padding-block: 5px;\n  }\n}\n\n@media only screen and (width <= 500px) {\n  .promptCard.slim {\n    max-inline-size: 80%;\n    inset-inline-start: 10%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtPrompt/FtPrompt.vue",
    "content": "<template>\n  <Teleport to=\".app\">\n    <div\n      class=\"prompt\"\n      tabindex=\"-1\"\n      :inert=\"inert\"\n      @click.self=\"hide\"\n      @keydown.enter.self=\"hide\"\n      @keydown.left.right.capture=\"handleArrowKeys\"\n    >\n      <FtCard\n        ref=\"promptCard\"\n        class=\"promptCard\"\n        :class=\"{ autosize, [theme]: true }\"\n        role=\"dialog\"\n        aria-modal=\"true\"\n        :aria-labelledby=\"id\"\n      >\n        <slot\n          name=\"label\"\n          :label-id=\"id\"\n        >\n          <h2\n            :id=\"id\"\n            class=\"center\"\n          >\n            {{ label }}\n          </h2>\n        </slot>\n\n        <slot>\n          <p\n            v-for=\"extraLabel in extraLabels\"\n            :key=\"extraLabel\"\n            class=\"center\"\n          >\n            <strong>\n              {{ extraLabel }}\n            </strong>\n          </p>\n          <FtFlexBox>\n            <FtButton\n              v-for=\"(option, index) in optionNames\"\n              :key=\"index\"\n              :label=\"option\"\n              :text-color=\"optionButtonTextColor(index)\"\n              :background-color=\"optionButtonBackgroundColor(index)\"\n              :icon=\"index === 0 && isFirstOptionDestructive ? ['fas', 'trash'] : null\"\n              @click=\"click(optionValues[index])\"\n            />\n          </FtFlexBox>\n        </slot>\n      </FtCard>\n    </div>\n  </Teleport>\n</template>\n\n<script setup>\nimport { nextTick, onBeforeUnmount, onMounted, useId, useTemplateRef } from 'vue'\n\nimport store from '../../store/index'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtButton from '../FtButton/FtButton.vue'\n\nconst props = defineProps({\n  label: {\n    type: String,\n    default: ''\n  },\n  extraLabels: {\n    type: Array,\n    default: () => []\n  },\n  optionNames: {\n    type: Array,\n    default: () => []\n  },\n  optionValues: {\n    type: Array,\n    default: () => []\n  },\n  autosize: {\n    type: Boolean,\n    default: false\n  },\n  isFirstOptionDestructive: {\n    type: Boolean,\n    default: false\n  },\n  theme: {\n    type: String,\n    default: 'base'\n  },\n  inert: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst emit = defineEmits(['click'])\n\nconst id = useId()\n\nconst promptCard = useTemplateRef('promptCard')\n\nlet promptButtons = []\nlet lastActiveElement = null\n\nonMounted(() => {\n  lastActiveElement = document.activeElement\n  document.addEventListener('keydown', handleEscape, true)\n  store.commit('addOpenPrompt', id)\n\n  nextTick(() => {\n    promptButtons = Array.from(promptCard.value.$el.querySelectorAll('.btn.ripple, .iconButton'))\n    focusItem(0)\n  })\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', handleEscape, true)\n  store.commit('removeOpenPrompt', id)\n  nextTick(() => lastActiveElement?.focus())\n})\n\n/**\n * @param {number} index\n */\nfunction optionButtonTextColor(index) {\n  if (index === 0 && props.isFirstOptionDestructive) {\n    return 'var(--destructive-text-color)'\n  } else if (index < props.optionNames.length - 1) {\n    return 'var(--text-with-accent-color)'\n  } else {\n    return null\n  }\n}\n\n/**\n * @param {number} index\n */\nfunction optionButtonBackgroundColor(index) {\n  if (index === 0 && props.isFirstOptionDestructive) {\n    return 'var(--destructive-color)'\n  } else if (index < props.optionNames.length - 1) {\n    return 'var(--accent-color)'\n  } else {\n    return null\n  }\n}\n\n/**\n * @param {any} value\n */\nfunction click(value) {\n  emit('click', value)\n}\n\nfunction hide() {\n  click(null)\n}\n\n/**\n * @param {number} index\n */\nfunction focusItem(index) {\n  if (index < 0) {\n    index = promptButtons.length - 1\n  } else if (index >= promptButtons.length) {\n    index = 0\n  }\n\n  promptButtons[index].focus()\n  store.dispatch('showOutlines')\n}\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction handleEscape(event) {\n  if (event.key === 'Escape' && !props.inert) {\n    event.preventDefault()\n    hide()\n  }\n}\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction handleArrowKeys(event) {\n  const currentIndex = promptButtons.indexOf(event.target)\n\n  // Only react if a button was focused when the arrow key was pressed\n  if (currentIndex === -1) {\n    return\n  }\n\n  event.preventDefault()\n\n  const direction = (event.key === 'ArrowLeft') ? -1 : 1\n  focusItem(currentIndex + direction)\n}\n</script>\n\n<style scoped src=\"./FtPrompt.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtRadioButton/FtRadioButton.css",
    "content": "/* stylelint-disable no-descending-specificity */\n.pure-radiobutton input[type='radio'] {\n  border: 0;\n  clip-path: circle(0);\n  block-size: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  inline-size: 1px;\n}\n\n.pure-radiobutton input[type='radio']:focus + label::before,\n.pure-radiobutton input[type='radio']:hover + label::before {\n  border: 2px solid var(--primary-color);\n}\n\n.pure-radiobutton input[type='radio']:active + label::before { transition-duration: 0s; }\n\n.pure-radiobutton input[type='radio'] + label {\n  position: relative;\n  padding-inline-start: 2em;\n  user-select: none;\n  cursor: pointer;\n  display: block;\n  margin-block-start: 10px;\n}\n\n.pure-radiobutton input[type='radio'] + label::before {\n  box-sizing: content-box;\n  content: '';\n  color: var(--primary-text-color);\n  position: absolute;\n  inset-block-start: 50%;\n  inset-inline-start: 0;\n  inline-size: 14px;\n  block-size: 14px;\n  margin-block-start: -9px;\n  border: 2px solid var(--primary-text-color);\n  text-align: center;\n  transition: all 0.4s ease;\n}\n\n.pure-radiobutton input[type='radio'] + label::after {\n  box-sizing: content-box;\n  content: '';\n  background-color: var(--primary-text-color);\n  position: absolute;\n  inset-block-start: 50%;\n  inset-inline-start: 4px;\n  inline-size: 10px;\n  block-size: 10px;\n  margin-block-start: -5px;\n  transform: scale(0);\n  transform-origin: 50%;\n  transition: transform 200ms ease-out;\n}\n\n.pure-radiobutton input[type='radio']:disabled + label::before { border-color: #ccc; }\n\n.pure-radiobutton input[type='radio']:disabled:focus + label::before,\n.pure-radiobutton input[type='radio']:disabled:hover + label::before { background-color: inherit; }\n\n.pure-radiobutton input[type='radio']:disabled:checked + label::before { background-color: #ccc; }\n\n\n.pure-checkbox input[type='radio']:checked + label::before,\n.pure-radiobutton input[type='radio']:checked + label::before {\n  animation: borderscale 300ms ease-in;\n}\n\n.pure-radiobutton input[type='radio']:focus + label::after {\n  background-color: var(--primary-color);\n}\n\n.pure-radiobutton input[type='radio']:checked + label::after { transform: scale(1); }\n\n.pure-radiobutton input[type='radio'] + label::before,\n.pure-radiobutton input[type='radio'] + label::after { border-radius: 50%; }\n\n@keyframes\n  borderscale {  50% {\n    box-shadow: 0 0 0 2px var(--primary-text-color);\n  }\n}\n\n.radioTitle {\n  margin-block: 0;\n}\n\n@media only screen and (width <= 680px) {\n  .pure-radiobutton input[type='radio'] + label {\n    margin-block-start: 3px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtRadioButton/FtRadioButton.vue",
    "content": "<template>\n  <div class=\"pure-radiobutton filter\">\n    <h3 class=\"radioTitle\">\n      {{ title }}\n    </h3>\n    <template\n      v-for=\"(label, index) in labels\"\n      :key=\"values[index]\"\n    >\n      <input\n        :id=\"id + values[index]\"\n        v-model=\"modelValue\"\n        :name=\"id\"\n        :value=\"values[index]\"\n        :disabled=\"disabled\"\n        class=\"radio\"\n        type=\"radio\"\n      >\n      <label\n        :for=\"id + values[index]\"\n      >\n        {{ label }}\n      </label>\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { useId } from 'vue'\n\nconst id = useId()\n\ndefineProps({\n  title: {\n    type: String,\n    required: true\n  },\n  labels: {\n    type: Array,\n    required: true\n  },\n  values: {\n    type: Array,\n    required: true\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n})\n\nconst modelValue = defineModel({ type: String, required: true })\n</script>\n\n<style scoped src=\"./FtRadioButton.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtRefreshWidget/FtRefreshWidget.scss",
    "content": "@use '../../scss-partials/utils';\n\n.floatingRefreshSection {\n  box-sizing: border-box;\n  padding-block: 5px;\n  padding-inline: 10px;\n  box-shadow: 0 2px 1px 0 var(--primary-shadow-color);\n  background-color: var(--card-bg-color);\n  border-inline-start: 2px solid var(--primary-shadow-color);\n  display: flex;\n  align-items: center;\n  gap: 5px;\n  justify-content: flex-end;\n\n  @include utils.fixed-top-bar;\n}\n\n.floatingRefreshSection:has(.lastRefreshTimestamp + .refreshButton) {\n  justify-content: space-between;\n}\n\n.lastRefreshTimestamp {\n  margin-block: 0;\n  text-align: center;\n  font-size: 16px;\n}\n\n@media only screen and (width <= 680px) {\n  .floatingRefreshSection,\n  .floatingRefreshSection.sideNavOpen,\n  .floatingRefreshSection.hideLabelsSideBar {\n    inline-size: 100%;\n    border-inline-start: none;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtRefreshWidget/FtRefreshWidget.vue",
    "content": "<template>\n  <div\n    class=\"floatingRefreshSection\"\n  >\n    <p\n      v-if=\"lastRefreshTimestamp\"\n      class=\"lastRefreshTimestamp\"\n    >\n      {{ t('Feed.Feed Last Updated', { feedName: title, date: lastRefreshTimestamp }) }}\n    </p>\n    <FtIconButton\n      :disabled=\"disableRefresh\"\n      :icon=\"['fas', 'sync']\"\n      class=\"refreshButton\"\n      :title=\"refreshFeedButtonTitle\"\n      :size=\"12\"\n      theme=\"primary\"\n      @click=\"click\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\n\nimport { KeyboardShortcuts } from '../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../helpers/utils'\n\nconst props = defineProps({\n  disableRefresh: {\n    type: Boolean,\n    default: false\n  },\n  lastRefreshTimestamp: {\n    type: String,\n    default: ''\n  },\n  title: {\n    type: String,\n    required: true\n  }\n})\n\nconst { t } = useI18n()\n\nconst refreshFeedButtonTitle = computed(() => {\n  return addKeyboardShortcutToActionTitle(\n    t('Feed.Refresh Feed', { subscriptionName: props.title }),\n    KeyboardShortcuts.APP.SITUATIONAL.REFRESH\n  )\n})\n\nconst emit = defineEmits(['click'])\n\nfunction click() {\n  emit('click')\n}\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtRefreshWidget.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtSearchFilters/FtSearchFilters.css",
    "content": ".center {\n  margin-block-start: 10px;\n  text-align: center;\n  user-select: none;\n}\n\n.searchRadio {\n  padding: 5px;\n}\n\n.radioFlexBox {\n  margin-block: 0;\n  margin-inline: auto;\n}\n\n.searchFilterCloseButtonContainer {\n  display: flex;\n  justify-content: center;\n}\n\n.titleContainer {\n  display: flex;\n  align-items: baseline;\n  justify-content: center;\n  gap: 0.5rem;\n  block-size: inherit;\n}\n\n.clearFilterButton {\n  border-radius: 50%;\n  border-style: none;\n  background-color: transparent;\n  color: var(--primary-text-color);\n  cursor: pointer;\n  font-size: 20px;\n  line-height: 1em;\n  padding: 10px;\n  transition: background 0.2s ease-out;\n\n  &:hover {\n    background-color: var(--side-nav-hover-color);\n    color: var(--side-nav-hover-text-color);\n    transition: background 0.2s ease-in;\n  }\n\n  &:active {\n    background-color: var(--tertiary-text-color);\n    color: var(--side-nav-active-text-color);\n    transition: background 0.2s ease-in;\n  }\n}\n\n.clearFilterIcon {\n  vertical-align: -0.25em;\n}\n\n@media only screen and (width <= 680px) {\n  .searchRadio {\n    border-inline-end: 0;\n    padding-block-start: 0;\n  }\n\n  .radioFlexBox {\n    flex-flow: column;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSearchFilters/FtSearchFilters.vue",
    "content": "<template>\n  <FtPrompt\n    theme=\"slim\"\n    @click=\"hideSearchFilters\"\n  >\n    <template #label=\"{ labelId }\">\n      <div class=\"titleContainer\">\n        <h2\n          :id=\"labelId\"\n          class=\"center\"\n        >\n          {{ title }}\n        </h2>\n        <button\n          class=\"clearFilterButton\"\n          :title=\"$t('Search Filters.Clear Filters')\"\n          :style=\"{visibility: (searchFilterValueChanged ? 'visible' : 'hidden')}\"\n          @click=\"clearFilters\"\n        >\n          <FontAwesomeIcon\n            class=\"clearFilterIcon\"\n            :icon=\"['fas', 'filter-circle-xmark']\"\n          />\n        </button>\n      </div>\n    </template>\n\n    <FtFlexBox class=\"radioFlexBox\">\n      <FtRadioButton\n        v-model=\"sortByValue\"\n        :title=\"$t('Global.Sort By')\"\n        :labels=\"sortByLabels\"\n        :values=\"SORT_BY_VALUES\"\n        class=\"searchRadio\"\n      />\n      <FtRadioButton\n        v-model=\"timeValue\"\n        :title=\"$t('Search Filters.Time.Time')\"\n        :labels=\"timeLabels\"\n        :values=\"TIME_VALUES\"\n        class=\"searchRadio\"\n      />\n      <FtRadioButton\n        v-model=\"typeValue\"\n        :title=\"$t('Search Filters.Type.Type')\"\n        :labels=\"typeLabels\"\n        :values=\"TYPE_VALUES\"\n        class=\"searchRadio\"\n      />\n      <FtRadioButton\n        v-model=\"durationValue\"\n        :title=\"$t('Search Filters.Duration.Duration')\"\n        :labels=\"durationLabels\"\n        :values=\"DURATION_VALUES\"\n        class=\"searchRadio\"\n      />\n      <FtCheckboxList\n        v-model=\"featuresValue\"\n        :title=\"$t('Search Filters.Features.Features')\"\n        :labels=\"featureLabels\"\n        :values=\"FEATURE_VALUES\"\n        class=\"searchRadio\"\n      />\n    </FtFlexBox>\n    <div class=\"searchFilterCloseButtonContainer\">\n      <FtButton\n        :label=\"$t('Close')\"\n        background-color=\"null\"\n        text-color=\"null\"\n        @click=\"hideSearchFilters\"\n      />\n    </div>\n  </FtPrompt>\n</template>\n\n<script setup>\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtRadioButton from '../FtRadioButton/FtRadioButton.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtCheckboxList from '../FtCheckboxList/FtCheckboxList.vue'\n\nimport store from '../../store/index'\n\nconst { t } = useI18n()\n\nconst SORT_BY_VALUES = [\n  'relevance',\n  'rating',\n  'upload_date',\n  'view_count'\n]\n\nconst TIME_VALUES = [\n  '',\n  'hour',\n  'today',\n  'week',\n  'month',\n  'year'\n]\n\nconst TYPE_VALUES = [\n  'all',\n  'video',\n  'channel',\n  'playlist',\n  'movie'\n]\n\nconst DURATION_VALUES = [\n  '',\n  'short',\n  'medium',\n  'long'\n]\n\nconst FEATURE_VALUES = [\n  'hd',\n  'subtitles',\n  'creative_commons',\n  '3d',\n  'live',\n  '4k',\n  '360',\n  'location',\n  'hdr',\n  'vr180'\n]\n\nconst NOT_ALLOWED_FOR_MOVIES_FEATURES = [\n  'live',\n  'subtitles',\n  '3d',\n  'creative_commons'\n]\n\nconst title = computed(() => t('Search Filters.Search Filters'))\n\nconst sortByLabels = computed(() => [\n  t('Search Filters.Sort By.Most Relevant'),\n  t('Search Filters.Sort By.Rating'),\n  t('Search Filters.Sort By.Upload Date'),\n  t('Search Filters.Sort By.View Count')\n])\n\nconst timeLabels = computed(() => [\n  t('Search Filters.Time.Any Time'),\n  t('Search Filters.Time.Last Hour'),\n  t('Search Filters.Time.Today'),\n  t('Search Filters.Time.This Week'),\n  t('Search Filters.Time.This Month'),\n  t('Search Filters.Time.This Year')\n])\n\nconst typeLabels = computed(() => [\n  t('Search Filters.Type.All Types'),\n  t('Search Filters.Type.Videos'),\n  t('Search Filters.Type.Channels'),\n  t('Playlists'),\n  t('Search Filters.Type.Movies')\n])\n\nconst durationLabels = computed(() => [\n  t('Search Filters.Duration.All Durations'),\n  t('Search Filters.Duration.Short (< 4 minutes)'),\n  t('Search Filters.Duration.Medium (4 - 20 minutes)'),\n  t('Search Filters.Duration.Long (> 20 minutes)')\n])\n\nconst featureLabels = computed(() => [\n  t('Search Filters.Features.HD'),\n  t('Search Filters.Features.Subtitles'),\n  t('Search Filters.Features.Creative Commons'),\n  t('Search Filters.Features.3D'),\n  t('Search Filters.Features.Live'),\n  t('Search Filters.Features.4K'),\n  t('Search Filters.Features.360 Video'),\n  t('Search Filters.Features.Location'),\n  t('Search Filters.Features.HDR'),\n  t('Search Filters.Features.VR180')\n])\n\nconst searchSettings = store.getters.getSearchSettings\n\n/** @type {import('vue').Ref<'relevance' | 'rating' | 'upload_date' | 'view_count'>} */\nconst sortByValue = ref(searchSettings.sortBy)\n\nwatch(sortByValue, (value) => {\n  store.commit('setSearchSortBy', value)\n})\n\n/** @type {import('vue').Ref<'' | 'hour' | 'today' | 'week' | 'month' | 'year'>} */\nconst timeValue = ref(searchSettings.time)\n\nwatch(timeValue, (value) => {\n  if (timeValue.value !== '' && !isVideoOrMovieOrAll(typeValue.value)) {\n    typeValue.value = 'all'\n  }\n\n  store.commit('setSearchTime', value)\n})\n\n/** @type {import('vue').Ref<'all' | 'video' | 'channel' | 'playlist' | 'movie'>} */\nconst typeValue = ref(searchSettings.type)\n\nwatch(typeValue, (value) => {\n  if (value === 'channel' || value === 'playlist') {\n    timeValue.value = ''\n    durationValue.value = ''\n    sortByValue.value = SORT_BY_VALUES[0]\n    if (featuresValue.value.length > 0) {\n      featuresValue.value = []\n    }\n  } else if (value === 'movie') {\n    if (featuresValue.value.length > 0) {\n      featuresValue.value = featuresValue.value.filter(e => !NOT_ALLOWED_FOR_MOVIES_FEATURES.includes(e))\n    }\n  }\n\n  store.commit('setSearchType', value)\n})\n\n/** @type {import('vue').Ref<'' | 'short' | 'medium' | 'long'>} */\nconst durationValue = ref(searchSettings.duration)\n\nwatch(durationValue, (value) => {\n  if (value !== '' && !isVideoOrMovieOrAll(typeValue.value)) {\n    typeValue.value = 'all'\n  }\n\n  store.commit('setSearchDuration', value)\n})\n\n/** @type {import('vue').Ref<('hd' | 'subtitles' | 'creative_commons' | '3d' | 'live' | '4k' | '360' | 'location' | 'hdr' | 'vr180')[]>} */\nconst featuresValue = ref([...searchSettings.features])\n\nwatch(featuresValue, (values) => {\n  if (values.length > 0 && (!isVideoOrMovieOrAll(typeValue.value) || NOT_ALLOWED_FOR_MOVIES_FEATURES.some(item => values.includes(item)))) {\n    typeValue.value = 'all'\n  }\n\n  store.commit('setSearchFeatures', [...values])\n}, { deep: true })\n\nconst searchFilterValueChanged = computed(() => {\n  return sortByValue.value !== SORT_BY_VALUES[0] ||\n    timeValue.value !== TIME_VALUES[0] ||\n    typeValue.value !== TYPE_VALUES[0] ||\n    durationValue.value !== DURATION_VALUES[0] ||\n    featuresValue.value.length > 0\n})\n\nwatch(searchFilterValueChanged, (value) => {\n  store.commit('setSearchFilterValueChanged', value)\n})\n\nfunction hideSearchFilters() {\n  store.dispatch('hideSearchFilters')\n}\n\n/**\n * @param {'all' | 'video' | 'channel' | 'playlist' | 'movie'} type\n */\nfunction isVideoOrMovieOrAll(type) {\n  return type === 'video' || type === 'movie' || type === 'all'\n}\n\nfunction clearFilters() {\n  sortByValue.value = SORT_BY_VALUES[0]\n  timeValue.value = TIME_VALUES[0]\n  typeValue.value = TYPE_VALUES[0]\n  durationValue.value = DURATION_VALUES[0]\n  featuresValue.value = []\n}\n\n</script>\n\n<style scoped src=\"./FtSearchFilters.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSelect/FtSelect.css",
    "content": "/*\n    This file is part of FreeTube.\n\n    FreeTube is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    FreeTube is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with FreeTube.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n/*\n* Credit goes to pavelvaravko for making this css.\n* https://codepen.io/pavelvaravko/pen/qjojOr\n*/\n\n/* select starting stylings ------------------------------ */\n.select {\n  position: relative;\n  inline-size: 200px;\n  margin-block-start: 30px;\n}\n\n.select-text {\n  position: relative;\n  font-family: inherit;\n  background-color: var(--search-bar-color);\n  color: var(--primary-text-color);\n  inline-size: 100%;\n  block-size: 45px;\n  padding-inline-start: 1rem;\n  font-size: 16px;\n  border-radius: 5px;\n  border: 0;\n}\n\n.select option {\n  color: var(--secondary-text-color);\n  background-color: var(--card-bg-color);\n}\n\n/* stylelint-disable-next-line a11y/no-outline-none */\n.select-text:focus {\n  outline: none;\n}\n\n/* Use custom arrow */\n.select .select-text {\n  appearance: none;\n  text-overflow: ellipsis;\n  padding-inline-end: 1.5rem;\n}\n\n.iconSelect {\n  position: absolute;\n  inset-block-start: 10px;\n  inset-inline-end: 10px;\n\n  /* Styling the down arrow */\n  padding: 0;\n  content: '';\n  border-inline-start: 6px solid transparent;\n  border-inline-end: 6px solid transparent;\n  pointer-events: none;\n  color: var(--tertiary-text-color);\n}\n\n.disabled,\n.disabled + .iconSelect {\n  opacity: 0.4;\n  cursor: not-allowed;\n}\n\n.selectTooltip {\n  position: absolute;\n  inset-block-start: -22px;\n  inset-inline-end: 13px;\n}\n\n\n/* LABEL ======================================= */\n.select-label {\n  font-size: 18px;\n  font-weight: normal;\n  position: absolute;\n  display: flex;\n  column-gap: 6px;\n  inset-inline-start: 0;\n  inset-block-start: 10px;\n  transition: 0.2s ease all;\n  color: var(--tertiary-text-color);\n}\n\n.select-icon {\n  inline-size: 14px;\n  block-size: 14px;\n}\n\n/* active state */\n.select-text:focus ~ .select-label,\n.select-text:valid ~ .select-label {\n  color: var(--accent-color);\n  inset-block-start: -20px;\n  transition: 0.2s ease all;\n  font-size: 14px;\n}\n\n/* BOTTOM BARS ================================= */\n.select-bar {\n  position: relative;\n  display: block;\n}\n\n.select-bar::before,\n.select-bar::after {\n  content: '';\n  block-size: 2px;\n  inline-size: 0;\n  inset-block-end: 1px;\n  position: absolute;\n  background: var(--accent-color);\n  transition: 0.2s ease all;\n}\n\n.select-bar::before {\n  inset-inline-start: 50%;\n}\n\n.select-bar::after {\n  inset-inline-end: 50%;\n}\n\n/* active state */\n.select-text:focus ~ .select-bar::before,\n.select-text:focus ~ .select-bar::after {\n  inline-size: 50%;\n}\n\n/* HIGHLIGHTER ================================== */\n.select-highlight {\n  position: absolute;\n  block-size: 60%;\n  inline-size: 100px;\n  inset-block-start: 25%;\n  inset-inline-start: 0;\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n@media only screen and (width <= 800px) {\n  .select {\n    inline-size: 100%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSelect/FtSelect.vue",
    "content": "<template>\n  <div class=\"select\">\n    <select\n      :id=\"id\"\n      :aria-describedby=\"describeById\"\n      class=\"select-text\"\n      :class=\"{ disabled }\"\n      :value=\"value\"\n      :name=\"id\"\n      :disabled=\"disabled\"\n      @change=\"change\"\n    >\n      <option\n        v-for=\"(name, index) in selectNames\"\n        :key=\"selectValues[index]\"\n        :dir=\"isLocaleSelector ? 'auto' : null\"\n        :value=\"selectValues[index]\"\n        :lang=\"isLocaleSelector && selectValues[index] !== 'system' ? selectValues[index] : null\"\n      >\n        {{ name }}\n      </option>\n    </select>\n    <FontAwesomeIcon\n      :icon=\"['fas', 'sort-down']\"\n      class=\"iconSelect\"\n    />\n    <span class=\"select-highlight\" />\n    <span class=\"select-bar\" />\n    <label\n      v-if=\"!disabled\"\n      class=\"select-label\"\n      :for=\"id\"\n    >\n      <FontAwesomeIcon\n        :icon=\"icon\"\n        class=\"select-icon\"\n        :color=\"iconColor\"\n      />\n      {{ placeholder }}\n    </label>\n    <FtTooltip\n      v-if=\"tooltip !== ''\"\n      class=\"selectTooltip\"\n      :tooltip=\"tooltip\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useId } from 'vue'\n\nimport FtTooltip from '../FtTooltip/FtTooltip.vue'\n\ndefineProps({\n  placeholder: {\n    type: String,\n    required: true\n  },\n  value: {\n    type: String,\n    required: true\n  },\n  selectNames: {\n    type: Array,\n    required: true\n  },\n  selectValues: {\n    type: Array,\n    required: true\n  },\n  tooltip: {\n    type: String,\n    default: ''\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n  describeById: {\n    type: String,\n    default: null\n  },\n  icon: {\n    type: Array,\n    required: true\n  },\n  iconColor: {\n    type: String,\n    default: null\n  },\n  isLocaleSelector: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst emit = defineEmits(['change'])\n\nconst id = useId()\n\n/**\n * @param {Event} event\n */\nfunction change(event) {\n  emit('change', event.target.value)\n}\n</script>\n\n<style scoped src=\"./FtSelect.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSettingsMenu/FtSettingsMenu.css",
    "content": ".settingsMenu {\n  /* top nav + margin */\n  inset-block-start: 96px;\n  position: sticky;\n  display: flex;\n  flex-direction: column;\n  padding-inline-start: 0;\n  block-size: calc(85vh - 96px);\n  max-block-size: 600px;\n}\n\n.header {\n  inline-size: fit-content;\n  margin-block: 0 10px;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n.title {\n  text-decoration: none;\n  color: var(--tertiary-text-color);\n  inline-size: 220px;\n  flex: 1 1 auto;\n  display: flex;\n  align-items: center;\n}\n\n/* prevent hover styling from showing on title click for mobile */\n@media (hover: hover) {\n  .title:hover {\n    color: var(--primary-text-color);\n  }\n}\n\n.titleContent {\n  inline-size: fit-content;\n  max-inline-size: 100%;\n}\n\n\n.iconAndTitleText {\n  overflow-x: hidden;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n\n  /* needed to have underline poke out */\n  margin-inline-start: 3px;\n}\n\n.titleUnderline {\n  /* have underline poke out */\n  inline-size: calc(100% + 6px);\n\n  /* prevent \"active\" border from visibly pushing the content up */\n  border-block-end: 4px solid transparent;\n}\n\n@media only screen and (width >= 1015px) {\n  .settingsMenu {\n    margin-block: 0;\n    font-size: 16px;\n  }\n\n  .header {\n    margin-block-start: 10px;\n    font-size: 26px;\n  }\n\n  .titleIcon {\n    inline-size: 16px;\n    block-size: 16px;\n  }\n\n  .title.active {\n    color: var(--primary-text-color);\n    font-weight: 600;\n  }\n\n  .title.active .titleUnderline {\n    border-block-end: 4px solid var(--primary-color);\n  }\n}\n\n/* overall mobile breakpoint; large text */\n@media only screen and (width <= 1015px) {\n  .settingsMenu {\n    inline-size: fit-content;\n    margin-inline: auto;\n    position: relative;\n    inset-block-start: 0;\n    font-size: 30px;\n    max-block-size: 1100px;\n  }\n\n  .titleIcon {\n    inline-size: 30px;\n    block-size: 30px;\n    margin-inline-end: 10px;\n  }\n\n  .title {\n    inline-size: fit-content;\n    max-inline-size: 90vw;\n  }\n\n  .header {\n    font-size: 32px;\n  }\n\n  /* hide the settings icon on mobile to avoid confusion */\n  .headingIcon {\n    display: none;\n  }\n}\n\n/* small height or width mobile breakpoint; intermediary text */\n@media only screen and (width <= 1015px) and (height <= 830px),\n  only screen and (width <= 500px) {\n  .settingsMenu {\n    font-size: 25px;\n  }\n\n  .titleIcon {\n    inline-size: 25px;\n    block-size: 25px;\n    margin-inline-end: 5px;\n  }\n\n  .header {\n    font-size: 25px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSettingsMenu/FtSettingsMenu.vue",
    "content": "<template>\n  <menu\n    class=\"settingsMenu\"\n  >\n    <h2 class=\"header\">\n      <FontAwesomeIcon\n        :icon=\"['fas', 'sliders-h']\"\n        class=\"headingIcon\"\n      />\n      {{ $t('Settings.Settings') }}\n    </h2>\n    <a\n      v-for=\"settingsSection in settingsSections\"\n      ref=\"linkRefs\"\n      :key=\"settingsSection.type\"\n      class=\"title\"\n      :class=\"{ active: activeSection === settingsSection.type }\"\n      href=\"javascript:;\"\n      :data-section=\"settingsSection.type\"\n      @click.stop=\"goToSettingsSection\"\n      @keydown.enter.stop=\"goToSettingsSection\"\n    >\n      <div class=\"titleContent\">\n        <div class=\"iconAndTitleText\">\n          <FontAwesomeIcon\n            :icon=\"settingsSection.icon\"\n            class=\"titleIcon\"\n          />\n          {{ settingsSection.title }}\n        </div>\n        <div class=\"titleUnderline\" />\n      </div>\n    </a>\n  </menu>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useTemplateRef } from 'vue'\n\ndefineProps({\n  settingsSections: {\n    type: Array,\n    required: true\n  },\n  activeSection: {\n    type: String,\n    default: null\n  }\n})\n\nconst emit = defineEmits(['navigate-to-section'])\n\n/**\n * @param {PointerEvent | KeyboardEvent} event\n */\nfunction goToSettingsSection(event) {\n  emit('navigate-to-section', event.currentTarget.dataset.section)\n}\n\nconst linkRefs = useTemplateRef('linkRefs')\n\ndefineExpose({\n  /**\n   * @param {string} name\n   */\n  focusLink: (name) => {\n    linkRefs.value.find((link) => link.dataset.section === name)?.focus()\n  }\n})\n</script>\n\n<style scoped src=\"./FtSettingsMenu.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSettingsSection/FtSettingsSection.scss",
    "content": ".settingsSection {\n  margin-block: 0;\n\n  @media only screen and (width <= 800px) {\n    inline-size: 100%;\n  }\n}\n\n.sectionHeader {\n  cursor: pointer;\n  display: block;\n  padding: 1px;\n}\n\n.sectionBody {\n  background-color: var(--card-bg-color);\n  padding-block: 10px;\n\n  > :deep(div) {\n    box-sizing: border-box;\n    padding-block: 0;\n    padding-inline: 20px;\n    inline-size: 100%;\n  }\n\n  > :deep(div:not(:last-child, .ft-flex-box)) {\n    @media only screen and (width <= 800px) {\n      margin-block-end: 20px;\n    }\n  }\n}\n\n.sectionTitle {\n  user-select: none;\n  margin-inline-start: 20px;\n  margin-block: 0.5em;\n}\n\n:deep(.groupTitle) {\n  text-align: center;\n  margin-block: 0.5em;\n}\n\n%switch-grid {\n  align-items: center;\n  display: grid;\n  grid-template-columns: auto auto;\n  justify-content: space-evenly;\n\n  @media only screen and (width <= 680px) {\n    grid-template-columns: auto;\n  }\n}\n\n:deep(.switchGrid) {\n  @extend %switch-grid;\n}\n\n:deep(.switchColumnGrid) {\n  @extend %switch-grid;\n\n  align-items: start;\n}\n\n:deep(.switchColumn) {\n  display: flex;\n  flex-direction: column;\n  align-items: start;\n}\n\n:deep(.center) {\n  text-align: center;\n}\n\n@media only screen and (width <= 460px) {\n  :deep(.settingsFlexStart460px) {\n    justify-content: flex-start;\n  }\n}\n\n@media only screen and (width <= 500px) {\n  :deep(.settingsFlexStart500px) {\n    justify-content: flex-start;\n  }\n}\n\n@media only screen and (width <= 680px) {\n  .settingsSection {\n    > :deep(div .text.bottom) {\n      inset-inline-start: -85px;\n    }\n\n    :deep(.switch-ctn.containsTooltip) {\n      inset-inline-start: -10px;\n      margin-inline-end: 5px;\n      padding-block: 0;\n      padding-inline: 10px;\n    }\n\n    :deep(:not(.select, .selectLabel) > .tooltip) {\n      display: inline-block;\n      position: absolute;\n      inset-inline-end: -25px;\n      inset-block-start: 12px;\n    }\n\n    :deep(.settingsFlexStart460px .tooltip) {\n      inset-inline-end: 0;\n      inset-block-start: -2px;\n    }\n\n    :deep(.switch-ctn) {\n      margin-block: 10px;\n      margin-inline: 7px;\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSettingsSection/FtSettingsSection.vue",
    "content": "<template>\n  <div\n    class=\"settingsSection\"\n  >\n    <div class=\"sectionBody\">\n      <h3 class=\"sectionTitle\">\n        {{ title }}\n      </h3>\n      <slot />\n    </div>\n  </div>\n</template>\n\n<script setup>\ndefineProps({\n  title: {\n    type: String,\n    required: true\n  }\n})\n</script>\n\n<style scoped src=\"./FtSettingsSection.scss\" lang=\"scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtShareButton/FtShareButton.css",
    "content": ".shareLinks {\n  display: grid;\n  grid-auto-flow: column;\n  grid-template-rows: auto auto;\n  padding: 12px;\n  inline-size: max-content;\n}\n\n.header {\n  color: var(--primary-text-color);\n  font-size: 18px;\n  font-weight: bold;\n  margin-block: 4px 8px;\n  margin-inline: 0;\n  display: flex;\n  justify-content: center;\n}\n\n.buttons {\n  display: flex;\n  flex-direction: column;\n  max-inline-size: min-content;\n  min-inline-size: 150px;\n}\n\n.action {\n  padding: 6px;\n  white-space: initial;\n}\n\n.divider {\n  background: var(--tertiary-text-color);\n  grid-row: span 3;\n  margin-block: 0;\n  margin-inline: 12px;\n  inline-size: 1px;\n}\n\n.youtubeLogo {\n  block-size: 18px;\n  inline-size: auto;\n}\n\n.invidious {\n  letter-spacing: -0.4px;\n}\n\n.invidiousLogo {\n  background-size: cover;\n  display: inline-block;\n  block-size: 20px;\n  margin-inline-end: 2px;\n  inline-size: 20px;\n}\n\n@media only screen and (width <= 450px) {\n  .shareLinks {\n    grid-auto-flow: row;\n    margin-inline: auto;\n    justify-items: center;\n    max-inline-size: max-content;\n  }\n\n  .header.invidious {\n    margin-block-start: 20px;\n  }\n\n  .buttons {\n    max-inline-size: min-content;\n    min-inline-size: 180px;\n  }\n\n  .divider {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtShareButton/FtShareButton.vue",
    "content": "<template>\n  <FtIconButton\n    ref=\"iconButton\"\n    :title=\"shareTitle\"\n    theme=\"secondary\"\n    :size=\"size\"\n    :icon=\"['fas', 'share-alt']\"\n    :dropdown-modal-on-mobile=\"true\"\n    dropdown-position-x=\"left\"\n    :dropdown-position-y=\"dropdownPositionY\"\n    :force-dropdown=\"true\"\n  >\n    <FtFlexBox>\n      <FtToggleSwitch\n        v-if=\"isVideo\"\n        :label=\"t('Share.Include Timestamp')\"\n        :compact=\"true\"\n        :default-value=\"includeTimestamp\"\n        @change=\"updateIncludeTimestamp\"\n      />\n    </FtFlexBox>\n    <div class=\"shareLinks\">\n      <div class=\"header\">\n        <img\n          id=\"youtubeShareImage\"\n          class=\"youtubeLogo\"\n          src=\"~../../assets/img/yt_logo_mono_dark.png\"\n          alt=\"YouTube\"\n          width=\"794\"\n          height=\"178\"\n        >\n      </div>\n\n      <div class=\"buttons\">\n        <FtButton\n          class=\"action\"\n          aria-describedby=\"youtubeShareImage\"\n          :icon=\"['fas', 'copy']\"\n          :label=\"t('Share.Copy Link')\"\n          @click=\"copyYoutube\"\n        />\n        <FtButton\n          class=\"action\"\n          aria-describedby=\"youtubeShareImage\"\n          :icon=\"['fas', 'globe']\"\n          :label=\"t('Share.Open Link')\"\n          @click=\"openYoutube\"\n        />\n        <FtButton\n          v-if=\"isVideo || isPlaylist\"\n          class=\"action\"\n          aria-describedby=\"youtubeShareImage\"\n          background-color=\"var(--accent-color-active)\"\n          :icon=\"['fas', 'copy']\"\n          :label=\"t('Share.Copy Embed')\"\n          @click=\"copyYoutubeEmbed\"\n        />\n        <FtButton\n          v-if=\"isVideo || isPlaylist\"\n          class=\"action\"\n          aria-describedby=\"youtubeShareImage\"\n          background-color=\"var(--accent-color-active)\"\n          :icon=\"['fas', 'globe']\"\n          :label=\"t('Share.Open Embed')\"\n          @click=\"openYoutubeEmbed\"\n        />\n      </div>\n\n      <template v-if=\"showInvidiousOptions\">\n        <div class=\"divider\" />\n\n        <div\n          id=\"invidiousShare\"\n          class=\"header invidious\"\n        >\n          <span class=\"invidiousLogo\" /> Invidious\n        </div>\n\n        <div class=\"buttons\">\n          <FtButton\n            aria-describedby=\"invidiousShare\"\n            class=\"action\"\n            :icon=\"['fas', 'copy']\"\n            :label=\"t('Share.Copy Link')\"\n            @click=\"copyInvidious\"\n          />\n          <FtButton\n            aria-describedby=\"invidiousShare\"\n            class=\"action\"\n            :icon=\"['fas', 'globe']\"\n            :label=\"t('Share.Open Link')\"\n            @click=\"openInvidious\"\n          />\n          <FtButton\n            v-if=\"isVideo || isPlaylist\"\n            aria-describedby=\"invidiousShare\"\n            class=\"action\"\n            background-color=\"var(--accent-color-active)\"\n            :icon=\"['fas', 'copy']\"\n            :label=\"t('Share.Copy Embed')\"\n            @click=\"copyInvidiousEmbed\"\n          />\n          <FtButton\n            v-if=\"isVideo || isPlaylist\"\n            aria-describedby=\"invidiousShare\"\n            class=\"action\"\n            background-color=\"var(--accent-color-active)\"\n            :icon=\"['fas', 'globe']\"\n            :label=\"t('Share.Open Embed')\"\n            @click=\"openInvidiousEmbed\"\n          />\n        </div>\n      </template>\n    </div>\n  </FtIconButton>\n</template>\n\n<script setup>\nimport { computed, ref, useTemplateRef } from 'vue'\nimport { copyToClipboard, openExternalLink } from '../../helpers/utils'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport store from '../../store/index'\n\nconst { t } = useI18n()\n\nconst props = defineProps({\n  shareTargetType: {\n    /**\n     * Allows to render the dropdown conditionally\n     * 'Channel' will exclude embed links\n     * 'Video' (default) keeps the original behaviour\n     */\n    type: String,\n    default: 'Video'\n  },\n  id: {\n    type: String,\n    required: true\n  },\n  playlistId: {\n    type: String,\n    default: ''\n  },\n  getTimestamp: {\n    type: Function,\n    default: null\n  },\n  dropdownPositionY: {\n    type: String,\n    default: 'bottom'\n  },\n  size: {\n    type: Number,\n    default: 20\n  }\n})\n\nconst includeTimestamp = ref(false)\nconst iconButton = useTemplateRef('iconButton')\n\nconst isChannel = computed(() => {\n  return props.shareTargetType === 'Channel'\n})\n\nconst isPlaylist = computed(() => {\n  return props.shareTargetType === 'Playlist'\n})\n\nconst isPost = computed(() => {\n  return props.shareTargetType === 'Post'\n})\n\nconst isVideo = computed(() => {\n  return props.shareTargetType === 'Video'\n})\n\nconst shareTitle = computed(() => {\n  if (isChannel.value) {\n    return t('Share.Share Channel')\n  }\n  if (isPlaylist.value) {\n    return t('Share.Share Playlist')\n  }\n  if (isPost.value) {\n    return t('Share.Share Post')\n  }\n  return t('Share.Share Video')\n})\n\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\nconst showInvidiousOptions = computed(() => {\n  return store.getters.getBackendPreference === 'invidious' || store.getters.getBackendFallback\n})\n\nconst selectedUserPlaylist = computed(() => {\n  if (props.playlistId == null || props.playlistId === '') { return null }\n\n  return store.getters.getPlaylist(props.playlistId)\n})\n\nconst playlistSharable = computed(() => {\n  // `playlistId` can be undefined\n  // User playlist ID should not be shared\n  return props.playlistId && props.playlistId.length !== 0 && selectedUserPlaylist.value == null\n})\n\nconst invidiousURL = computed(() => {\n  if (isChannel.value) {\n    return `${currentInvidiousInstanceUrl.value}/channel/${props.id}`\n  }\n  if (isPlaylist.value) {\n    return `${currentInvidiousInstanceUrl.value}/playlist?list=${props.id}`\n  }\n  if (isPost.value) {\n    return `${currentInvidiousInstanceUrl.value}/post/${props.id}`\n  }\n  let videoUrl = `${currentInvidiousInstanceUrl.value}/watch?v=${props.id}`\n  // `playlistId` can be undefined\n  if (playlistSharable.value) {\n    // `index` seems can be ignored\n    videoUrl += `&list=${props.playlistId}`\n  }\n  return videoUrl\n})\n\nconst invidiousEmbedURL = computed(() => {\n  if (isPlaylist.value) {\n    return `${currentInvidiousInstanceUrl.value}/embed/videoseries?list=${props.id}`\n  }\n  return `${currentInvidiousInstanceUrl.value}/embed/${props.id}`\n})\n\nconst youtubeChannelUrl = computed(() => {\n  return `https://www.youtube.com/channel/${props.id}`\n})\n\nconst youtubePlaylistUrl = computed(() => {\n  return `https://youtube.com/playlist?list=${props.id}`\n})\n\nconst youtubeURL = computed(() => {\n  if (isChannel.value) {\n    return youtubeChannelUrl.value\n  }\n  if (isPlaylist.value) {\n    return youtubePlaylistUrl.value\n  }\n  if (isPost.value) {\n    return `https://www.youtube.com/post/${props.id}`\n  }\n  let videoUrl = `https://www.youtube.com/watch?v=${props.id}`\n  if (playlistSharable.value) {\n    // `index` seems can be ignored\n    videoUrl += `&list=${props.playlistId}`\n  }\n  return videoUrl\n})\n\nconst youtubeShareURL = computed(() => {\n  if (isChannel.value) {\n    return youtubeChannelUrl.value\n  }\n  if (isPlaylist.value) {\n    return youtubePlaylistUrl.value\n  }\n  if (isPost.value) {\n    return `https://www.youtube.com/post/${props.id}`\n  }\n  const videoUrl = `https://youtu.be/${props.id}`\n  if (playlistSharable.value) {\n    // `index` seems can be ignored\n    return `${videoUrl}?list=${props.playlistId}`\n  }\n  return videoUrl\n})\n\nconst youtubeEmbedURL = computed(() => {\n  if (isPlaylist.value) {\n    return `https://www.youtube-nocookie.com/embed/videoseries?list=${props.id}`\n  }\n  return `https://www.youtube-nocookie.com/embed/${props.id}`\n})\n\nif (isVideo.value && !props.getTimestamp) {\n  console.error('Error in props validation: A Video FtShareButton requires a valid get-timestamp function.')\n}\n\nfunction openInvidious() {\n  openExternalLink(getFinalUrl(invidiousURL.value))\n  iconButton.value.hideDropdown()\n}\n\nfunction copyInvidious() {\n  copyToClipboard(getFinalUrl(invidiousURL.value), { messageOnSuccess: t('Share.Invidious URL copied to clipboard') })\n  iconButton.value.hideDropdown()\n}\n\nfunction openYoutube() {\n  openExternalLink(getFinalUrl(youtubeURL.value))\n  iconButton.value.hideDropdown()\n}\n\nfunction copyYoutube() {\n  copyToClipboard(getFinalUrl(youtubeShareURL.value), { messageOnSuccess: t('Share.YouTube URL copied to clipboard') })\n  iconButton.value.hideDropdown()\n}\n\nfunction openYoutubeEmbed() {\n  openExternalLink(getFinalUrl(youtubeEmbedURL.value))\n  iconButton.value.hideDropdown()\n}\n\nfunction copyYoutubeEmbed() {\n  copyToClipboard(getFinalUrl(youtubeEmbedURL.value), { messageOnSuccess: t('Share.YouTube Embed URL copied to clipboard') })\n  iconButton.value.hideDropdown()\n}\n\nfunction openInvidiousEmbed() {\n  openExternalLink(getFinalUrl(invidiousEmbedURL.value))\n  iconButton.value.hideDropdown()\n}\n\nfunction copyInvidiousEmbed() {\n  copyToClipboard(getFinalUrl(invidiousEmbedURL.value), { messageOnSuccess: t('Share.Invidious Embed URL copied to clipboard') })\n  iconButton.value.hideDropdown()\n}\n\nfunction updateIncludeTimestamp() {\n  includeTimestamp.value = !includeTimestamp.value\n}\n\nfunction getFinalUrl(url) {\n  if (isChannel.value || isPlaylist.value || isPost.value) {\n    return url\n  }\n  if (url.indexOf('?') === -1) {\n    return includeTimestamp.value ? `${url}?t=${props.getTimestamp()}` : url\n  }\n  return includeTimestamp.value ? `${url}&t=${props.getTimestamp()}` : url\n}\n</script>\n<style scoped src=\"./FtShareButton.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSlider/FtSlider.css",
    "content": ".pure-material-slider {\n  display: inline-block;\n  inline-size: 380px;\n  color: rgb(var(--primary-text-color) 0.87);\n  font-size: 16px;\n  line-height: 1.5;\n  padding: 5px;\n  margin-block: 12px;\n  margin-inline: 8px;\n}\n\n.input {\n  appearance: none;\n  position: relative;\n  inset-block-start: 24px;\n  display: block;\n  margin-block: 0 -36px;\n  margin-inline: 0;\n  inline-size: 100%;\n  block-size: 36px;\n  background-color: transparent;\n  cursor: pointer;\n}\n\n/* Without Span */\n.input:last-child {\n  position: static;\n  margin: 0;\n}\n\n.label {\n  display: inline-block;\n  margin-block-end: 36px;\n}\n/* stylelint-disable-next-line a11y/no-outline-none */\n.input:focus {\n  outline: none;\n}\n\n.input:disabled {\n  cursor: default;\n  opacity: 0.38;\n}\n\n.input:disabled + .label {\n  opacity: 0.38;\n}\n\n.input::-webkit-slider-runnable-track {\n  margin-block: 17px;\n  margin-inline: 0;\n  border-radius: 1px;\n  inline-size: 100%;\n  block-size: 2px;\n  background-color: var(--accent-color-opacity4);\n}\n\n.input::-webkit-slider-thumb {\n  appearance: none;\n  border: 0;\n  border-radius: 50%;\n  block-size: 2px;\n  inline-size: 2px;\n  background-color: var(--accent-color);\n  transform: scale(6, 6);\n  transition: box-shadow 0.2s;\n}\n\n.input:focus::-webkit-slider-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity2);\n}\n\n.input:active::-webkit-slider-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity4) !important;\n}\n\n.input:disabled::-webkit-slider-thumb {\n  background-color: #000;\n  color: #fff; /* Safari */\n  box-shadow: 0 0 0 1px #fff !important;\n  transform: scale(4, 4);\n}\n\n.pure-material-slider:hover > .input::-webkit-slider-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity1);\n}\n\n.pure-material-slider:hover > .input:focus::-webkit-slider-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity3);\n}\n\n.input:disabled::-webkit-slider-runnable-track {\n  background-color: rgb(0 0 0 / 38%);\n}\n\n.input::-moz-range-track {\n  margin-block: 0;\n  margin: 17px;\n  border-radius: 1px;\n  inline-size: 100%;\n  block-size: 2px;\n  background-color: var(--accent-color-opacity4);\n}\n\n.input::-moz-range-thumb {\n  appearance: none;\n  border: 0;\n  border-radius: 50%;\n  block-size: 2px;\n  inline-size: 2px;\n  background-color: var(--accent-color);\n  transform: scale(6, 6);\n  transition: box-shadow 0.2s;\n}\n\n.input::-moz-range-progress {\n  border-radius: 1px;\n  block-size: 2px;\n  background-color: var(--accent-color);\n}\n\n.input:focus::-moz-range-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity2);\n}\n\n.input:active::-moz-range-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity4) !important;\n}\n\n.input:disabled::-moz-range-thumb {\n  background-color: #000;\n  box-shadow: 0 0 0 1px #fff !important;\n  transform: scale(4, 4);\n}\n\n.pure-material-slider:hover > .input:hover::-moz-range-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity1);\n}\n\n.pure-material-slider:hover > input:focus::-moz-range-thumb {\n  box-shadow: 0 0 0 2px var(--accent-color-opacity3);\n}\n\n.input:disabled::-moz-range-track {\n  background-color: rgb(0 0 0 / 38%);\n}\n\n.input:disabled::-moz-range-progress {\n  background-color: rgb(0 0 0 / 87%);\n}\n\n.input::-moz-focus-outer {\n  border: 0;\n}\n\n@media only screen and (width <= 680px) {\n  .pure-material-slider {\n    inline-size: 100%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSlider/FtSlider.vue",
    "content": "<template>\n  <label\n    class=\"pure-material-slider\"\n    :for=\"id\"\n  >\n    <input\n      :id=\"id\"\n      v-model.number=\"currentValue\"\n      class=\"input\"\n      :disabled=\"disabled\"\n      type=\"range\"\n      :min=\"minValue\"\n      :max=\"maxValue\"\n      :step=\"step\"\n      @change=\"change\"\n    >\n    <span class=\"label\">\n      {{ $t('Display Label', {label: label, value: displayLabel}) }}\n    </span>\n  </label>\n</template>\n\n<script setup>\nimport { computed, ref, useId, watch } from 'vue'\n\nconst props = defineProps({\n  label: {\n    type: String,\n    required: true\n  },\n  defaultValue: {\n    type: Number,\n    required: true\n  },\n  minValue: {\n    type: Number,\n    required: true\n  },\n  maxValue: {\n    type: Number,\n    required: true\n  },\n  step: {\n    type: Number,\n    required: true\n  },\n  valueExtension: {\n    type: String,\n    default: null\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  }\n})\n\nconst emit = defineEmits(['change'])\n\nconst id = useId()\nconst currentValue = ref(props.defaultValue)\n\nwatch(() => props.defaultValue, (value) => {\n  if (currentValue.value !== value) {\n    currentValue.value = value\n  }\n})\n\nconst displayLabel = computed(() => {\n  if (props.valueExtension === null) {\n    return currentValue.value\n  } else {\n    return `${currentValue.value}${props.valueExtension}`\n  }\n})\n\nfunction change() {\n  emit('change', currentValue.value)\n}\n\n</script>\n<style scoped src=\"./FtSlider.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSponsorBlockCategory/FtSponsorBlockCategory.css",
    "content": ".sponsorBlockCategory {\n  margin-block-start: 30px;\n  padding-block: 0;\n  padding-inline: 10px;\n}\n\n.sponsorTitle {\n  font-size: x-large;\n}\n\n@media only screen and (width <= 680px) {\n  .sponsorBlockCategory {\n    inline-size: 100%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtSponsorBlockCategory/FtSponsorBlockCategory.vue",
    "content": "<template>\n  <div class=\"sponsorBlockCategory\">\n    <div\n      :id=\"id\"\n      class=\"sponsorTitle\"\n    >\n      {{ translatedCategoryName }}\n    </div>\n    <FtSelect\n      :describe-by-id=\"id\"\n      :placeholder=\"$t('Settings.SponsorBlock Settings.Category Color')\"\n      :value=\"sponsorBlockValues.color\"\n      :select-names=\"colorNames\"\n      :select-values=\"COLOR_VALUES\"\n      :icon=\"['fas', 'palette']\"\n      :class=\"'sec' + sponsorBlockValues.color\"\n      icon-color=\"rgb(var(--accent-color-rgb))\"\n      @change=\"updateColor\"\n    />\n    <FtSelect\n      :describe-by-id=\"id\"\n      :placeholder=\"$t('Settings.SponsorBlock Settings.Skip Options.Skip Option')\"\n      :value=\"sponsorBlockValues.skip\"\n      :select-names=\"skipNames\"\n      :select-values=\"SKIP_VALUES\"\n      :icon=\"['fas', 'forward']\"\n      @change=\"updateSkipOption\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed, useId } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtSelect from '../FtSelect/FtSelect.vue'\n\nimport store from '../../store/index'\n\nimport { colors } from '../../helpers/colors'\nimport { useColorTranslations } from '../../composables/colors'\n\nconst props = defineProps({\n  categoryName: {\n    type: String,\n    required: true\n  }\n})\n\nconst { t } = useI18n()\n\nconst SKIP_VALUES = [\n  'autoSkip',\n  // 'promptToSkip',\n  'showInSeekBar',\n  'doNothing'\n]\n\nconst skipNames = computed(() => [\n  t('Settings.SponsorBlock Settings.Skip Options.Auto Skip'),\n  // t('Settings.SponsorBlock Settings.Skip Options.Prompt To Skip'),\n  t('Settings.SponsorBlock Settings.Skip Options.Show In Seek Bar'),\n  t('Settings.SponsorBlock Settings.Skip Options.Do Nothing')\n])\n\nconst COLOR_VALUES = colors.map(color => color.name)\nconst colorNames = useColorTranslations()\n\nconst id = useId()\n\n/** @type {import('vue').ComputedRef<{ color: string, skip: string }>} */\nconst sponsorBlockValues = computed(() => {\n  switch (props.categoryName) {\n    case 'sponsor':\n      return store.getters.getSponsorBlockSponsor\n    case 'self-promotion':\n      return store.getters.getSponsorBlockSelfPromo\n    case 'interaction':\n      return store.getters.getSponsorBlockInteraction\n    case 'intro':\n      return store.getters.getSponsorBlockIntro\n    case 'outro':\n      return store.getters.getSponsorBlockOutro\n    case 'recap':\n      return store.getters.getSponsorBlockRecap\n    case 'music offtopic':\n      return store.getters.getSponsorBlockMusicOffTopic\n    case 'filler':\n      return store.getters.getSponsorBlockFiller\n    default:\n      return ''\n  }\n})\n\nconst translatedCategoryName = computed(() => {\n  switch (props.categoryName) {\n    case 'sponsor':\n      return t('Video.Sponsor Block category.sponsor')\n    case 'self-promotion':\n      return t('Video.Sponsor Block category.self-promotion')\n    case 'interaction':\n      return t('Video.Sponsor Block category.interaction')\n    case 'intro':\n      return t('Video.Sponsor Block category.intro')\n    case 'outro':\n      return t('Video.Sponsor Block category.outro')\n    case 'recap':\n      return t('Video.Sponsor Block category.recap')\n    case 'music offtopic':\n      return t('Video.Sponsor Block category.music offtopic')\n    case 'filler':\n      return t('Video.Sponsor Block category.filler')\n    default:\n      return ''\n  }\n})\n\n/**\n * @param {string} color\n */\nfunction updateColor(color) {\n  updateSponsorCategory({\n    color,\n    skip: sponsorBlockValues.value.skip\n  })\n}\n\n/**\n * @param {string} skipOption\n */\nfunction updateSkipOption(skipOption) {\n  updateSponsorCategory({\n    color: sponsorBlockValues.value.color,\n    skip: skipOption\n  })\n}\n\n/**\n * @param {{ color: string, skip: string }} payload\n */\nfunction updateSponsorCategory(payload) {\n  switch (props.categoryName) {\n    case 'sponsor':\n      store.dispatch('updateSponsorBlockSponsor', payload)\n      break\n    case 'self-promotion':\n      store.dispatch('updateSponsorBlockSelfPromo', payload)\n      break\n    case 'interaction':\n      store.dispatch('updateSponsorBlockInteraction', payload)\n      break\n    case 'intro':\n      store.dispatch('updateSponsorBlockIntro', payload)\n      break\n    case 'outro':\n      store.dispatch('updateSponsorBlockOutro', payload)\n      break\n    case 'recap':\n      store.dispatch('updateSponsorBlockRecap', payload)\n      break\n    case 'music offtopic':\n      store.dispatch('updateSponsorBlockMusicOffTopic', payload)\n      break\n    case 'filler':\n      store.dispatch('updateSponsorBlockFiller', payload)\n      break\n  }\n}\n</script>\n\n<style scoped src=\"./FtSponsorBlockCategory.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtSubscribeButton/FtSubscribeButton.css",
    "content": ".buttonList {\n  margin: 5px;\n  margin-block-end: 10px;\n  border-radius: 4px;\n  block-size: fit-content;\n  box-shadow: 0 1px 2px rgb(0 0 0 / 50%);\n  display: flex;\n  flex-wrap: nowrap;\n\n  /* addresses odd clipping behavior when adjusting window size */\n  background-color: var(--primary-color);\n}\n\n.ftSubscribeButton {\n  position: relative;\n  text-align: start;\n  inline-size: fit-content;\n}\n\n.subscribeButton {\n  min-inline-size: 150px;\n  white-space: initial;\n}\n\n.subscribeButton,\n.profileDropdownToggle {\n  align-self: center;\n  margin-block: 0;\n  margin-inline: 0;\n}\n\n.profileDropdownToggle {\n  border-inline-start: none !important;\n  border-start-start-radius: 0;\n  border-end-start-radius: 0;\n  display: inline-block;\n  min-inline-size: 1em;\n  padding-inline: 10px;\n  box-sizing: content-box;\n}\n\n.subscribeButton.hasProfileDropdownToggle {\n  min-inline-size: 100px;\n  padding-inline: 5px;\n  border-inline-end: 2px solid var(--primary-color-active) !important;\n  border-start-end-radius: 0;\n  border-end-end-radius: 0;\n  box-sizing: content-box;\n}\n\n.subscribeButton.hasProfileDropdownToggle,\n.profileDropdownToggle {\n  padding-block: 5px;\n  padding-inline: 6px;\n  box-shadow: none;\n  flex: auto;\n  block-size: 2em;\n}\n\n.subscribeButton.dropdownOpened,\n.profileDropdownToggle.dropdownOpened {\n  border-end-start-radius: 0;\n  border-end-end-radius: 0;\n}\n\n.profileDropdown {\n  background-color: var(--side-nav-color);\n  box-shadow: 0 1px 2px rgb(0 0 0 / 50%);\n  color: var(--secondary-text-color);\n  display: inline;\n  font-size: 12px;\n  max-block-size: 200px;\n  margin-block: -10px 0;\n  margin-inline: 5px 0;\n  overflow-y: scroll;\n  position: absolute;\n  text-align: center;\n  user-select: none;\n  z-index: 3;\n\n  /* accounts for parent's left and right margins */\n  inline-size: calc(100% - 10px);\n}\n\n.profileList {\n  list-style-type: none;\n  margin: 0;\n  padding-inline: 0;\n}\n\n.profile {\n  cursor: pointer;\n  display: flex;\n  gap: 0.5em;\n  padding-inline-start: 0.5em;\n  block-size: 50px;\n  align-items: center;\n  transition: background 0.2s ease-out;\n}\n\n.profile:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.colorOption {\n  inline-size: 40px;\n  block-size: 40px;\n  cursor: pointer;\n  align-items: center;\n  display: flex;\n  justify-content: center;\n  flex-shrink: 0;\n  border-radius: 50%;\n}\n\n.initial {\n  font-size: 20px;\n  line-height: 1em;\n  text-align: center;\n  user-select: none;\n}\n\n.profileName {\n  padding-inline-end: 1em;\n  text-align: start;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.profile.subscribed {\n  background-color: var(--primary-color);\n}\n\n.profile.subscribed > .profileName {\n  color: var(--text-with-main-color);\n}\n"
  },
  {
    "path": "src/renderer/components/FtSubscribeButton/FtSubscribeButton.vue",
    "content": "<template>\n  <div\n    ref=\"subscribeButton\"\n    class=\"ftSubscribeButton\"\n    @focusout=\"handleProfileDropdownFocusOut\"\n  >\n    <div\n      class=\"buttonList\"\n    >\n      <FtButton\n        :label=\"subscribedText\"\n        :no-border=\"true\"\n        class=\"subscribeButton\"\n        :class=\"{\n          hasProfileDropdownToggle: isProfileDropdownEnabled,\n          dropdownOpened: isProfileDropdownOpen\n        }\"\n        background-color=\"var(--primary-color)\"\n        text-color=\"var(--text-with-main-color)\"\n        @click=\"handleSubscription(activeProfile)\"\n      />\n      <FtPrompt\n        v-if=\"showUnsubscribePopupForProfile !== null\"\n        :label=\"$t('Channels.Unsubscribe Prompt', { channelName: channelName })\"\n        :option-names=\"[$t('Yes'), $t('No')]\"\n        :option-values=\"['yes', 'no']\"\n        :autosize=\"true\"\n        @click=\"handleUnsubscribeConfirmation\"\n      />\n      <FtButton\n        v-if=\"isProfileDropdownEnabled\"\n        :no-border=\"true\"\n        :title=\"isProfileDropdownOpen ? $t('Profile.Close Profile Dropdown') : $t('Profile.Open Profile Dropdown')\"\n        class=\"profileDropdownToggle\"\n        :class=\"{ dropdownOpened: isProfileDropdownOpen}\"\n        background-color=\"var(--primary-color)\"\n        text-color=\"var(--text-with-main-color)\"\n        :aria-expanded=\"isProfileDropdownOpen\"\n        @click=\"toggleProfileDropdown\"\n      >\n        <FontAwesomeIcon\n          :icon=\"isProfileDropdownOpen ? ['fas', 'angle-up'] : ['fas', 'angle-down']\"\n        />\n      </FtButton>\n    </div>\n    <div\n      v-if=\"isProfileDropdownOpen\"\n      tabindex=\"-1\"\n      class=\"profileDropdown\"\n    >\n      <ul\n        class=\"profileList\"\n      >\n        <li\n          v-for=\"(profile, index) in profileDisplayList\"\n          :key=\"index\"\n          class=\"profile\"\n          :class=\"{\n            subscribed: isProfileSubscribed(profile)\n          }\"\n          :aria-labelledby=\"id + '-' + index\"\n          :aria-selected=\"isActiveProfile(profile)\"\n          :aria-checked=\"isProfileSubscribed(profile)\"\n          tabindex=\"0\"\n          role=\"checkbox\"\n          @click.stop.prevent=\"handleSubscription(profile)\"\n          @keydown.space.stop.prevent=\"handleSubscription(profile)\"\n        >\n          <div\n            class=\"colorOption\"\n            :style=\"{ background: profile.bgColor, color: profile.textColor }\"\n          >\n            <div\n              class=\"initial\"\n              dir=\"auto\"\n            >\n              {{ isProfileSubscribed(profile) ? $t('checkmark') : profileInitials[profile._id] }}\n            </div>\n          </div>\n          <p\n            :id=\"id + '-' + index\"\n            class=\"profileName\"\n            dir=\"auto\"\n          >\n            {{ profile.name }}\n          </p>\n        </li>\n      </ul>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, ref, shallowRef, useId, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\n\nimport store from '../../store/index'\n\nimport { MAIN_PROFILE_ID } from '../../../constants'\nimport { showToast } from '../../helpers/utils'\nimport { getFirstCharacter } from '../../helpers/strings'\n\nconst { locale, t } = useI18n()\n\nconst props = defineProps({\n  channelId: {\n    type: String,\n    required: true\n  },\n  channelName: {\n    type: String,\n    required: true\n  },\n  channelThumbnail: {\n    type: String,\n    default: null\n  },\n  hideProfileDropdownToggle: {\n    type: Boolean,\n    default: false\n  },\n  openDropdownOnSubscribe: {\n    type: Boolean,\n    default: true\n  },\n  subscriptionCountText: {\n    type: String,\n    default: ''\n  }\n})\n\nconst emit = defineEmits(['subscribed'])\n\nconst id = useId()\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\n/** @type {import('vue').ComputedRef<Profile[]>} */\nconst profileList = computed(() => {\n  return store.getters.getProfileList\n})\n\n/** @type {import('vue').ComputedRef<Profile>} */\nconst activeProfile = computed(() => {\n  return store.getters.getActiveProfile\n})\n\nconst profileDisplayList = computed(() => [\n  profileList.value[0],\n  ...(activeProfile.value._id !== MAIN_PROFILE_ID ? [activeProfile.value] : []),\n  ...profileList.value.filter((profile, i) => i !== 0 && !isActiveProfile(profile) && !isProfileSubscribed(profile)),\n  ...profileList.value.filter((profile, i) => i !== 0 && !isActiveProfile(profile) && isProfileSubscribed(profile))\n])\n\nconst profileInitials = computed(() => {\n  const locale_ = locale.value\n\n  return profileList.value.reduce((accumulator, profile) => {\n    accumulator[profile._id] = profile.name\n      ? getFirstCharacter(profile.name, locale_)\n      : ''\n\n    return accumulator\n  }, {})\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelSubscriptions = computed(() => {\n  return store.getters.getHideChannelSubscriptions\n})\n\nconst subscribedText = computed(() => {\n  let subscribedValue = (isProfileSubscribed(activeProfile.value) ? t('Channel.Unsubscribe') : t('Channel.Subscribe'))\n  if (props.subscriptionCountText !== '' && !hideChannelSubscriptions.value) {\n    subscribedValue += ' ' + props.subscriptionCountText\n  }\n  return subscribedValue\n})\n\nconst isProfileDropdownEnabled = computed(() => {\n  return !props.hideProfileDropdownToggle && profileList.value.length > 1\n})\n\nconst isProfileDropdownOpen = ref(false)\n/** @type {import('vue').ShallowRef<Profile | null>} */\nconst showUnsubscribePopupForProfile = shallowRef(null)\n\n/**\n * @param {Profile} profile\n */\nfunction handleSubscription(profile) {\n  if (props.channelId === '') {\n    return\n  }\n\n  if (isProfileSubscribed(profile)) {\n    if (store.getters.getUnsubscriptionPopupStatus) {\n      showUnsubscribePopupForProfile.value = profile\n    } else {\n      handleUnsubscription(profile)\n    }\n  } else {\n    const profileIds = [profile._id]\n\n    if (profile._id !== MAIN_PROFILE_ID) {\n      const primaryProfile = profileList.value.find(prof => {\n        return prof._id === MAIN_PROFILE_ID\n      })\n\n      if (!isProfileSubscribed(primaryProfile)) {\n        profileIds.push(MAIN_PROFILE_ID)\n      }\n    }\n\n    store.dispatch('addChannelToProfiles', {\n      channel: {\n        id: props.channelId,\n        name: props.channelName,\n        thumbnail: props.channelThumbnail\n      },\n      profileIds\n    })\n\n    showToast(t('Channel.Added channel to your subscriptions'))\n    emit('subscribed')\n  }\n\n  if (isProfileDropdownEnabled.value && props.openDropdownOnSubscribe && !isProfileDropdownOpen.value) {\n    toggleProfileDropdown()\n  }\n}\n\nconst subscribeButton = useTemplateRef('subscribeButton')\n\nfunction handleProfileDropdownFocusOut() {\n  if (subscribeButton.value && !subscribeButton.value.matches(':focus-within')) {\n    isProfileDropdownOpen.value = false\n  }\n}\n\nfunction toggleProfileDropdown() {\n  isProfileDropdownOpen.value = !isProfileDropdownOpen.value\n}\n\n/**\n * @param {'yes' | 'no' | null} value\n */\nfunction handleUnsubscribeConfirmation(value) {\n  const profile = showUnsubscribePopupForProfile.value\n  showUnsubscribePopupForProfile.value = null\n\n  if (value === 'yes') {\n    handleUnsubscription(profile)\n  }\n}\n\n/**\n * @param {Profile} profile\n */\nfunction handleUnsubscription(profile) {\n  const profileIds = [profile._id]\n\n  if (profile._id === MAIN_PROFILE_ID) {\n    // Check if a subscription exists in a different profile.\n    // Remove from there as well.\n\n    profileList.value.forEach((profileInList) => {\n      if (profileInList._id === MAIN_PROFILE_ID) {\n        return\n      }\n\n      if (isProfileSubscribed(profileInList)) {\n        profileIds.push(profileInList._id)\n      }\n    })\n  }\n\n  store.dispatch('removeChannelFromProfiles', { channelId: props.channelId, profileIds })\n\n  showToast(t('Channel.Channel has been removed from your subscriptions'))\n\n  if (profile._id === MAIN_PROFILE_ID && profileIds.length > 1) {\n    showToast(t('Channel.Removed subscription from {count} other channel(s)', { count: profileIds.length - 1 }))\n  }\n}\n\n/**\n * @param {Profile} profile\n */\nfunction isActiveProfile(profile) {\n  return profile._id === activeProfile.value._id\n}\n\n/**\n * @param {Profile} profile\n */\nfunction isProfileSubscribed(profile) {\n  const channelId = props.channelId\n\n  return profile.subscriptions.some((channel) => channel.id === channelId)\n}\n</script>\n\n<style scoped src=\"./FtSubscribeButton.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtTimestampCatcher.vue",
    "content": "<template>\n  <!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->\n  <p\n    v-safer-html=\"displayText\"\n    dir=\"auto\"\n    @click=\"catchTimestampClick\"\n  />\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { vSaferHtml } from '../directives/vSaferHtml.js'\n\nconst props = defineProps({\n  inputHtml: {\n    type: String,\n    default: ''\n  },\n  linkTabIndex: {\n    type: String,\n    default: '0'\n  },\n})\n\nconst router = useRouter()\nconst videoId = router.currentRoute.value.params.id\n\n/** @type {import('vue').ComputedRef<string>} */\nconst displayText = computed(() => props.inputHtml.replaceAll(/(?:(\\d+):)?(\\d+):(\\d+)/g, (timestamp, hours, minutes, seconds) => {\n  let time = 60 * Number(minutes) + Number(seconds)\n\n  if (hours) {\n    time += 3600 * Number(hours)\n  }\n\n  const url = router.resolve({\n    path: `/watch/${videoId}`,\n    query: {\n      timestamp: time\n    }\n  }).href\n\n  // Adding the URL lets the user open the video in a new window at this timestamp\n  return `<a tabindex=\"${props.linkTabIndex}\" href=\"${url}\" data-time=\"${time}\">${timestamp}</a>`\n}))\n\nconst emit = defineEmits(['timestamp-event'])\n\n/**\n * @param {PointerEvent} event\n */\nfunction catchTimestampClick(event) {\n  /** @type {HTMLAnchorElement} */\n  const target = event.target\n\n  if (target.tagName === 'A' && target.dataset.time) {\n    const timeSeconds = parseInt(target.dataset.time)\n\n    if (!isNaN(timeSeconds)) {\n      event.preventDefault()\n\n      emit('timestamp-event', timeSeconds)\n      window.scrollTo(0, 0)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/FtToast/FtToast.css",
    "content": ".toast-holder {\n  position: fixed;\n  inset-inline-start: 50vw;\n  transform: translate(calc(-50% * var(--horizontal-directionality-coefficient)), 0);\n  inset-block-end: 50px;\n\n  /* Higher than any prompt */\n  z-index: 300;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  pointer-events: none;\n}\n\n.toast {\n  padding: 10px;\n  margin: 5px;\n  text-align: center;\n  overflow-y: auto;\n  background-color: rgb(0 0 0 / 70%);\n  color: #fff;\n  opacity: 0;\n  border-radius: 20px;\n  cursor: pointer;\n}\n\n.message {\n  margin: auto;\n}\n\n.open {\n  pointer-events: auto;\n  visibility: visible;\n  opacity: 1;\n  transition: visibility 0s linear 0s, opacity 300ms;\n}\n\n.closed {\n  visibility: hidden;\n  pointer-events: none;\n  opacity: 0;\n  transition: visibility 0s linear 300ms, opacity 300ms;\n}\n"
  },
  {
    "path": "src/renderer/components/FtToast/FtToast.vue",
    "content": "<template>\n  <div class=\"toast-holder\">\n    <div\n      v-for=\"toast in toasts\"\n      :key=\"toast.id\"\n      class=\"toast\"\n      :class=\"{ closed: !toast.isOpen, open: toast.isOpen }\"\n      tabindex=\"0\"\n      role=\"status\"\n      @click=\"performAction(toast)\"\n      @keydown.enter.prevent=\"performAction(toast)\"\n      @keydown.space.prevent=\"performAction(toast)\"\n    >\n      <p class=\"message\">\n        {{ toast.message }}\n      </p>\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { nextTick, onBeforeUnmount, onMounted, reactive } from 'vue'\nimport { ToastEventBus } from '../../helpers/utils'\n\nlet idCounter = 0\n\n/**\n * @typedef Toast\n * @property {string | (({elapsedMs: number, remainingMs: number}) => string)} message\n * @property {Function | null} action\n * @property {boolean} isOpen\n * @property {NodeJS.Timeout | number} timeout\n * @property {NodeJS.Timeout | number} interval\n * @property {number} id\n */\n\n/** @type {import('vue').Reactive<Toast[]>} */\nconst toasts = reactive([])\n\n/**\n * @param {CustomEvent<{ message: string | (({elapsedMs: number, remainingMs: number}) => string), time: number | null, action: Function | null, abortSignal: AbortSignal | null }>} event\n */\nfunction open({ detail: { message, time, action, abortSignal } }) {\n  const id = idCounter++\n\n  /** @type {Toast} */\n  const toast = {\n    id,\n    message,\n    action,\n    isOpen: false,\n    timeout: 0,\n    interval: 0\n  }\n  time ||= 3000\n  let elapsed = 0\n  const updateDelay = 1000\n\n  if (typeof message === 'function') {\n    toast.message = message({ elapsedMs: elapsed, remainingMs: time - elapsed })\n    toast.interval = setInterval(() => {\n      elapsed += updateDelay\n      // Skip last update\n      if (elapsed >= time) { return }\n\n      // We need to locate the object in the array so we get the reactive proxy,\n      // as modifying the original object won't trigger reactive effects such as updating the DOM\n      const toast = toasts.find(t => t.id === id)\n\n      if (toast) {\n        toast.message = message({ elapsedMs: elapsed, remainingMs: time - elapsed })\n      }\n    }, updateDelay)\n  }\n\n  toast.timeout = setTimeout(close, time, toast)\n  if (abortSignal != null) {\n    abortSignal.addEventListener('abort', () => {\n      close(toast)\n    })\n  }\n\n  nextTick(() => {\n    // We need to locate the object in the array so we get the reactive proxy,\n    // as modifying the original object won't trigger reactive effects such as updating the DOM\n    const toast = toasts.find(t => t.id === id)\n\n    if (toast) {\n      toast.isOpen = true\n    }\n  })\n\n  if (toasts.length > 4) {\n    remove(toasts[0])\n  }\n  toasts.push(toast)\n}\n\n/**\n * @param {Toast} toast\n */\nfunction close(toast) {\n  setTimeout(remove, 300, toast)\n\n  toast.isOpen = false\n}\n\n/**\n * @param {Toast} toast\n */\nfunction performAction(toast) {\n  toast.action?.()\n  remove(toast)\n}\n\n/**\n * @param {Toast} toast\n */\nfunction remove(toast) {\n  const index = toasts.indexOf(toast)\n\n  if (index !== -1) {\n    toasts.splice(index, 1)\n    cleanup(toast)\n  }\n}\n\n/**\n * @param {Toast} toast\n */\nfunction cleanup(toast) {\n  // assumes `toasts.indexOf(toast) !== -1`\n  clearTimeout(toast.timeout)\n  clearInterval(toast.interval)\n}\n\nonMounted(() => {\n  ToastEventBus.addEventListener('toast-open', open)\n})\n\nonBeforeUnmount(() => {\n  ToastEventBus.removeEventListener('toast-open', open)\n  toasts.forEach(cleanup)\n})\n</script>\n\n<style scoped src=\"./FtToast.css\" />\n"
  },
  {
    "path": "src/renderer/components/FtToggleSwitch/FtToggleSwitch.scss",
    "content": "/* Thanks to Guus Lieben for the Material Design Switch */\n\n.switch-ctn {\n  margin-block: 20px;\n  margin-inline: 16px;\n  position: relative;\n\n  &.compact {\n    margin: 0;\n  }\n}\n\n.switch-input {\n  appearance: none;\n  block-size: 20px;\n  inset-inline-start: -3px;\n  position: absolute;\n  inset-block-start: calc(50% - 3px);\n  transform: translate(0, -50%);\n  inline-size: 34px;\n}\n\n.switch-label {\n  cursor: pointer;\n  display: inline-block;\n  font-weight: 500;\n  padding-block: 12px;\n  padding-inline: 44px 0;\n  position: relative;\n  text-align: start;\n\n  &::before,\n  &::after {\n    content: '';\n    margin: 0;\n    outline: 0;\n    position: absolute;\n    inset-block-start: 50%;\n    transform: translate(0, -50%);\n    transition: all 0.3s ease;\n  }\n\n  &::before {\n    background-color: #9e9e9e;\n    border-radius: 8px;\n    block-size: 14px;\n    inset-inline-start: 1px;\n    inline-size: 34px;\n\n    .switch-input:checked + & {\n      background-color: var(--accent-color-light);\n    }\n\n    .switch-input:disabled + & {\n      background-color: #9e9e9e;\n    }\n  }\n\n  &::after {\n    background-color: #fafafa;\n    border-radius: 50%;\n    box-shadow: 0 3px 1px -2px rgb(0 0 0 / 14%), 0 2px 2px 0 rgb(0 0 0 / 9.8%), 0 1px 5px 0 rgb(0 0 0 / 8.4%);\n    block-size: 20px;\n    inset-inline-start: 0;\n    inline-size: 20px;\n\n    .switch-input:checked + & {\n      background-color: var(--accent-color);\n      transform: translate(calc(80% * var(--horizontal-directionality-coefficient)), -50%);\n    }\n\n    .switch-input:disabled + & {\n      background-color: #bdbdbd;\n    }\n  }\n\n  @media (width <= 680px) {\n    max-inline-size: 250px;\n  }\n}\n\n.containsTooltip .switch-label-text {\n  margin-inline-end: 5px;\n}\n\n.disabled {\n  .switch-label {\n    cursor: not-allowed;\n  }\n\n  .switch-label-text {\n    opacity: 0.4;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/FtToggleSwitch/FtToggleSwitch.vue",
    "content": "<template>\n  <div\n    class=\"switch-ctn\"\n    :class=\"{\n      compact,\n      disabled: disabled,\n      containsTooltip: tooltip.length > 0\n    }\"\n  >\n    <input\n      :id=\"id\"\n      v-model=\"currentValue\"\n      type=\"checkbox\"\n      name=\"set-name\"\n      class=\"switch-input\"\n      :checked=\"currentValue\"\n      :disabled=\"disabled\"\n      @change=\"change\"\n    >\n    <label\n      :for=\"id\"\n      class=\"switch-label\"\n    >\n      <span class=\"switch-label-text\">\n        {{ label }}\n      </span>\n      <FtTooltip\n        v-if=\"tooltip !== ''\"\n        class=\"selectTooltip\"\n        :position=\"tooltipPosition\"\n        :tooltip=\"tooltip\"\n        :allow-newlines=\"tooltipAllowNewlines\"\n      />\n    </label>\n  </div>\n</template>\n\n<script setup>\nimport { ref, useId, watch } from 'vue'\n\nimport FtTooltip from '../FtTooltip/FtTooltip.vue'\n\nconst props = defineProps({\n  label: {\n    type: String,\n    required: true\n  },\n  defaultValue: {\n    type: Boolean,\n    default: false\n  },\n  compact: {\n    type: Boolean,\n    default: false\n  },\n  disabled: {\n    type: Boolean,\n    default: false\n  },\n  tooltip: {\n    type: String,\n    default: ''\n  },\n  tooltipPosition: {\n    type: String,\n    default: 'bottom-left'\n  },\n  tooltipAllowNewlines: {\n    type: Boolean,\n    default: false,\n  },\n})\n\nconst emit = defineEmits(['change'])\n\nconst id = useId()\n\nconst currentValue = ref(props.defaultValue)\n\nwatch(() => props.defaultValue, (value) => {\n  currentValue.value = value\n})\n\nfunction change() {\n  emit('change', currentValue.value)\n}\n</script>\n\n<style scoped lang=\"scss\" src=\"./FtToggleSwitch.scss\" />\n"
  },
  {
    "path": "src/renderer/components/FtTooltip/FtTooltip.css",
    "content": ".button {\n  background-color: transparent;\n  border-style: none;\n  color: var(--primary-text-color);\n  cursor: pointer;\n  font-size: 1rem;\n  padding: 0;\n}\n\n.text {\n  background-color: color-mix(in srgb, var(--primary-text-color) 80%, transparent);\n  border-radius: 20px;\n  color: var(--card-bg-color);\n  font-size: 1rem;\n  line-height: 120%;\n  margin: 0;\n  max-inline-size: max-content;\n  min-inline-size: 15em;\n  opacity: 0;\n  padding-block: 10px;\n  padding-inline: 8px;\n  pointer-events: none;\n  position: absolute;\n  text-align: center;\n  transition-duration: 275ms;\n  transition-property: opacity, transform, visibility;\n  visibility: hidden;\n  z-index: 2;\n}\n\n.text.bottom {\n  margin-block-start: 1em;\n  inset-block-start: 100%;\n  inset-inline-start: 50%;\n  transform: translate(calc(-50% * var(--horizontal-directionality-coefficient)), -1em);\n}\n\n.text.bottom-left {\n  margin-block-start: 1em;\n  inset-block-start: 100%;\n  inset-inline-start: -100px;\n  transform: translate(calc(-50% * var(--horizontal-directionality-coefficient)), -1em);\n}\n\n.text.left {\n  margin-inline-end: 1em;\n  inset-inline-end: 100%;\n  inset-block-start: 50%;\n  transform: translate(calc(1em * var(--horizontal-directionality-coefficient)), -50%);\n}\n\n.text.right {\n  inset-inline-start: 100%;\n  margin-inline-start: 1em;\n  inset-block-start: 50%;\n  transform: translate(calc(-1em * var(--horizontal-directionality-coefficient)), -50%);\n}\n\n.text.top {\n  inset-block-end: 100%;\n  inset-inline-start: 50%;\n  margin-block-end: 1em;\n  transform: translate(calc(-50% * var(--horizontal-directionality-coefficient)), 1em);\n}\n\n.button:focus + .text,\n.button:hover + .text {\n  opacity: 1;\n  visibility: visible;\n}\n\n.button:focus + .text.bottom,\n.button:hover + .text.bottom,\n.button:hover + .text.bottom-left,\n.button:focus + .text.top,\n.button:hover + .text.top {\n  transform: translate(calc(-50% * var(--horizontal-directionality-coefficient)), 0);\n}\n\n.button:focus + .text.left,\n.button:hover + .text.left,\n.button:focus + .text.right,\n.button:hover + .text.right {\n  transform: translate(0, -50%);\n}\n\n.text.allowNewlines {\n  white-space: pre-wrap;\n  text-align: start;\n  inline-size: 55vw;\n}\n\n.tooltip {\n  display: inline-block;\n  position: relative;\n}\n"
  },
  {
    "path": "src/renderer/components/FtTooltip/FtTooltip.vue",
    "content": "<template>\n  <div class=\"tooltip\">\n    <button\n      :aria-labelledby=\"id\"\n      class=\"button\"\n      type=\"button\"\n    >\n      <FontAwesomeIcon :icon=\"['fas', 'question-circle']\" />\n    </button>\n    <p\n      :id=\"id\"\n      class=\"text\"\n      :class=\"{\n        [position]: true,\n        allowNewlines,\n      }\"\n      role=\"tooltip\"\n    >\n      {{ tooltip }}\n    </p>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { useId } from 'vue'\n\ndefineProps({\n  position: {\n    type: String,\n    default: 'bottom',\n    validator: (value) => value === 'bottom' || value === 'left' || value === 'right' || value === 'top' || value === 'bottom-left'\n  },\n  tooltip: {\n    type: String,\n    required: true\n  },\n  allowNewlines: {\n    type: Boolean,\n    default: false,\n  },\n})\n\nconst id = useId()\n</script>\n\n<style scoped src=\"./FtTooltip.css\" />\n"
  },
  {
    "path": "src/renderer/components/GeneralSettings/GeneralSettings.css",
    "content": ".select {\n  min-inline-size: 240px;\n  inline-size: auto;\n}\n\n.switchGrid {\n  gap: 10px;\n  margin-block-end: 12px;\n}\n"
  },
  {
    "path": "src/renderer/components/GeneralSettings/GeneralSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"t('Settings.General Settings.General Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.General Settings.Check for Updates')\"\n          :default-value=\"checkForUpdates\"\n          :compact=\"true\"\n          @change=\"updateCheckForUpdates\"\n        />\n        <FtToggleSwitch\n          v-if=\"SUPPORTS_LOCAL_API\"\n          :label=\"t('Settings.General Settings.Fallback to Non-Preferred Backend on Failure')\"\n          :default-value=\"backendFallback\"\n          :compact=\"true\"\n          :tooltip=\"t('Tooltips.General Settings.Fallback to Non-Preferred Backend on Failure')\"\n          @change=\"updateBackendFallback\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.General Settings.Auto Load Next Page.Label')\"\n          :default-value=\"generalAutoLoadMorePaginatedItemsEnabled\"\n          :compact=\"true\"\n          :tooltip=\"t('Settings.General Settings.Auto Load Next Page.Tooltip')\"\n          @change=\"updateGeneralAutoLoadMorePaginatedItemsEnabled\"\n        />\n        <FtToggleSwitch\n          v-if=\"!IS_MAC && USING_ELECTRON\"\n          :label=\"t('Settings.General Settings.Minimize to system tray')\"\n          :default-value=\"hideToTrayOnMinimize\"\n          :compact=\"true\"\n          @change=\"updateHideToTrayOnMinimize\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.General Settings.Check for Latest Blog Posts')\"\n          :default-value=\"checkForBlogPosts\"\n          :compact=\"true\"\n          @change=\"updateCheckForBlogPosts\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.General Settings.Enable Search Suggestions')\"\n          :default-value=\"enableSearchSuggestions\"\n          :compact=\"true\"\n          @change=\"updateEnableSearchSuggestions\"\n        />\n        <FtToggleSwitch\n          v-if=\"USING_ELECTRON\"\n          :label=\"t('Settings.General Settings.Open Deep Links In New Window')\"\n          :default-value=\"openDeepLinksInNewWindow\"\n          :compact=\"true\"\n          :tooltip=\"t('Tooltips.General Settings.Open Deep Links In New Window')\"\n          @change=\"updateOpenDeepLinksInNewWindow\"\n        />\n      </div>\n    </div>\n    <div class=\"switchGrid\">\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.Preferred API Backend.Preferred API Backend')\"\n        :value=\"backendPreference\"\n        :select-names=\"backendNames\"\n        :select-values=\"BACKEND_VALUES\"\n        :tooltip=\"t('Tooltips.General Settings.Preferred API Backend')\"\n        :icon=\"['fas', 'server']\"\n        @change=\"updateBackendPreference\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.Default Landing Page')\"\n        :value=\"landingPage\"\n        :select-names=\"defaultPageNames\"\n        :select-values=\"defaultPageValues\"\n        :icon=\"['fas', 'location-dot']\"\n        @change=\"updateLandingPage\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.Video View Type.Video View Type')\"\n        :value=\"listType\"\n        :select-names=\"viewTypeNames\"\n        :select-values=\"VIEW_TYPE_VALUES\"\n        :icon=\"listType === 'grid' ? ['fas', 'grip'] : ['fas', 'list']\"\n        @change=\"updateListType\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.Thumbnail Preference.Thumbnail Preference')\"\n        :value=\"thumbnailPreference\"\n        :select-names=\"thumbnailTypeNames\"\n        :select-values=\"THUMBNAIL_TYPE_VALUES\"\n        :tooltip=\"t('Tooltips.General Settings.Thumbnail Preference')\"\n        :icon=\"['fas', 'images']\"\n        @change=\"handleThumbnailPreferenceChange\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.Locale Preference')\"\n        :value=\"currentLocale\"\n        :select-names=\"localeNames\"\n        :select-values=\"LOCALE_VALUES\"\n        :icon=\"['fas', 'language']\"\n        :is-locale-selector=\"true\"\n        @change=\"updateCurrentLocale\"\n      />\n      <FtSelect\n        v-if=\"regionDataLoaded\"\n        :placeholder=\"t('Settings.General Settings.Region for Trending')\"\n        :value=\"region\"\n        :select-names=\"regionNames\"\n        :select-values=\"regionValues\"\n        :icon=\"['fas', 'globe']\"\n        :tooltip=\"t('Tooltips.General Settings.Region for Trending')\"\n        @change=\"updateRegion\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.General Settings.External Link Handling.External Link Handling')\"\n        :value=\"externalLinkHandling\"\n        :select-names=\"externalLinkHandlingNames\"\n        :select-values=\"EXTERNAL_LINK_HANDLING_VALUES\"\n        :icon=\"['fas', 'external-link-alt']\"\n        :tooltip=\"t('Tooltips.General Settings.External Link Handling')\"\n        @change=\"updateExternalLinkHandling\"\n      />\n    </div>\n    <div\n      v-if=\"backendPreference === 'invidious' || backendFallback\"\n    >\n      <FtFlexBox class=\"settingsFlexStart460px\">\n        <FtInput\n          :placeholder=\"t('Settings.General Settings.Current Invidious Instance')\"\n          :show-action-button=\"false\"\n          :show-label=\"true\"\n          :value=\"currentInvidiousInstance\"\n          :data-list=\"invidiousInstancesList\"\n          :tooltip=\"t('Tooltips.General Settings.Invidious Instance')\"\n          @input=\"handleInvidiousInstanceInput\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <div>\n          <a\n            href=\"https://api.invidious.io\"\n          >\n            {{ t('Settings.General Settings.View all Invidious instance information') }}\n          </a>\n        </div>\n      </FtFlexBox>\n      <p\n        v-if=\"defaultInvidiousInstance !== ''\"\n        class=\"center\"\n      >\n        {{ t('Settings.General Settings.The currently set default instance is {instance}', { instance: defaultInvidiousInstance }) }}\n      </p>\n      <template v-else>\n        <p class=\"center\">\n          {{ t('Settings.General Settings.No default instance has been set') }}\n        </p>\n        <p class=\"center\">\n          {{ t('Settings.General Settings.Current instance will be randomized on startup') }}\n        </p>\n      </template>\n      <FtFlexBox>\n        <FtButton\n          :label=\"t('Settings.General Settings.Set Current Instance as Default')\"\n          @click=\"handleSetDefaultInstanceClick\"\n        />\n        <FtButton\n          :label=\"t('Settings.General Settings.Clear Default Instance')\"\n          @click=\"handleClearDefaultInstanceClick\"\n        />\n      </FtFlexBox>\n    </div>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, onBeforeUnmount } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRouter } from 'vue-router'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtButton from '../FtButton/FtButton.vue'\n\nimport store from '../../store/index'\n\nimport allLocales from '../../../../static/locales/activeLocales.json'\nimport { debounce, randomArrayItem, showToast } from '../../helpers/utils'\nimport { translateWindowTitle } from '../../helpers/strings'\n\nconst USING_ELECTRON = !!process.env.IS_ELECTRON\nconst SUPPORTS_LOCAL_API = !!process.env.SUPPORTS_LOCAL_API\nconst IS_MAC = process.platform === 'darwin'\n\nconst { t } = useI18n()\nconst router = useRouter()\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst checkForUpdates = computed(() => store.getters.getCheckForUpdates)\n\n/**\n * @param {boolean} value\n */\nfunction updateCheckForUpdates(value) {\n  store.dispatch('updateCheckForUpdates', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/**\n * @param {boolean} value\n */\nfunction updateBackendFallback(value) {\n  store.dispatch('updateBackendFallback', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst generalAutoLoadMorePaginatedItemsEnabled = computed(() => {\n  return store.getters.getGeneralAutoLoadMorePaginatedItemsEnabled\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateGeneralAutoLoadMorePaginatedItemsEnabled(value) {\n  store.dispatch('updateGeneralAutoLoadMorePaginatedItemsEnabled', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideToTrayOnMinimize = computed(() => store.getters.getHideToTrayOnMinimize)\n\n/**\n * @param {boolean} value\n */\nfunction updateHideToTrayOnMinimize(value) {\n  store.dispatch('updateHideToTrayOnMinimize', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst checkForBlogPosts = computed(() => store.getters.getCheckForBlogPosts)\n\n/**\n * @param {boolean} value\n */\nfunction updateCheckForBlogPosts(value) {\n  store.dispatch('updateCheckForBlogPosts', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst enableSearchSuggestions = computed(() => store.getters.getEnableSearchSuggestions)\n\n/**\n * @param {boolean} value\n */\nfunction updateEnableSearchSuggestions(value) {\n  store.dispatch('updateEnableSearchSuggestions', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst openDeepLinksInNewWindow = computed(() => store.getters.getOpenDeepLinksInNewWindow)\n\n/**\n * @param {boolean} value\n */\nfunction updateOpenDeepLinksInNewWindow(value) {\n  store.dispatch('updateOpenDeepLinksInNewWindow', value)\n}\n\nconst BACKEND_VALUES = process.env.SUPPORTS_LOCAL_API\n  ? ['invidious', 'local']\n  : ['invidious']\n\nconst backendNames = computed(() => {\n  if (process.env.SUPPORTS_LOCAL_API) {\n    return [\n      t('Settings.General Settings.Preferred API Backend.Invidious API'),\n      t('Settings.General Settings.Preferred API Backend.Local API')\n    ]\n  } else {\n    return [\n      t('Settings.General Settings.Preferred API Backend.Invidious API')\n    ]\n  }\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/**\n * @param {'local' | 'invidious'} value\n */\nfunction updateBackendPreference(value) {\n  store.dispatch('updateBackendPreference', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePlaylists = computed(() => store.getters.getHidePlaylists)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePopularVideos = computed(() => store.getters.getHidePopularVideos)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideTrendingVideos = computed(() => store.getters.getHideTrendingVideos)\n\nconst INCLUDED_DEFAULT_PAGE_NAMES = [\n  'subscriptions',\n  'subscribedChannels',\n  'popular',\n  'userPlaylists',\n  'history',\n  'settings',\n  ...(process.env.SUPPORTS_LOCAL_API ? ['trending'] : [])\n]\n\nconst defaultPages = computed(() => {\n  let includedPageNames = INCLUDED_DEFAULT_PAGE_NAMES\n\n  if (hideTrendingVideos.value || !backendFallback.value || backendPreference.value !== 'local') {\n    includedPageNames = includedPageNames.filter((pageName) => pageName !== 'trending')\n  }\n\n  if (hidePlaylists.value) {\n    includedPageNames = includedPageNames.filter((pageName) => pageName !== 'userPlaylists')\n  }\n\n  if (!(!hidePopularVideos.value && (backendFallback.value || backendPreference.value === 'invidious'))) {\n    includedPageNames = includedPageNames.filter((pageName) => pageName !== 'popular')\n  }\n\n  return router.getRoutes().filter((route) => includedPageNames.includes(route.name))\n})\n\nconst defaultPageNames = computed(() => defaultPages.value.map((route) => translateWindowTitle(route.meta.title)))\n\nconst defaultPageValues = computed(() => {\n  // avoid Vue parsing issues by excluding '/' from path values\n  return defaultPages.value.map((route) => route.path.slice(1))\n})\n\n/** @type {import('vue').ComputedRef<'subscriptions' | 'subscribedChannels' | 'popular' | 'userPlaylists' | 'history' | 'settings' | 'trending'>} */\nconst landingPage = computed(() => store.getters.getLandingPage)\n\n/**\n * @param {'subscriptions' | 'subscribedChannels' | 'popular' | 'userPlaylists' | 'history' | 'settings' | 'trending'} value\n */\nfunction updateLandingPage(value) {\n  store.dispatch('updateLandingPage', value)\n}\n\nconst VIEW_TYPE_VALUES = ['grid', 'list']\n\nconst viewTypeNames = computed(() => [\n  t('Settings.General Settings.Video View Type.Grid'),\n  t('Settings.General Settings.Video View Type.List')\n])\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => store.getters.getListType)\n\n/**\n * @param {'grid' | 'list'} value\n */\nfunction updateListType(value) {\n  store.dispatch('updateListType', value)\n}\n\nconst THUMBNAIL_TYPE_VALUES = ['', 'start', 'middle', 'end', 'hidden', 'blur']\n\nconst thumbnailTypeNames = computed(() => [\n  t('Settings.General Settings.Thumbnail Preference.Default'),\n  t('Settings.General Settings.Thumbnail Preference.Beginning'),\n  t('Settings.General Settings.Thumbnail Preference.Middle'),\n  t('Settings.General Settings.Thumbnail Preference.End'),\n  t('Settings.General Settings.Thumbnail Preference.Hidden'),\n  t('Settings.General Settings.Thumbnail Preference.Blur')\n])\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst blurThumbnails = computed(() => store.getters.getBlurThumbnails)\n\n/** @type {import('vue').ComputedRef<'' | 'start' | 'middle' | 'end' | 'hidden' | 'blur'>} */\nconst thumbnailPreference = computed(() => {\n  return blurThumbnails.value ? 'blur' : store.getters.getThumbnailPreference\n})\n\n/**\n * @param {'' | 'start' | 'middle' | 'end' | 'hidden' | 'blur'} value\n */\nfunction handleThumbnailPreferenceChange(value) {\n  store.dispatch('updateBlurThumbnails', value === 'blur')\n  store.dispatch('updateThumbnailPreference', value)\n}\n\nconst LOCALE_VALUES = ['system', ...allLocales]\n\nconst localeNames = computed(() => [\n  t('Settings.General Settings.System Default'),\n  ...process.env.LOCALE_NAMES\n])\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentLocale = computed(() => store.getters.getCurrentLocale)\n\n/**\n * @param {string} value\n */\nfunction updateCurrentLocale(value) {\n  store.dispatch('updateCurrentLocale', value)\n}\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst regionNames = computed(() => store.getters.getRegionNames)\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst regionValues = computed(() => store.getters.getRegionValues)\n\nconst regionDataLoaded = computed(() => regionValues.value.length > 0)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst region = computed(() => store.getters.getRegion)\n\n/**\n * @param {string} value\n */\nfunction updateRegion(value) {\n  store.dispatch('updateRegion', value)\n}\n\nconst EXTERNAL_LINK_HANDLING_VALUES = ['', 'openLinkAfterPrompt', 'doNothing']\n\nconst externalLinkHandlingNames = computed(() => [\n  t('Settings.General Settings.External Link Handling.Open Link'),\n  t('Settings.General Settings.External Link Handling.Ask Before Opening Link'),\n  t('Settings.General Settings.External Link Handling.No Action')\n])\n\n/** @type {import('vue').ComputedRef<'' | 'openLinkAfterPrompt' | 'doNothing'>} */\nconst externalLinkHandling = computed(() => store.getters.getExternalLinkHandling)\n\n/**\n * @param {'' | 'openLinkAfterPrompt' | 'doNothing'} value\n */\nfunction updateExternalLinkHandling(value) {\n  store.dispatch('updateExternalLinkHandling', value)\n}\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst invidiousInstancesList = computed(() => store.getters.getInvidiousInstancesList)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstance = computed(() => store.getters.getCurrentInvidiousInstance)\n\nonBeforeUnmount(() => {\n  if (currentInvidiousInstance.value === '') {\n    // FIXME: If we call an action from here, there's no guarantee it will finish\n    // before the component is destroyed, which could bring up some problems\n    // Since I can't see any way to await it (because lifecycle hooks must be\n    // synchronous), unfortunately, we have to copy/paste the logic\n    // from the `setRandomCurrentInvidiousInstance` action onto here\n    // Fix when we migrate to Pinia\n    const instanceList = invidiousInstancesList.value\n    store.commit('setCurrentInvidiousInstance', randomArrayItem(instanceList))\n  }\n})\n\nconst setCurrentInvidiousInstanceBounce = debounce((/** @type {string} */instance) => {\n  store.commit('setCurrentInvidiousInstance', instance)\n}, 500)\n\n/**\n * @param {string} input\n */\nfunction handleInvidiousInstanceInput(input) {\n  let instance = input\n  // If NOT something like https:// (1-2 slashes), remove trailing slash\n  if (!/^https?:\\/{1,2}$/.test(input)) {\n    instance = input.replace(/\\/$/, '')\n  }\n\n  setCurrentInvidiousInstanceBounce(instance)\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst defaultInvidiousInstance = computed(() => store.getters.getDefaultInvidiousInstance)\n\nfunction handleSetDefaultInstanceClick() {\n  const instance = currentInvidiousInstance.value\n  store.dispatch('updateDefaultInvidiousInstance', instance)\n\n  const message = t('Default Invidious instance has been set to {instance}', { instance })\n  showToast(message)\n}\n\nfunction handleClearDefaultInstanceClick() {\n  store.dispatch('updateDefaultInvidiousInstance', '')\n  showToast(t('Default Invidious instance has been cleared'))\n}\n</script>\n\n<style scoped src=\"./GeneralSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/ParentalControlSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Parental Control Settings.Parental Control Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Parental Control Settings.Hide Unsubscribe Button')\"\n          compact\n          :default-value=\"hideUnsubscribeButton\"\n          @change=\"updateHideUnsubscribeButton\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Parental Control Settings.Show Family Friendly Only')\"\n          compact\n          :default-value=\"showFamilyFriendlyOnly\"\n          @change=\"updateShowFamilyFriendlyOnly\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Parental Control Settings.Hide Search Bar')\"\n          compact\n          :default-value=\"hideSearchBar\"\n          @change=\"updateHideSearchBar\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Parental Control Settings.Hide Uploader on Watch page')\"\n          compact\n          :default-value=\"hideUploader\"\n          @change=\"updateHideUploader\"\n        />\n      </div>\n    </div>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'\nimport FtToggleSwitch from './FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../store/index'\n\nconst hideSearchBar = computed(() => {\n  return store.getters.getHideSearchBar\n})\n\nconst hideUnsubscribeButton = computed(() => {\n  return store.getters.getHideUnsubscribeButton\n})\n\nconst hideUploader = computed(() => {\n  return store.getters.getHideUploader\n})\n\nconst showFamilyFriendlyOnly = computed(() => {\n  return store.getters.getShowFamilyFriendlyOnly\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateHideSearchBar(value) {\n  store.dispatch('updateHideSearchBar', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateHideUnsubscribeButton(value) {\n  store.dispatch('updateHideUnsubscribeButton', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateHideUploader(value) {\n  store.dispatch('updateHideUploader', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateShowFamilyFriendlyOnly(value) {\n  store.dispatch('updateShowFamilyFriendlyOnly', value)\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/PasswordDialog/PasswordDialog.css",
    "content": ".card {\n  inline-size: 85%;\n  margin: auto;\n  box-sizing: border-box;\n}\n\n.passwordInput {\n  inline-size: 100%;\n}\n"
  },
  {
    "path": "src/renderer/components/PasswordDialog/PasswordDialog.vue",
    "content": "<template>\n  <FtCard\n    class=\"card\"\n  >\n    <h3>{{ $t(\"Settings.Password Dialog.Enter Password To Unlock\") }}</h3>\n\n    <FtInput\n      ref=\"password\"\n      :placeholder=\"$t('Settings.Password Dialog.Password')\"\n      :show-action-button=\"false\"\n      input-type=\"password\"\n      class=\"passwordInput\"\n      @input=\"handlePasswordInput\"\n    />\n  </FtCard>\n</template>\n\n<script setup>\nimport { computed, onMounted, useTemplateRef } from 'vue'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtInput from '../FtInput/FtInput.vue'\n\nimport store from '../../store/index'\n\nconst emit = defineEmits(['unlocked'])\n\nconst password = useTemplateRef('password')\n\nonMounted(() => {\n  password.value.focus()\n})\n\nconst settingsPassword = computed(() => {\n  return store.getters.getSettingsPassword\n})\n\nfunction handlePasswordInput(input) {\n  if (input === settingsPassword.value) {\n    emit('unlocked')\n  }\n}\n</script>\n\n<style scoped src=\"./PasswordDialog.css\" />\n"
  },
  {
    "path": "src/renderer/components/PasswordSettings/PasswordSettings.css",
    "content": ".centerButton {\n  align-self: center;\n}\n"
  },
  {
    "path": "src/renderer/components/PasswordSettings/PasswordSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Password Settings.Password Settings')\"\n  >\n    <FtFlexBox\n      v-if=\"hasStoredPassword\"\n      class=\"settingsFlexStart460px\"\n    >\n      <FtButton\n        :label=\"$t('Settings.Password Settings.Remove Password')\"\n        @click=\"handleRemovePassword\"\n      />\n    </FtFlexBox>\n    <FtFlexBox\n      v-else\n      class=\"settingsFlexStart460px\"\n    >\n      <FtInput\n        :placeholder=\"$t('Settings.Password Settings.Set Password To Prevent Access')\"\n        :show-action-button=\"false\"\n        show-label\n        input-type=\"password\"\n        :value=\"password\"\n        @input=\"e => password = e\"\n        @keydown.enter=\"handleSetPassword\"\n      />\n      <FtButton\n        class=\"centerButton\"\n        :label=\"$t('Settings.Password Settings.Set Password')\"\n        @click=\"handleSetPassword\"\n      />\n    </FtFlexBox>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtButton from '../FtButton/FtButton.vue'\n\nimport store from '../../store/index'\n\nconst settingsPassword = computed(() => {\n  return store.getters.getSettingsPassword\n})\n\nconst hasStoredPassword = computed(() => {\n  return settingsPassword.value !== ''\n})\n\nconst password = ref('')\n\nfunction handleSetPassword() {\n  store.dispatch('updateSettingsPassword', password.value)\n  password.value = ''\n}\n\nfunction handleRemovePassword() {\n  store.dispatch('updateSettingsPassword', '')\n  password.value = ''\n}\n</script>\n\n<style scoped src=\"./PasswordSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/PlayerSettings/PlayerSettings.css",
    "content": ".screenshotFolderContainer {\n  align-items: center;\n  column-gap: 1rem;\n  margin-block: 0;\n  margin-inline: auto;\n  inline-size: 95%;\n}\n\n.screenshotFolderLabel,\n.screenshotFolderButton,\n.screenshotFilenamePatternTitle {\n  flex-grow: 0;\n}\n\n.screenshotFolderPath,\n.screenshotFilenamePatternInput,\n.screenshotFilenamePatternExample {\n  flex-grow: 1;\n  margin-block-start: 10px;\n}\n"
  },
  {
    "path": "src/renderer/components/PlayerSettings/PlayerSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"t('Settings.Player Settings.Player Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Proxy Videos Through Invidious')\"\n          :compact=\"true\"\n          :default-value=\"showProxyVideosAsDisabled ? false : proxyVideos\"\n          :disabled=\"showProxyVideosAsDisabled\"\n          :tooltip=\"t('Tooltips.Player Settings.Proxy Videos Through Invidious')\"\n          @change=\"updateProxyVideos\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Turn on Subtitles by Default')\"\n          :compact=\"true\"\n          :default-value=\"enableSubtitlesByDefault\"\n          @change=\"updateEnableSubtitlesByDefault\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Scroll Volume Over Video Player')\"\n          :compact=\"true\"\n          :disabled=\"videoSkipMouseScroll\"\n          :default-value=\"videoVolumeMouseScroll\"\n          @change=\"updateVideoVolumeMouseScroll\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Scroll Playback Rate Over Video Player')\"\n          :compact=\"true\"\n          :default-value=\"videoPlaybackRateMouseScroll\"\n          :tooltip=\"t('Tooltips.Player Settings.Scroll Playback Rate Over Video Player')\"\n          @change=\"updateVideoPlaybackRateMouseScroll\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Skip by Scrolling Over Video Player')\"\n          :compact=\"true\"\n          :disabled=\"videoVolumeMouseScroll\"\n          :default-value=\"videoSkipMouseScroll\"\n          :tooltip=\"t('Tooltips.Player Settings.Skip by Scrolling Over Video Player')\"\n          @change=\"updateVideoSkipMouseScroll\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Play Next Video')\"\n          :compact=\"true\"\n          :disabled=\"hideRecommendedVideos\"\n          :default-value=\"playNextVideo\"\n          @change=\"updatePlayNextVideo\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Autoplay Playlists')\"\n          :compact=\"true\"\n          :default-value=\"autoplayPlaylists\"\n          @change=\"updateAutoplayPlaylists\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Autoplay Videos')\"\n          :compact=\"true\"\n          :default-value=\"autoplayVideos\"\n          @change=\"updateAutoplayVideos\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Display Play Button In Video Player')\"\n          :compact=\"true\"\n          :default-value=\"displayVideoPlayButton\"\n          @change=\"updateDisplayVideoPlayButton\"\n        />\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Enter Fullscreen on Display Rotate')\"\n          :compact=\"true\"\n          :default-value=\"enterFullscreenOnDisplayRotate\"\n          @change=\"updateEnterFullscreenOnDisplayRotate\"\n        />\n      </div>\n    </div>\n    <FtFlexBox>\n      <FtSelect\n        :placeholder=\"t('Settings.Player Settings.Default Viewing Mode.Default Viewing Mode')\"\n        :value=\"defaultViewingMode\"\n        :select-names=\"viewingModeNames\"\n        :select-values=\"viewingModeValues\"\n        :icon=\"['fas', 'expand']\"\n        @change=\"updateDefaultViewingMode\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.Player Settings.Default Video Format.Default Video Format')\"\n        :value=\"defaultVideoFormat\"\n        :select-names=\"formatNames\"\n        :select-values=\"FORMAT_VALUES\"\n        :tooltip=\"t('Tooltips.Player Settings.Default Video Format')\"\n        :icon=\"['fas', 'file-video']\"\n        @change=\"updateDefaultVideoFormat\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.Player Settings.Default Quality.Default Quality')\"\n        :value=\"defaultQuality\"\n        :select-names=\"qualityNames\"\n        :select-values=\"QUALITY_VALUES\"\n        :icon=\"['fas', 'photo-film']\"\n        @change=\"updateDefaultQuality\"\n      />\n      <FtSelect\n        :placeholder=\"t('Settings.Player Settings.Video Playback Rate Interval')\"\n        :value=\"videoPlaybackRateIntervalString\"\n        :select-names=\"PLAYBACK_RATE_INTERVAL_VALUES\"\n        :select-values=\"PLAYBACK_RATE_INTERVAL_VALUES\"\n        :icon=\"['fas', 'gauge']\"\n        @change=\"updateVideoPlaybackRateInterval\"\n      />\n    </FtFlexBox>\n    <FtFlexBox>\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Next Video Interval')\"\n        :default-value=\"defaultInterval\"\n        :min-value=\"0\"\n        :max-value=\"60\"\n        :step=\"1\"\n        value-extension=\"s\"\n        @change=\"updateDefaultInterval\"\n      />\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Autoplay Interruption Timer')\"\n        :default-value=\"defaultAutoplayInterruptionIntervalHours\"\n        :min-value=\"1\"\n        :max-value=\"12\"\n        :step=\"1\"\n        value-extension=\"h\"\n        @change=\"updateDefaultAutoplayInterruptionIntervalHours\"\n      />\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Fast-Forward / Rewind Interval')\"\n        :default-value=\"defaultSkipInterval\"\n        :min-value=\"1\"\n        :max-value=\"70\"\n        :step=\"1\"\n        value-extension=\"s\"\n        @change=\"updateDefaultSkipInterval\"\n      />\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Default Volume')\"\n        :default-value=\"defaultVolume\"\n        :min-value=\"0\"\n        :max-value=\"100\"\n        :step=\"1\"\n        value-extension=\"%\"\n        @change=\"updateDefaultVolume\"\n      />\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Default Playback Rate')\"\n        :default-value=\"defaultPlayback\"\n        :min-value=\"videoPlaybackRateInterval\"\n        :max-value=\"maxVideoPlaybackRate\"\n        :step=\"videoPlaybackRateInterval\"\n        value-extension=\"x\"\n        @change=\"updateDefaultPlayback\"\n      />\n      <FtSlider\n        :label=\"t('Settings.Player Settings.Max Video Playback Rate')\"\n        :default-value=\"maxVideoPlaybackRate\"\n        :min-value=\"2\"\n        :max-value=\"10\"\n        :step=\"1\"\n        value-extension=\"x\"\n        @change=\"updateMaxVideoPlaybackRate\"\n      />\n    </FtFlexBox>\n    <br>\n    <FtFlexBox>\n      <FtToggleSwitch\n        :label=\"t('Settings.Player Settings.Screenshot.Enable')\"\n        :default-value=\"enableScreenshot\"\n        @change=\"updateEnableScreenshot\"\n      />\n    </FtFlexBox>\n    <div v-if=\"enableScreenshot\">\n      <FtFlexBox>\n        <FtSelect\n          :placeholder=\"t('Settings.Player Settings.Screenshot.Format Label')\"\n          :value=\"screenshotFormat\"\n          :select-names=\"SCREENSHOT_FORMAT_NAMES\"\n          :select-values=\"SCREENSHOT_FORMAT_VALUES\"\n          :icon=\"['fas', 'file-image']\"\n          @change=\"handleUpdateScreenshotFormat\"\n        />\n        <FtSlider\n          :label=\"t('Settings.Player Settings.Screenshot.Quality Label')\"\n          :default-value=\"screenshotQuality\"\n          :min-value=\"0\"\n          :max-value=\"100\"\n          :step=\"1\"\n          value-extension=\"%\"\n          :disabled=\"screenshotFormat === 'png'\"\n          @change=\"updateScreenshotQuality\"\n        />\n      </FtFlexBox>\n      <FtFlexBox v-if=\"USING_ELECTRON\">\n        <FtToggleSwitch\n          :label=\"t('Settings.Player Settings.Screenshot.Ask Path')\"\n          :default-value=\"screenshotAskPath\"\n          @change=\"updateScreenshotAskPath\"\n        />\n      </FtFlexBox>\n      <FtFlexBox\n        v-if=\"USING_ELECTRON && !screenshotAskPath\"\n        class=\"screenshotFolderContainer\"\n      >\n        <p class=\"screenshotFolderLabel\">\n          {{ t('Settings.Player Settings.Screenshot.Folder Label') }}\n        </p>\n        <FtInput\n          class=\"screenshotFolderPath\"\n          :placeholder=\"screenshotFolder\"\n          :show-action-button=\"false\"\n          :show-label=\"false\"\n          :disabled=\"true\"\n        />\n        <FtButton\n          :label=\"t('Settings.Player Settings.Screenshot.Folder Button')\"\n          class=\"screenshotFolderButton\"\n          @click=\"chooseScreenshotFolder\"\n        />\n      </FtFlexBox>\n      <FtFlexBox\n        class=\"screenshotFolderContainer\"\n      >\n        <p class=\"screenshotFilenamePatternTitle\">\n          {{ t('Settings.Player Settings.Screenshot.File Name Label') }}\n          <FtTooltip\n            class=\"selectTooltip\"\n            position=\"bottom\"\n            :tooltip=\"t('Settings.Player Settings.Screenshot.File Name Tooltip')\"\n          />\n        </p>\n        <FtInput\n          class=\"screenshotFilenamePatternInput\"\n          placeholder=\"\"\n          :value=\"screenshotFilenamePattern\"\n          :show-action-button=\"false\"\n          :show-label=\"false\"\n          @input=\"handleScreenshotFilenamePatternChanged\"\n        />\n        <FtInput\n          class=\"screenshotFilenamePatternExample\"\n          :placeholder=\"screenshotFilenameExample\"\n          :show-action-button=\"false\"\n          :show-label=\"false\"\n          :disabled=\"true\"\n        />\n      </FtFlexBox>\n      <br>\n    </div>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, onMounted, ref } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport FtSlider from '../FtSlider/FtSlider.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtTooltip from '../FtTooltip/FtTooltip.vue'\n\nimport store from '../../store/index'\n\nconst { t } = useI18n()\n\n/** @type {boolean} */\nconst USING_ELECTRON = process.env.IS_ELECTRON\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst proxyVideos = computed(() => store.getters.getProxyVideos)\n\nconst showProxyVideosAsDisabled = computed(() => {\n  return store.getters.getBackendPreference !== 'invidious' && !store.getters.getBackendFallback\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateProxyVideos(value) {\n  store.dispatch('updateProxyVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst enableSubtitlesByDefault = computed(() => store.getters.getEnableSubtitlesByDefault)\n\n/**\n * @param {boolean} value\n */\nfunction updateEnableSubtitlesByDefault(value) {\n  store.dispatch('updateEnableSubtitlesByDefault', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst videoVolumeMouseScroll = computed(() => store.getters.getVideoVolumeMouseScroll)\n\n/**\n * @param {boolean} value\n */\nfunction updateVideoVolumeMouseScroll(value) {\n  store.dispatch('updateVideoVolumeMouseScroll', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst videoPlaybackRateMouseScroll = computed(() => store.getters.getVideoPlaybackRateMouseScroll)\n\n/**\n * @param {boolean} value\n */\nfunction updateVideoPlaybackRateMouseScroll(value) {\n  store.dispatch('updateVideoPlaybackRateMouseScroll', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst videoSkipMouseScroll = computed(() => store.getters.getVideoSkipMouseScroll)\n\n/**\n * @param {boolean} value\n */\nfunction updateVideoSkipMouseScroll(value) {\n  store.dispatch('updateVideoSkipMouseScroll', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst playNextVideo = computed(() => store.getters.getPlayNextVideo)\n\n/**\n * @param {boolean} value\n */\nfunction updatePlayNextVideo(value) {\n  store.dispatch('updatePlayNextVideo', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideRecommendedVideos = computed(() => store.getters.getHideRecommendedVideos)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst autoplayPlaylists = computed(() => store.getters.getAutoplayPlaylists)\n\n/**\n * @param {boolean} value\n */\nfunction updateAutoplayPlaylists(value) {\n  store.dispatch('updateAutoplayPlaylists', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst autoplayVideos = computed(() => store.getters.getAutoplayVideos)\n\n/**\n * @param {boolean} value\n */\nfunction updateAutoplayVideos(value) {\n  store.dispatch('updateAutoplayVideos', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst displayVideoPlayButton = computed(() => store.getters.getDisplayVideoPlayButton)\n\n/**\n * @param {boolean} value\n */\nfunction updateDisplayVideoPlayButton(value) {\n  store.dispatch('updateDisplayVideoPlayButton', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst enterFullscreenOnDisplayRotate = computed(() => store.getters.getEnterFullscreenOnDisplayRotate)\n\n/**\n * @param {boolean} value\n */\nfunction updateEnterFullscreenOnDisplayRotate(value) {\n  store.dispatch('updateEnterFullscreenOnDisplayRotate', value)\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst externalPlayer = computed(() => store.getters.getExternalPlayer)\n\nconst defaultViewingMode = computed(() => {\n  /** @type {'default' | 'theatre' | 'fullwindow' | 'fullscreen' | 'pip' | 'external_player'} */\n  const defaultViewingMode = store.getters.getDefaultViewingMode\n\n  if ((defaultViewingMode === 'external_player' && (!process.env.IS_ELECTRON || externalPlayer.value === '')) ||\n    (!process.env.IS_ELECTRON && (defaultViewingMode === 'fullscreen' || defaultViewingMode === 'pip'))) {\n    return 'default'\n  }\n\n  return defaultViewingMode\n})\n\nconst viewingModeNames = computed(() => {\n  const viewingModeNames = [\n    t('Settings.General Settings.Thumbnail Preference.Default'),\n    t('Settings.Player Settings.Default Viewing Mode.Theater'),\n    t('Video.Player.Full Window'),\n\n    ...process.env.IS_ELECTRON\n      ? [\n          t('Settings.Player Settings.Default Viewing Mode.Full Screen'),\n          t('Settings.Player Settings.Default Viewing Mode.Picture in Picture')\n        ]\n      : []\n  ]\n\n  if (process.env.IS_ELECTRON && externalPlayer.value !== '') {\n    viewingModeNames.push(\n      t('Settings.Player Settings.Default Viewing Mode.External Player', { externalPlayerName: externalPlayer.value })\n    )\n  }\n\n  return viewingModeNames\n})\n\nconst viewingModeValues = computed(() => {\n  const viewingModeValues = [\n    'default',\n    'theatre',\n    'fullwindow',\n\n    ...process.env.IS_ELECTRON\n      ? ['fullscreen', 'pip']\n      : []\n  ]\n\n  if (process.env.IS_ELECTRON && externalPlayer.value !== '') {\n    viewingModeValues.push('external_player')\n  }\n\n  return viewingModeValues\n})\n\n/**\n * @param {'default' | 'theatre' | 'fullwindow' | 'fullscreen' | 'pip' | 'external_player'} value\n */\nfunction updateDefaultViewingMode(value) {\n  store.dispatch('updateDefaultViewingMode', value)\n}\n\nconst FORMAT_VALUES = ['dash', 'legacy', 'audio']\n\nconst formatNames = computed(() => [\n  t('Settings.Player Settings.Default Video Format.Dash Formats'),\n  t('Settings.Player Settings.Default Video Format.Legacy Formats'),\n  t('Settings.Player Settings.Default Video Format.Audio Formats')\n])\n\n/** @type {import('vue').ComputedRef<'dash' | 'audio' |' legacy'>} */\nconst defaultVideoFormat = computed(() => store.getters.getDefaultVideoFormat)\n\n/**\n * @param {'dash' | 'legacy' | 'audio'} value\n */\nfunction updateDefaultVideoFormat(value) {\n  store.dispatch('updateDefaultVideoFormat', value)\n}\n\nconst QUALITY_VALUES = ['2160', '1440', '1080', '720', '480', '360', '240', '144', 'auto']\n\nconst qualityNames = computed(() => [\n  t('Settings.Player Settings.Default Quality.4k'),\n  t('Settings.Player Settings.Default Quality.1440p'),\n  t('Settings.Player Settings.Default Quality.1080p'),\n  t('Settings.Player Settings.Default Quality.720p'),\n  t('Settings.Player Settings.Default Quality.480p'),\n  t('Settings.Player Settings.Default Quality.360p'),\n  t('Settings.Player Settings.Default Quality.240p'),\n  t('Settings.Player Settings.Default Quality.144p'),\n  t('Settings.Player Settings.Default Quality.Auto')\n])\n\n/** @type {import('vue').ComputedRef<'2160' | '1440' | '1080' | '720' | '480' | '360' | '240' | '144' | 'auto'>} */\nconst defaultQuality = computed(() => store.getters.getDefaultQuality)\n\n/**\n * @param {'2160' | '1440' | '1080' | '720' | '480' | '360' | '240' | '144' | 'auto'} value\n */\nfunction updateDefaultQuality(value) {\n  store.dispatch('updateDefaultQuality', value)\n}\n\nconst PLAYBACK_RATE_INTERVAL_VALUES = ['0.1', '0.25', '0.5', '1']\n\n/** @type {import('vue').ComputedRef<number>} */\nconst videoPlaybackRateInterval = computed(() => store.getters.getVideoPlaybackRateInterval)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst videoPlaybackRateIntervalString = computed(() => store.getters.getVideoPlaybackRateInterval.toString())\n\n/**\n * @param {string} value\n */\nfunction updateVideoPlaybackRateInterval(value) {\n  store.dispatch('updateVideoPlaybackRateInterval', parseFloat(value))\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultInterval = computed(() => store.getters.getDefaultInterval)\n\n/**\n * @param {number} value\n */\nfunction updateDefaultInterval(value) {\n  store.dispatch('updateDefaultInterval', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultAutoplayInterruptionIntervalHours = computed(() => {\n  return store.getters.getDefaultAutoplayInterruptionIntervalHours\n})\n\n/**\n * @param {number} value\n */\nfunction updateDefaultAutoplayInterruptionIntervalHours(value) {\n  store.dispatch('updateDefaultAutoplayInterruptionIntervalHours', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultSkipInterval = computed(() => store.getters.getDefaultSkipInterval)\n\n/**\n * @param {number} value\n */\nfunction updateDefaultSkipInterval(value) {\n  store.dispatch('updateDefaultSkipInterval', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultVolume = computed(() => Math.round(store.getters.getDefaultVolume * 100))\n\n/**\n * @param {number} value\n */\nfunction updateDefaultVolume(value) {\n  store.dispatch('updateDefaultVolume', value / 100)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultPlayback = computed(() => store.getters.getDefaultPlayback)\n\n/**\n * @param {number} value\n */\nfunction updateDefaultPlayback(value) {\n  store.dispatch('updateDefaultPlayback', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst maxVideoPlaybackRate = computed(() => store.getters.getMaxVideoPlaybackRate)\n\n/**\n * @param {number} value\n */\nfunction updateMaxVideoPlaybackRate(value) {\n  store.dispatch('updateMaxVideoPlaybackRate', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst enableScreenshot = computed(() => store.getters.getEnableScreenshot)\n\n/**\n * @param {boolean} value\n */\nfunction updateEnableScreenshot(value) {\n  store.dispatch('updateEnableScreenshot', value)\n}\n\nconst SCREENSHOT_FORMAT_NAMES = ['PNG', 'JPEG', 'WebP']\nconst SCREENSHOT_FORMAT_VALUES = ['png', 'jpeg', 'webp']\n\n/** @type {import('vue').ComputedRef<'png' | 'jpeg' | 'webp'>} */\nconst screenshotFormat = computed(() => store.getters.getScreenshotFormat)\n\n/**\n * @param {'png' | 'jpeg' | 'webp'} format\n */\nasync function handleUpdateScreenshotFormat(format) {\n  await store.dispatch('updateScreenshotFormat', format)\n  getScreenshotFilenameExample(screenshotFilenamePattern.value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst screenshotQuality = computed(() => store.getters.getScreenshotQuality)\n\n/**\n * @param {number} value\n */\nfunction updateScreenshotQuality(value) {\n  store.dispatch('updateScreenshotQuality', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst screenshotAskPath = computed(() => store.getters.getScreenshotAskPath)\n\n/**\n * @param {boolean} value\n */\nfunction updateScreenshotAskPath(value) {\n  store.dispatch('updateScreenshotAskPath', value)\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst screenshotFolder = computed(() => store.getters.getScreenshotFolderPath)\n\nfunction chooseScreenshotFolder() {\n  // only use with electron\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.chooseDefaultFolder()\n  }\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst screenshotFilenamePattern = computed(() => store.getters.getScreenshotFilenamePattern)\n\nonMounted(() => {\n  getScreenshotFilenameExample(screenshotFilenamePattern.value)\n})\n\nconst SCREENSHOT_DEFAULT_PATTERN = '%Y%M%D-%H%N%S'\n\n/**\n * @param {string} input\n */\nasync function handleScreenshotFilenamePatternChanged(input) {\n  const pattern = input.trim()\n\n  if (!await getScreenshotFilenameExample(pattern)) {\n    return\n  }\n\n  store.dispatch('updateScreenshotFilenamePattern', pattern || SCREENSHOT_DEFAULT_PATTERN)\n}\n\nconst screenshotFilenameExample = ref('')\n\n/**\n * @param {string} pattern\n */\nasync function getScreenshotFilenameExample(pattern) {\n  try {\n    const filename = await store.dispatch('parseScreenshotCustomFileName', {\n      pattern: pattern || SCREENSHOT_DEFAULT_PATTERN,\n      date: new Date(),\n      playerTime: 123.456,\n      videoId: 'dQw4w9WgXcQ'\n    })\n\n    screenshotFilenameExample.value = `${filename}.${screenshotFormat.value}`\n    return true\n  } catch (err) {\n    screenshotFilenameExample.value = `❗ ${err.message}`\n    return false\n  }\n}\n</script>\n\n<style scoped src=\"./PlayerSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/PlaylistInfo/PlaylistInfo.scss",
    "content": ".playListThumbnail {\n  inline-size: 100%;\n}\n\n.playlistThumbnail img {\n  inline-size: 100%;\n  // Ensure placeholder image displayed at same aspect ratio as most other images\n  aspect-ratio: 16/9;\n\n  @media only screen and (width <= 800px) {\n    display: none;\n  }\n}\n\n.blur {\n  filter: blur(20px);\n}\n\n.playlistStats {\n  font-size: 15px;\n}\n\n.playlistStats p {\n  color: var(--secondary-text-color);\n  margin: 0;\n}\n\n.playlistTitle {\n  margin-block-end: 0.1em;\n\n  /* Prevents overflow for long values */\n  overflow-wrap: anywhere;\n\n  @media only screen and (width <= 850px) {\n    // margin-inline-in routerView = 8px x2 = 16px\n    // For unknown reason class `routerView` is in 2 containers\n    // padding for `playlistInfo` is 10px x2 = 20px\n    // Also scrollbar got unknown width so using 95vw instead of 100vw\n    max-inline-size: calc(95vw - 32px - 20px);\n    text-overflow: ellipsis;\n  }\n}\n\n.playlistDescription {\n  max-block-size: 20vh;\n  overflow-y: auto;\n  white-space: break-spaces;\n  margin-inline: auto;\n\n  @media only screen and (width <= 500px) {\n    max-block-size: 10vh;\n  }\n}\n\n.playlistChannel {\n  align-items: center;\n  color: inherit;\n  display: flex;\n  gap: 8px;\n  block-size: 40px;\n  text-decoration: none;\n}\n\n.channelThumbnail {\n  border-radius: 200px;\n  float: inline-start;\n  inline-size: 40px;\n}\n\n.channelName {\n  font-size: 15px;\n  margin: 0;\n  word-break: break-all;\n}\n\n.channelShareWrapper {\n  column-gap: 8px;\n  display: grid;\n  grid-template-columns: auto minmax(min-content, 1fr);\n}\n\n.playlistOptions {\n  display: grid;\n  grid-auto-flow: column;\n  column-gap: 8px;\n  justify-content: flex-end;\n}\n\n.searchInputsRow {\n  margin-block-start: 8px;\n}\n\n.top-bar {\n  .playlistThumbnail,\n  .playlistInfoSeparator {\n    display: none;\n  }\n\n  .playlistStats {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    text-align: center;\n  }\n\n  .playlistTitle {\n    margin-block-start: 0.2em;\n  }\n\n  .playlistTitle,\n  .playlistDescription {\n    overflow-x: hidden;\n    text-align: center;\n    text-overflow: ellipsis;\n    max-inline-size: 750px;\n    inline-size: 100%;\n    margin-block: 8px;\n  }\n\n  .descriptionInput {\n    margin-block-start: 8px;\n  }\n\n  .playlistOptionsAndSearch {\n    display: flex;\n    flex-direction: column;\n    justify-content: space-between;\n    align-items: center;\n  }\n\n  .channelShareWrapper,\n  .searchInputsRow,\n  .playlistStats {\n    column-gap: 0;\n    inline-size: 100%;\n  }\n\n  .inputElement {\n    inline-size: 100%;\n  }\n}\n\n@media only screen and (width <= 1250px) {\n  :deep(.sharePlaylistIcon .iconDropdown) {\n    inset-inline: auto;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/PlaylistInfo/PlaylistInfo.vue",
    "content": "<template>\n  <div\n    class=\"playlistInfo\"\n    :class=\"{ [theme]: true }\"\n  >\n    <div\n      class=\"playlistThumbnail\"\n    >\n      <router-link\n        v-if=\"firstVideoIdExists\"\n        :to=\"{\n          path: `/watch/${firstVideoId}`,\n          query: {\n            playlistId: id,\n            playlistType: videoPlaylistType,\n            playlistItemId: firstVideoPlaylistItemId,\n          },\n        }\"\n        tabindex=\"-1\"\n      >\n        <img\n          :src=\"thumbnail\"\n          alt=\"\"\n          :class=\"{ blur: blurThumbnails }\"\n        >\n      </router-link>\n      <img\n        v-else\n        :src=\"thumbnail\"\n        alt=\"\"\n        :class=\"{ blur: blurThumbnails }\"\n      >\n    </div>\n\n    <div class=\"playlistStats\">\n      <template\n        v-if=\"editMode\"\n      >\n        <FtInput\n          ref=\"playlistTitleInput\"\n          class=\"inputElement\"\n          :placeholder=\"$t('User Playlists.Playlist Name')\"\n          :show-action-button=\"false\"\n          :show-label=\"false\"\n          :value=\"newTitle\"\n          :maxlength=\"255\"\n          @input=\"handlePlaylistNameInput\"\n          @keydown.enter=\"savePlaylistInfo\"\n        />\n        <FtFlexBox v-if=\"inputPlaylistNameBlank\">\n          <p>\n            {{ $t('User Playlists.SinglePlaylistView.Toast[\"Playlist name cannot be empty. Please input a name.\"]') }}\n          </p>\n        </FtFlexBox>\n        <FtFlexBox v-if=\"inputPlaylistWithNameExists\">\n          <p>\n            {{ $t('User Playlists.CreatePlaylistPrompt.Toast[\"There is already a playlist with this name. Please pick a different name.\"]') }}\n          </p>\n        </FtFlexBox>\n      </template>\n      <template\n        v-else\n      >\n        <h2\n          class=\"playlistTitle\"\n          dir=\"auto\"\n        >\n          {{ title }}\n        </h2>\n        <p>\n          {{ t('Global.Counts.Video Count', { count: parsedVideoCount }, videoCount) }}\n          <template v-if=\"!hideViews && !isUserPlaylist\">\n            - {{ t('Global.Counts.View Count', { count: parsedViewCount }, viewCount) }}\n          </template>\n          -\n          <template v-if=\"infoSource !== 'local'\">\n            {{ $t(\"Playlist.Last Updated On\") }}\n          </template>\n          {{ lastUpdated }}\n          <template v-if=\"durationFormatted !== ''\">\n            <br>\n            {{ $t('User Playlists.TotalTimePlaylist', { duration: durationFormatted }) }}\n          </template>\n        </p>\n      </template>\n    </div>\n\n    <FtInput\n      v-if=\"editMode\"\n      class=\"inputElement descriptionInput\"\n      :placeholder=\"$t('User Playlists.Playlist Description')\"\n      :show-action-button=\"false\"\n      :show-label=\"false\"\n      :value=\"newDescription\"\n      @input=\"(input) => newDescription = input\"\n      @keydown.enter=\"savePlaylistInfo\"\n    />\n    <p\n      v-else\n      class=\"playlistDescription\"\n      dir=\"auto\"\n    >\n      {{ description }}\n    </p>\n\n    <hr class=\"playlistInfoSeparator\">\n\n    <div\n      class=\"channelShareWrapper\"\n    >\n      <router-link\n        v-if=\"!isUserPlaylist && channelId\"\n        class=\"playlistChannel\"\n        :to=\"`/channel/${channelId}`\"\n      >\n        <img\n          class=\"channelThumbnail\"\n          :src=\"channelThumbnail\"\n          alt=\"\"\n        >\n        <h3\n          class=\"channelName\"\n          dir=\"auto\"\n        >\n          {{ channelName }}\n        </h3>\n      </router-link>\n      <div\n        v-else\n        class=\"playlistChannel\"\n      >\n        <h3\n          class=\"channelName\"\n          dir=\"auto\"\n        >\n          {{ channelName }}\n        </h3>\n      </div>\n\n      <div class=\"playlistOptionsAndSearch\">\n        <div class=\"playlistOptions\">\n          <FtIconButton\n            v-if=\"editMode\"\n            :title=\"$t('User Playlists.Save Changes')\"\n            :disabled=\"playlistPersistenceDisabled\"\n            :icon=\"['fas', 'save']\"\n            theme=\"secondary\"\n            @click=\"savePlaylistInfo\"\n          />\n          <FtIconButton\n            v-if=\"editMode\"\n            :title=\"$t('User Playlists.Cancel')\"\n            :icon=\"['fas', 'times']\"\n            theme=\"secondary\"\n            @click=\"exitEditMode\"\n          />\n          <FtIconButton\n            v-if=\"!editMode && isUserPlaylist\"\n            :title=\"markedAsQuickBookmarkTarget ? $t('User Playlists.Quick Bookmark Enabled') : $t('User Playlists.Enable Quick Bookmark With This Playlist')\"\n            :icon=\"markedAsQuickBookmarkTarget ? ['fas', 'bookmark'] : ['far', 'bookmark']\"\n            :disabled=\"markedAsQuickBookmarkTarget\"\n            :theme=\"markedAsQuickBookmarkTarget ? 'secondary' : 'base-no-default'\"\n            @disabled-click=\"handleQuickBookmarkEnabledDisabledClick\"\n            @click=\"enableQuickBookmarkForThisPlaylist\"\n          />\n          <FtIconButton\n            v-if=\"!editMode && isUserPlaylist\"\n            :title=\"$t('User Playlists.Edit Playlist Info')\"\n            :icon=\"['fas', 'edit']\"\n            theme=\"secondary\"\n            @click=\"enterEditMode\"\n          />\n          <FtIconButton\n            v-if=\"videoCount > 0 && showPlaylists && !editMode\"\n            :title=\"$t('User Playlists.Copy Playlist')\"\n            :icon=\"['fas', 'copy']\"\n            theme=\"secondary\"\n            @click=\"toggleCopyVideosPrompt\"\n          />\n          <FtIconButton\n            v-if=\"exportPlaylistButtonVisible\"\n            :title=\"$t('User Playlists.Export Playlist')\"\n            :icon=\"['fas', 'file-arrow-down']\"\n            theme=\"secondary\"\n            @click=\"showExportPrompt = true\"\n          />\n          <FtIconButton\n            v-if=\"!editMode && userPlaylistDuplicateItemCount > 0\"\n            :title=\"$t('User Playlists.Remove Duplicate Videos')\"\n            :icon=\"['fas', 'users-slash']\"\n            theme=\"destructive\"\n            @click=\"showRemoveDuplicateVideosPrompt = true\"\n          />\n          <FtIconButton\n            v-if=\"!editMode && userPlaylistAnyVideoWatched\"\n            :title=\"$t('User Playlists.Remove Watched Videos')\"\n            :icon=\"['fas', 'eye-slash']\"\n            theme=\"destructive\"\n            @click=\"showRemoveVideosOnWatchPrompt = true\"\n          />\n          <FtIconButton\n            v-if=\"deletePlaylistButtonVisible\"\n            :disabled=\"markedAsQuickBookmarkTarget\"\n            :title=\"!markedAsQuickBookmarkTarget ? $t('User Playlists.Delete Playlist') : playlistDeletionDisabledLabel\"\n            :icon=\"['fas', 'trash']\"\n            theme=\"destructive\"\n            @disabled-click=\"handlePlaylistDeleteDisabledClick\"\n            @click=\"showDeletePlaylistPrompt = true\"\n          />\n          <FtShareButton\n            v-if=\"sharePlaylistButtonVisible\"\n            :id=\"id\"\n            class=\"sharePlaylistIcon\"\n            :dropdown-position-y=\"description ? 'top' : 'bottom'\"\n            share-target-type=\"Playlist\"\n          />\n        </div>\n        <div\n          v-if=\"searchVideoModeAllowed\"\n          class=\"searchInputsRow\"\n        >\n          <FtInput\n            ref=\"searchInput\"\n            class=\"inputElement\"\n            :placeholder=\"$t('User Playlists.SinglePlaylistView.Search for Videos')\"\n            :show-clear-text-button=\"true\"\n            :show-action-button=\"false\"\n            :value=\"query\"\n            :maxlength=\"255\"\n            @input=\"updateQueryDebounced\"\n            @clear=\"updateQueryDebounced('')\"\n          />\n        </div>\n      </div>\n      <FtPrompt\n        v-if=\"showDeletePlaylistPrompt\"\n        :label=\"$t('User Playlists.Are you sure you want to delete this playlist? This cannot be undone')\"\n        :option-names=\"deletePlaylistPromptNames\"\n        :option-values=\"DELETE_PLAYLIST_PROMPT_VALUES\"\n        is-first-option-destructive\n        @click=\"handleDeletePlaylistPromptAnswer\"\n      />\n      <FtPrompt\n        v-if=\"showRemoveVideosOnWatchPrompt\"\n        :label=\"removeVideosOnWatchPromptLabelText\"\n        :option-names=\"deletePlaylistPromptNames\"\n        :option-values=\"DELETE_PLAYLIST_PROMPT_VALUES\"\n        is-first-option-destructive\n        @click=\"handleRemoveVideosOnWatchPromptAnswer\"\n      />\n      <FtPrompt\n        v-if=\"showRemoveDuplicateVideosPrompt\"\n        :label=\"removeDuplicateVideosPromptLabelText\"\n        :option-names=\"deletePlaylistPromptNames\"\n        :option-values=\"DELETE_PLAYLIST_PROMPT_VALUES\"\n        is-first-option-destructive\n        @click=\"handleRemoveDuplicateVideosPromptAnswer\"\n      />\n      <FtPrompt\n        v-if=\"showExportPrompt\"\n        :label=\"t('Settings.Data Settings.Select Export Type')\"\n        :option-names=\"exportNames\"\n        :option-values=\"EXPORT_VALUES\"\n        @click=\"handleExport\"\n      />\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRouter } from 'vue-router'\n\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtPrompt from '../FtPrompt/FtPrompt.vue'\nimport FtShareButton from '../FtShareButton/FtShareButton.vue'\n\nimport store from '../../store/index'\n\nimport {\n  ctrlFHandler,\n  debounce,\n  formatNumber,\n  showToast,\n  getTodayDateStrLocalTimezone,\n  writeFileWithPicker,\n  deepCopy,\n} from '../../helpers/utils'\nimport thumbnailPlaceholder from '../../assets/img/thumbnail_placeholder.svg'\n\nconst props = defineProps({\n  id: {\n    type: String,\n    required: true,\n  },\n  firstVideoId: {\n    type: String,\n    required: true,\n  },\n  firstVideoPlaylistItemId: {\n    type: String,\n    required: true,\n  },\n  playlistThumbnail: {\n    type: String,\n    required: true,\n  },\n  theme: {\n    type: String,\n    default: 'base'\n  },\n  title: {\n    type: String,\n    required: true,\n  },\n  channelThumbnail: {\n    type: String,\n    required: true,\n  },\n  channelName: {\n    type: String,\n    required: true,\n  },\n  channelId: {\n    type: String,\n    default: null,\n  },\n  videoCount: {\n    type: Number,\n    required: true,\n  },\n  videos: {\n    type: Array,\n    required: true\n  },\n  sortedVideos: {\n    type: Array,\n    required: true\n  },\n  viewCount: {\n    type: Number,\n    required: true,\n  },\n  totalPlaylistDuration: {\n    type: Number,\n    required: true\n  },\n  isDurationApproximate: {\n    type: Boolean,\n    required: true\n  },\n  lastUpdated: {\n    type: String,\n    default: undefined,\n  },\n  description: {\n    type: String,\n    required: true,\n  },\n  infoSource: {\n    type: String,\n    required: true,\n  },\n  moreVideoDataAvailable: {\n    type: Boolean,\n    required: true,\n  },\n  searchVideoModeAllowed: {\n    type: Boolean,\n    required: true,\n  },\n  searchQueryText: {\n    type: String,\n    required: true,\n  },\n})\n\nconst emit = defineEmits(['enter-edit-mode', 'exit-edit-mode', 'search-video-query-change', 'prompt-open', 'prompt-close'])\n\nconst { locale, t } = useI18n()\n\nconst query = ref('')\nconst editMode = ref(false)\nconst showDeletePlaylistPrompt = ref(false)\nconst showRemoveVideosOnWatchPrompt = ref(false)\nconst showRemoveDuplicateVideosPrompt = ref(false)\nconst showExportPrompt = ref(false)\nconst newTitle = ref(props.title)\nconst newDescription = ref(props.description)\n\nif (props.videoCount > 0) {\n  query.value = props.searchQueryText\n}\n\nconst durationFormatted = computed(() => {\n  const total = props.totalPlaylistDuration\n\n  const duration = {\n    hours: Math.floor(total / 3600),\n    minutes: Math.floor((total % 3600) / 60),\n    seconds: total % 60,\n  }\n\n  let formatted = new Intl.DurationFormat([locale.value, 'en'], { style: 'short' }).format(duration)\n\n  if (props.moreVideoDataAvailable && !isUserPlaylist.value) {\n    formatted += '+'\n  }\n\n  if (props.isDurationApproximate && formatted) {\n    formatted = `~${formatted}`\n  }\n\n  return formatted\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSharingActions = computed(() => store.getters.getHideSharingActions)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<Record<string, object>>} */\nconst historyCacheById = computed(() => store.getters.getHistoryCacheById)\n\n/** @type {import('vue').ComputedRef<'' | 'start' | 'middle' | 'end' | 'hidden' | 'blur'>} */\nconst thumbnailPreference = computed(() => store.getters.getThumbnailPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst blurThumbnails = computed(() => store.getters.getBlurThumbnails)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideViews = computed(() => store.getters.getHideVideoViews)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showPlaylists = computed(() => !store.getters.getHidePlaylists)\n\n/** @type {import('vue').ComputedRef<object | undefined>} */\nconst selectedUserPlaylist = computed(() => store.getters.getPlaylist(props.id))\n\n/** @type {import('vue').ComputedRef<object[]>} */\nconst allPlaylists = computed(() => store.getters.getAllPlaylists)\n\nconst firstVideoIdExists = computed(() => props.firstVideoId !== '')\n\nconst parsedViewCount = computed(() => formatNumber(props.viewCount))\nconst parsedVideoCount = computed(() => formatNumber(props.videoCount))\n\n/** @type {import('vue').ComputedRef<string>} */\nconst thumbnail = computed(() => {\n  if (thumbnailPreference.value === 'hidden' || !firstVideoIdExists.value) {\n    return thumbnailPlaceholder\n  }\n\n  let baseUrl = 'https://i.ytimg.com'\n  if (backendPreference.value === 'invidious') {\n    baseUrl = currentInvidiousInstanceUrl.value\n  } else if (typeof props.playlistThumbnail === 'string' && props.playlistThumbnail.length > 0) {\n    // Use playlist thumbnail provided by YT when available\n    return props.playlistThumbnail\n  }\n\n  switch (thumbnailPreference.value) {\n    case 'start':\n      return `${baseUrl}/vi/${props.firstVideoId}/mq1.jpg`\n    case 'middle':\n      return `${baseUrl}/vi/${props.firstVideoId}/mq2.jpg`\n    case 'end':\n      return `${baseUrl}/vi/${props.firstVideoId}/mq3.jpg`\n    default:\n      return `${baseUrl}/vi/${props.firstVideoId}/mqdefault.jpg`\n  }\n})\n\nconst isUserPlaylist = computed(() => props.infoSource === 'user')\nconst videoPlaylistType = computed(() => isUserPlaylist.value ? 'user' : '')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst userPlaylistAnyVideoWatched = computed(() => {\n  if (!isUserPlaylist.value) { return false }\n\n  const historyCacheById_ = historyCacheById.value\n  return selectedUserPlaylist.value.videos.some((video) => {\n    return historyCacheById_[video.videoId] !== undefined\n  })\n})\n\n/** @type {import('vue').ComputedRef<number>} */\nconst userPlaylistUniqueVideosCount = computed(() => {\n  return selectedUserPlaylist.value?.videos.reduce((set, video) => {\n    set.add(video.videoId)\n    return set\n  }, new Set()).size ?? 0\n})\n\nconst userPlaylistDuplicateItemCount = computed(() => {\n  if (userPlaylistUniqueVideosCount.value === 0) { return 0 }\n\n  return selectedUserPlaylist.value.videos.length - userPlaylistUniqueVideosCount.value\n})\n\nconst exportPlaylistButtonVisible = computed(() => {\n  return isUserPlaylist.value && !editMode.value && props.videoCount > 0\n})\n\nconst deletePlaylistButtonVisible = computed(() => {\n  return isUserPlaylist.value && !editMode.value && !selectedUserPlaylist.value.protected\n})\n\nconst sharePlaylistButtonVisible = computed(() => {\n  return !isUserPlaylist.value && !hideSharingActions.value\n})\n\n/** @type {import('vue').ComputedRef<object | undefined>} */\nconst quickBookmarkPlaylist = computed(() => {\n  return store.getters.getQuickBookmarkPlaylist\n})\n\nconst markedAsQuickBookmarkTarget = computed(() => {\n  return selectedUserPlaylist.value &&\n    quickBookmarkPlaylist.value &&\n    quickBookmarkPlaylist.value._id === selectedUserPlaylist.value._id\n})\n\nconst playlistDeletionDisabledLabel = computed(() => {\n  return t('User Playlists[\"Cannot delete the quick bookmark target playlist.\"]')\n})\n\nconst inputPlaylistNameBlank = computed(() => newTitle.value.trim() === '')\n\nconst inputPlaylistWithNameExists = computed(() => {\n  const playlistName = newTitle.value\n  const selectedUserPlaylistId = selectedUserPlaylist.value._id\n\n  return playlistName !== '' &&\n    allPlaylists.value.some((playlist) => {\n      return playlist._id !== selectedUserPlaylistId && playlist.playlistName === playlistName\n    })\n})\n\nconst playlistPersistenceDisabled = computed(() => {\n  return inputPlaylistNameBlank.value || inputPlaylistWithNameExists.value\n})\n\nwatch(showDeletePlaylistPrompt, handlePromptToggle)\nwatch(showRemoveVideosOnWatchPrompt, handlePromptToggle)\nwatch(showExportPrompt, handlePromptToggle)\n\n/**\n * @param {boolean} shown\n */\nfunction handlePromptToggle(shown) {\n  if (shown) {\n    emit('prompt-open')\n  } else {\n    emit('prompt-close')\n  }\n}\n\n/**\n * @param {string} input\n */\nfunction handlePlaylistNameInput(input) {\n  if (input.trim() === '') {\n    // Need to show message for blank input\n    newTitle.value = input\n    return\n  }\n\n  newTitle.value = input.trim()\n}\n\nfunction toggleCopyVideosPrompt(force = false) {\n  if (props.moreVideoDataAvailable && !isUserPlaylist.value && !force) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"Some videos in the playlist are not loaded yet. Click here to copy anyway.\"]'), 5000, () => {\n      toggleCopyVideosPrompt(true)\n    })\n    return\n  }\n\n  store.dispatch('showAddToPlaylistPromptForManyVideos', {\n    videos: props.videos,\n    newPlaylistDefaultProperties: {\n      title: props.channelName === '' ? props.title : `${props.title} | ${props.channelName}`,\n    },\n  })\n}\n\nasync function savePlaylistInfo() {\n  // Still possible to attempt to create via pressing enter\n  if (playlistPersistenceDisabled.value) { return }\n\n  const playlist = {\n    playlistName: newTitle.value,\n    protected: selectedUserPlaylist.value.protected,\n    description: newDescription.value,\n    videos: deepCopy(selectedUserPlaylist.value.videos),\n    _id: props.id,\n  }\n  try {\n    await store.dispatch('updatePlaylist', playlist)\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"Playlist has been updated.\"]'))\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There was an issue with updating this playlist.\"]'))\n    console.error(e)\n  } finally {\n    exitEditMode()\n  }\n}\n\nconst playlistTitleInput = useTemplateRef('playlistTitleInput')\n\nfunction enterEditMode() {\n  newTitle.value = props.title\n  newDescription.value = props.description\n  editMode.value = true\n\n  emit('enter-edit-mode')\n\n  nextTick(() => {\n    playlistTitleInput.value.focus()\n  })\n}\n\nfunction handleQuickBookmarkEnabledDisabledClick() {\n  showToast(t('User Playlists.SinglePlaylistView.Toast[\"This playlist is already being used for quick bookmark.\"]'))\n}\n\nfunction handlePlaylistDeleteDisabledClick() {\n  showToast(playlistDeletionDisabledLabel.value)\n}\n\nconst EXPORT_VALUES = [\n  'database',\n  'youtube',\n  'urls',\n  'close'\n]\n\nconst exportNames = computed(() => [\n  `${t('Settings.Data Settings.Export FreeTube')} (.db)`,\n  `${t('Settings.Data Settings.Export YouTube')} (.csv)`,\n  `${t('User Playlists.Export list of URLs')} (.txt)`,\n  t('Close')\n])\n\n/**\n * @param {'database' | 'youtube' | 'urls' | null} value\n */\nfunction handleExport(value) {\n  showExportPrompt.value = false\n\n  switch (value) {\n    case 'database':\n      exportAsFreeTubeDatabase()\n      break\n    case 'youtube':\n      exportAsYouTubeCsv()\n      break\n    case 'urls':\n      exportAsListOfUrls()\n      break\n  }\n}\n\n/**\n * @param {string} title\n * @param {string} extension\n */\nfunction getExportFilename(title, extension) {\n  const dateStr = getTodayDateStrLocalTimezone()\n  const sanitisedTitle = title.replaceAll(/[ \"%*/:<>?\\\\|]/g, '_')\n  return `freetube-playlist-${sanitisedTitle}-${dateStr}.${extension}`\n}\n\nasync function exportAsFreeTubeDatabase() {\n  const exportFileName = getExportFilename(selectedUserPlaylist.value.playlistName, 'db')\n\n  const data = JSON.stringify(selectedUserPlaylist.value) + '\\n'\n\n  // See DataSettings.vue `promptAndWriteToFile`\n\n  try {\n    const response = await writeFileWithPicker(\n      exportFileName,\n      data,\n      t('Settings.Data Settings.Playlist File'),\n      'application/x-freetube-db',\n      '.db',\n      'single-playlist-export',\n      'downloads'\n    )\n\n    if (response) {\n      showToast(t('User Playlists.The playlist has been successfully exported'))\n    }\n  } catch (error) {\n    const message = t('Settings.Data Settings.Unable to write file')\n    showToast(`${message}: ${error}`)\n  }\n}\n\nasync function exportAsYouTubeCsv() {\n  const exportFileName = getExportFilename(props.title, 'csv')\n\n  const videoData = props.sortedVideos.map((video) => {\n    // Remove milliseconds and replace \"Z\" with +00:00 to match YouTube's exports\n    const timestamp = new Date(video.timeAdded).toISOString().slice(0, -5) + '+00:00'\n\n    return `${video.videoId},${timestamp}`\n  }).join('\\n')\n\n  // YouTube includes 6 line feed characters at the end of the file, so we do the same here\n  const data = `Video ID,Playlist video creation timestamp\\n${videoData}\\n\\n\\n\\n\\n\\n`\n\n  // See DataSettings.vue `promptAndWriteToFile`\n\n  try {\n    const response = await writeFileWithPicker(\n      exportFileName,\n      data,\n      '',\n      'text/csv',\n      '.csv',\n      'single-playlist-export',\n      'downloads'\n    )\n\n    if (response) {\n      showToast(t('User Playlists.The playlist has been successfully exported'))\n    }\n  } catch (error) {\n    const message = t('Settings.Data Settings.Unable to write file')\n    showToast(`${message}: ${error}`)\n  }\n}\n\nasync function exportAsListOfUrls() {\n  const exportFileName = getExportFilename(props.title, 'txt')\n\n  const data = props.sortedVideos.map((video) => {\n    return `https://www.youtube.com/watch?v=${video.videoId}`\n  }).join('\\n') + '\\n'\n\n  // See DataSettings.vue `promptAndWriteToFile`\n\n  try {\n    const response = await writeFileWithPicker(\n      exportFileName,\n      data,\n      '',\n      'text/plain',\n      '.txt',\n      'single-playlist-export',\n      'downloads'\n    )\n\n    if (response) {\n      showToast(t('User Playlists.The playlist has been successfully exported'))\n    }\n  } catch (error) {\n    const message = t('Settings.Data Settings.Unable to write file')\n    showToast(`${message}: ${error}`)\n  }\n}\n\nfunction exitEditMode() {\n  editMode.value = false\n\n  emit('exit-edit-mode')\n}\n\nconst DELETE_PLAYLIST_PROMPT_VALUES = ['delete', 'cancel']\n\nconst deletePlaylistPromptNames = computed(() => [\n  t('Yes, Delete'),\n  t('Cancel')\n])\n\n/** @type {import('vue').ComputedRef<number>} */\nconst userPlaylistWatchedVideoCount = computed(() => {\n  if (!isUserPlaylist.value || !userPlaylistAnyVideoWatched.value) { return false }\n\n  const historyCacheById_ = historyCacheById.value\n  return selectedUserPlaylist.value.videos.reduce((count, video) => {\n    return historyCacheById_[video.videoId] !== undefined ? count + 1 : count\n  }, 0)\n})\n\nconst removeVideosOnWatchPromptLabelText = computed(() => {\n  return t(\n    'User Playlists.Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone',\n    { playlistItemCount: userPlaylistWatchedVideoCount.value },\n    userPlaylistWatchedVideoCount.value\n  )\n})\n\nconst removeDuplicateVideosPromptLabelText = computed(() => {\n  return t(\n    'User Playlists.Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone',\n    { playlistItemCount: userPlaylistDuplicateItemCount.value },\n    userPlaylistDuplicateItemCount.value\n  )\n})\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nasync function handleRemoveDuplicateVideosPromptAnswer(option) {\n  showRemoveDuplicateVideosPrompt.value = false\n  if (option !== 'delete') { return }\n\n  const videoIdsAdded = new Set()\n  const newVideoItems = selectedUserPlaylist.value.videos.reduce((ary, video) => {\n    if (!videoIdsAdded.has(video.videoId)) {\n      ary.push(video)\n      videoIdsAdded.add(video.videoId)\n    }\n\n    return ary\n  }, [])\n\n  const removedVideosCount = userPlaylistDuplicateItemCount.value\n  if (removedVideosCount === 0) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There were no videos to remove.\"]'))\n    return\n  }\n\n  const playlist = {\n    playlistName: props.title,\n    protected: selectedUserPlaylist.value.protected,\n    description: props.description,\n    videos: deepCopy(newVideoItems),\n    _id: props.id,\n  }\n  try {\n    await store.dispatch('updatePlaylist', playlist)\n    showToast(t('User Playlists.SinglePlaylistView.Toast.{videoCount} video(s) have been removed', {\n      videoCount: removedVideosCount\n    }, removedVideosCount))\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There was an issue with updating this playlist.\"]'))\n    console.error(e)\n  }\n}\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nasync function handleRemoveVideosOnWatchPromptAnswer(option) {\n  showRemoveVideosOnWatchPrompt.value = false\n  if (option !== 'delete') { return }\n\n  const historyCacheById_ = historyCacheById.value\n  const videosToWatch = selectedUserPlaylist.value.videos.filter((video) => {\n    return !Object.hasOwn(historyCacheById_, video.videoId)\n  })\n\n  const removedVideosCount = selectedUserPlaylist.value.videos.length - videosToWatch.length\n\n  if (removedVideosCount === 0) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There were no videos to remove.\"]'))\n    return\n  }\n\n  const playlist = {\n    playlistName: props.title,\n    protected: selectedUserPlaylist.value.protected,\n    description: props.description,\n    videos: deepCopy(videosToWatch),\n    _id: props.id\n  }\n  try {\n    await store.dispatch('updatePlaylist', playlist)\n    showToast(t('User Playlists.SinglePlaylistView.Toast.{videoCount} video(s) have been removed', {\n      videoCount: removedVideosCount\n    }, removedVideosCount))\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There was an issue with updating this playlist.\"]'))\n    console.error(e)\n  }\n}\n\nconst router = useRouter()\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nfunction handleDeletePlaylistPromptAnswer(option) {\n  showDeletePlaylistPrompt.value = false\n  if (option !== 'delete') { return }\n\n  if (selectedUserPlaylist.value.protected) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"This playlist is protected and cannot be removed.\"]'))\n  } else {\n    store.dispatch('removePlaylist', props.id)\n    router.push(\n      {\n        path: '/userPlaylists'\n      }\n    )\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"Playlist {playlistName} has been deleted.\"]', {\n      playlistName: props.title\n    }))\n  }\n}\n\nfunction enableQuickBookmarkForThisPlaylist() {\n  const currentQuickBookmarkTargetPlaylist = quickBookmarkPlaylist.value\n\n  store.dispatch('updateQuickBookmarkTargetPlaylistId', props.id)\n  if (currentQuickBookmarkTargetPlaylist != null) {\n    showToast(\n      t('User Playlists.SinglePlaylistView.Toast[\"This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo\"]', {\n        oldPlaylistName: currentQuickBookmarkTargetPlaylist.playlistName\n      }),\n      5000,\n      () => {\n        store.dispatch('updateQuickBookmarkTargetPlaylistId', currentQuickBookmarkTargetPlaylist._id)\n        showToast(\n          t('User Playlists.SinglePlaylistView.Toast[\"Reverted to use {oldPlaylistName} for quick bookmark\"]', {\n            oldPlaylistName: currentQuickBookmarkTargetPlaylist.playlistName\n          }),\n          5000,\n        )\n      },\n    )\n  } else {\n    showToast(t('User Playlists.SinglePlaylistView.Toast.This playlist is now used for quick bookmark'))\n  }\n}\n\nconst updateQueryDebounced = debounce((newQuery) => {\n  query.value = newQuery\n  emit('search-video-query-change', newQuery)\n}, 500)\n\nconst searchInput = useTemplateRef('searchInput')\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchInput.value)\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n</script>\n\n<style scoped lang=\"scss\" src=\"./PlaylistInfo.scss\" />\n"
  },
  {
    "path": "src/renderer/components/PrivacySettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Privacy Settings.Privacy Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Privacy Settings.Remember History')\"\n          compact\n          :default-value=\"rememberHistory\"\n          @change=\"handleRememberHistory\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Privacy Settings.Remember Search History')\"\n          compact\n          :default-value=\"rememberSearchHistory\"\n          @change=\"updateRememberSearchHistory\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Privacy Settings.Save Watched Videos With Last Viewed Playlist')\"\n          compact\n          :disabled=\"!rememberHistory\"\n          :default-value=\"saveVideoHistoryWithLastViewedPlaylist\"\n          @change=\"updateSaveVideoHistoryWithLastViewedPlaylist\"\n        />\n      </div>\n    </div>\n    <br>\n    <FtFlexBox>\n      <FtSelect\n        :placeholder=\"$t('Settings.Privacy Settings.Save Watched Progress')\"\n        :value=\"watchedProgressSavingMode\"\n        :select-names=\"watchedProgressSavingModeNames\"\n        :select-values=\"WATCHED_PROGRESS_SAVING_MODE_VALUES\"\n        :icon=\"['fas', 'bars-progress']\"\n        :tooltip=\"$t('Settings.Privacy Settings.Watched Progress Saving Mode.Tooltip')\"\n        :disabled=\"!rememberHistory\"\n        @change=\"updateWatchedProgressSavingMode\"\n      />\n    </FtFlexBox>\n    <br>\n    <FtFlexBox>\n      <FtButton\n        :label=\"$t('Settings.Privacy Settings.Clear Search History and Cache')\"\n        text-color=\"var(--destructive-text-color)\"\n        background-color=\"var(--destructive-color)\"\n        :icon=\"['fas', 'trash']\"\n        @click=\"showSearchCachePrompt = true\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Privacy Settings.Remove Watch History')\"\n        text-color=\"var(--destructive-text-color)\"\n        background-color=\"var(--destructive-color)\"\n        :icon=\"['fas', 'trash']\"\n        @click=\"showRemoveHistoryPrompt = true\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Privacy Settings.Remove All Subscriptions / Profiles')\"\n        text-color=\"var(--destructive-text-color)\"\n        background-color=\"var(--destructive-color)\"\n        :icon=\"['fas', 'trash']\"\n        @click=\"showRemoveSubscriptionsPrompt = true\"\n      />\n      <FtButton\n        :label=\"$t('Settings.Privacy Settings.Remove All Playlists')\"\n        text-color=\"var(--destructive-text-color)\"\n        background-color=\"var(--destructive-color)\"\n        :icon=\"['fas', 'trash']\"\n        @click=\"showRemovePlaylistsPrompt = true\"\n      />\n    </FtFlexBox>\n    <FtPrompt\n      v-if=\"showSearchCachePrompt\"\n      :label=\"$t('Settings.Privacy Settings.Are you sure you want to clear out your search history and cache?')\"\n      :option-names=\"promptNames\"\n      :option-values=\"PROMPT_VALUES\"\n      is-first-option-destructive\n      @click=\"handleSearchCache\"\n    />\n    <FtPrompt\n      v-if=\"showRemoveHistoryPrompt\"\n      :label=\"$t('Settings.Privacy Settings.Are you sure you want to remove your entire watch history?')\"\n      :option-names=\"promptNames\"\n      :option-values=\"PROMPT_VALUES\"\n      is-first-option-destructive\n      @click=\"handleRemoveHistory\"\n    />\n    <FtPrompt\n      v-if=\"showRemoveSubscriptionsPrompt\"\n      :label=\"removeSubscriptionsPromptMessage\"\n      :option-names=\"promptNames\"\n      :option-values=\"PROMPT_VALUES\"\n      is-first-option-destructive\n      @click=\"handleRemoveSubscriptions\"\n    />\n    <FtPrompt\n      v-if=\"showRemovePlaylistsPrompt\"\n      :label=\"$t('Settings.Privacy Settings.Are you sure you want to remove all your playlists?')\"\n      :option-names=\"promptNames\"\n      :option-values=\"PROMPT_VALUES\"\n      is-first-option-destructive\n      @click=\"handleRemovePlaylists\"\n    />\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport FtButton from './FtButton/FtButton.vue'\nimport FtFlexBox from './ft-flex-box/ft-flex-box.vue'\nimport FtPrompt from './FtPrompt/FtPrompt.vue'\nimport FtSelect from './FtSelect/FtSelect.vue'\nimport FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'\nimport FtToggleSwitch from './FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../store/index'\n\nimport { MAIN_PROFILE_ID } from '../../constants'\nimport { showToast } from '../helpers/utils'\n\nconst { t } = useI18n()\n\nconst PROMPT_VALUES = ['delete', 'cancel']\nconst promptNames = computed(() => [\n  t('Yes, Delete'),\n  t('Cancel')\n])\n\nconst removeSubscriptionsPromptMessage = computed(() => {\n  return t('Settings.Privacy Settings[\"Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.\"]')\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst rememberHistory = computed(() => store.getters.getRememberHistory)\n\n/**\n * @param {boolean} value\n */\nfunction handleRememberHistory(value) {\n  if (!value) {\n    store.dispatch('updateWatchedProgressSavingMode', 'never')\n  }\n\n  store.dispatch('updateRememberHistory', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst rememberSearchHistory = computed(() => store.getters.getRememberSearchHistory)\n\n/**\n * @param {boolean} value\n */\nfunction updateRememberSearchHistory(value) {\n  store.dispatch('updateRememberSearchHistory', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst saveVideoHistoryWithLastViewedPlaylist = computed(() => store.getters.getSaveVideoHistoryWithLastViewedPlaylist)\n\n/**\n * @param {boolean} value\n */\nfunction updateSaveVideoHistoryWithLastViewedPlaylist(value) {\n  store.dispatch('updateSaveVideoHistoryWithLastViewedPlaylist', value)\n}\n\nconst WATCHED_PROGRESS_SAVING_MODE_VALUES = ['auto', 'semi-auto', 'never']\nconst watchedProgressSavingModeNames = computed(() => [\n  t('Settings.Privacy Settings.Watched Progress Saving Mode.Modes.Auto'),\n  t('Settings.Privacy Settings.Watched Progress Saving Mode.Modes.Semi-auto'),\n  t('Settings.Privacy Settings.Watched Progress Saving Mode.Modes.Never')\n])\n\n/** @type {import('vue').ComputedRef<'auto' | 'semi-auto' | 'never'>} */\nconst watchedProgressSavingMode = computed(() => store.getters.getWatchedProgressSavingMode)\n\n/**\n * @param {'auto' | 'semi-auto' | 'never'} value\n */\nfunction updateWatchedProgressSavingMode(value) {\n  store.dispatch('updateWatchedProgressSavingMode', value)\n}\n\nconst showSearchCachePrompt = ref(false)\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nfunction handleSearchCache(option) {\n  showSearchCachePrompt.value = false\n\n  if (option !== 'delete') { return }\n\n  store.dispatch('clearSessionSearchHistory')\n  store.dispatch('removeAllSearchHistoryEntries')\n  showToast(t('Settings.Privacy Settings.Search history and cache have been cleared'))\n}\n\nconst showRemoveHistoryPrompt = ref(false)\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nfunction handleRemoveHistory(option) {\n  showRemoveHistoryPrompt.value = false\n\n  if (option !== 'delete') { return }\n\n  store.dispatch('removeAllHistory')\n  showToast(t('Settings.Privacy Settings.Watch history has been cleared'))\n}\n\nconst showRemoveSubscriptionsPrompt = ref(false)\n\nconst profileList = computed(() => store.getters.getProfileList)\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nfunction handleRemoveSubscriptions(option) {\n  showRemoveSubscriptionsPrompt.value = false\n\n  if (option !== 'delete') { return }\n\n  store.dispatch('updateActiveProfile', MAIN_PROFILE_ID)\n\n  profileList.value.forEach((profile) => {\n    if (profile._id === MAIN_PROFILE_ID) {\n      const newProfile = {\n        _id: MAIN_PROFILE_ID,\n        name: profile.name,\n        bgColor: profile.bgColor,\n        textColor: profile.textColor,\n        subscriptions: []\n      }\n      store.dispatch('updateProfile', newProfile)\n    } else {\n      store.dispatch('removeProfile', profile._id)\n    }\n  })\n\n  store.dispatch('clearSubscriptionsCache')\n}\n\nconst showRemovePlaylistsPrompt = ref(false)\n\n/**\n * @param {'delete' | 'cancel' | null} option\n */\nfunction handleRemovePlaylists(option) {\n  showRemovePlaylistsPrompt.value = false\n\n  if (option !== 'delete') { return }\n\n  store.dispatch('removeAllPlaylists')\n  store.dispatch('updateQuickBookmarkTargetPlaylistId', 'favorites')\n  showToast(t('Settings.Privacy Settings.All playlists have been removed'))\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/ProxySettings/ProxySettings.css",
    "content": ".protocol-dropdown {\n  margin-block-end: 1rem;\n}\n\n.proxy-warning {\n  padding-block: 12px;\n  padding-inline: 4%;\n  background-color: var(--accent-color);\n  color: var(--text-with-accent-color);\n  font-weight: bold;\n}\n\n.warning-icon {\n  font-size: large;\n}\n"
  },
  {
    "path": "src/renderer/components/ProxySettings/ProxySettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Proxy Settings.Proxy Settings')\"\n  >\n    <FtFlexBox class=\"settingsFlexStart500px\">\n      <p\n        v-if=\"useProxy\"\n        class=\"proxy-warning\"\n      >\n        <FontAwesomeIcon\n          :icon=\"['fas', 'circle-exclamation']\"\n          class=\"warning-icon\"\n        />\n        {{ $t('Settings.Proxy Settings.Proxy Warning') }}\n      </p>\n      <FtToggleSwitch\n        :label=\"$t('Settings.Proxy Settings.Enable Tor / Proxy')\"\n        :default-value=\"useProxy\"\n        @change=\"handleUpdateProxy\"\n      />\n    </FtFlexBox>\n    <template\n      v-if=\"useProxy\"\n    >\n      <FtFlexBox>\n        <FtSelect\n          :placeholder=\"$t('Settings.Proxy Settings.Proxy Protocol')\"\n          :value=\"proxyProtocol\"\n          :select-names=\"PROTOCOL_NAMES\"\n          :select-values=\"PROTOCOL_VALUES\"\n          class=\"protocol-dropdown\"\n          :icon=\"['fas', 'network-wired']\"\n          @change=\"handleUpdateProxyProtocol\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <FtInput\n          :placeholder=\"$t('Settings.Proxy Settings.Proxy Host')\"\n          :show-action-button=\"false\"\n          show-label\n          :value=\"proxyHostname\"\n          @input=\"handleUpdateProxyHostname\"\n          @keydown.enter=\"testProxy\"\n        />\n        <FtInput\n          :placeholder=\"$t('Settings.Proxy Settings.Proxy Port Number')\"\n          :show-action-button=\"false\"\n          show-label\n          :value=\"proxyPort\"\n          :maxlength=\"5\"\n          @input=\"handleUpdateProxyPort\"\n          @keydown.enter=\"testProxy\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <FtInput\n          :placeholder=\"$t('Settings.Proxy Settings.Proxy Username')\"\n          :show-action-button=\"false\"\n          show-label\n          :value=\"proxyUsername\"\n          @input=\"handleUpdateProxyUsername\"\n          @keydown.enter=\"testProxy\"\n        />\n        <FtInput\n          :placeholder=\"$t('Settings.Proxy Settings.Proxy Password')\"\n          :show-action-button=\"false\"\n          show-label\n          :value=\"proxyPassword\"\n          input-type=\"password\"\n          @input=\"handleUpdateProxyPassword\"\n          @keydown.enter=\"testProxy\"\n        />\n      </FtFlexBox>\n      <p\n        class=\"center\"\n      >\n        {{ $t('Settings.Proxy Settings.Clicking on Test Proxy will send a request to') }} {{ proxyTestUrl }}\n      </p>\n      <FtFlexBox>\n        <FtButton\n          :label=\"$t('Settings.Proxy Settings.Test Proxy')\"\n          @click=\"testProxy\"\n        />\n      </FtFlexBox>\n      <FtLoader\n        v-if=\"isLoading\"\n      />\n      <div\n        v-if=\"!isLoading && dataAvailable\"\n        class=\"center\"\n      >\n        <h3>\n          {{ $t('Settings.Proxy Settings.Your Info') }}\n        </h3>\n        <p>\n          {{ $t('Display Label', { label: $t('Settings.Proxy Settings.Ip'), value: proxyIp }) }}\n        </p>\n        <p>\n          {{ $t('Display Label', { label: $t('Settings.Proxy Settings.Country'), value: proxyCountry }) }}\n        </p>\n        <p>\n          {{ $t('Display Label', { label: $t('Settings.Proxy Settings.Region'), value: proxyRegion }) }}\n        </p>\n        <p>\n          {{ $t('Display Label', { label: $t('Settings.Proxy Settings.City'), value: proxyCity }) }}\n        </p>\n      </div>\n    </template>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onBeforeUnmount, ref } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtSelect from '../FtSelect/FtSelect.vue'\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtLoader from '../FtLoader/FtLoader.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\n\nimport store from '../../store/index'\n\nimport { debounce, showToast } from '../../helpers/utils'\n\nconst { locale, t } = useI18n()\n\nconst PROTOCOL_NAMES = [\n  'HTTP',\n  'HTTPS',\n  'SOCKS4',\n  'SOCKS5'\n]\n\nconst PROTOCOL_VALUES = [\n  'http',\n  'https',\n  'socks4',\n  'socks5'\n]\n\nconst isLoading = ref(false)\nconst dataAvailable = ref(false)\nconst proxyIp = ref('')\nconst proxyCountry = ref('')\nconst proxyRegion = ref('')\nconst proxyCity = ref('')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useProxy = computed(() => {\n  return store.getters.getUseProxy\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst proxyProtocol = computed(() => {\n  return store.getters.getProxyProtocol\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst proxyHostname = computed(() => {\n  return store.getters.getProxyHostname\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst proxyPort = computed(() => {\n  return store.getters.getProxyPort\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst proxyUsername = computed(() => {\n  return store.getters.getProxyUsername\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst proxyPassword = computed(() => {\n  return store.getters.getProxyPassword\n})\n\nconst proxyUrl = computed(() => {\n  return `${proxyProtocol.value}://${proxyHostname.value}:${proxyPort.value}`\n})\n\n// locales found here: https://ipwhois.io/documentation\nconst SUPPORTED_LANGS = ['en', 'ru', 'de', 'es', 'pt-BR', 'fr', 'zh-CN', 'ja']\n\nconst localeToUse = computed(() => {\n  const freeTubeLang = locale.value\n\n  return SUPPORTED_LANGS.find(lang => freeTubeLang === lang) ?? SUPPORTED_LANGS.find(lang => freeTubeLang.slice(0, 2) === lang.slice(0, 2))\n})\n\nconst proxyTestUrl = computed(() => {\n  let proxyTestUrl = 'https://ipwho.is/?output=json&fields=ip,country,city,region'\n\n  if (localeToUse.value) {\n    proxyTestUrl += `&lang=${localeToUse.value}`\n  }\n\n  return proxyTestUrl\n})\n\n/**\n * @param {boolean} enabled\n */\nfunction handleUpdateProxy(enabled) {\n  if (enabled) {\n    enableProxy()\n  } else {\n    disableProxy()\n  }\n\n  store.dispatch('updateUseProxy', enabled)\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateProxyProtocol(value) {\n  if (useProxy.value) {\n    enableProxy()\n  }\n\n  store.dispatch('updateProxyProtocol', value)\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateProxyHostname(value) {\n  if (useProxy.value) {\n    debouncedEnableProxy()\n  }\n\n  store.dispatch('updateProxyHostname', value)\n}\n\nonBeforeUnmount(() => {\n  if (proxyHostname.value === '') {\n    store.dispatch('updateProxyHostname', '127.0.0.1')\n  }\n\n  if (proxyPort.value === '') {\n    store.dispatch('updateProxyPort', '9050')\n  }\n})\n\n/**\n * @param {string} value\n */\nfunction handleUpdateProxyPort(value) {\n  if (useProxy.value) {\n    debouncedEnableProxy()\n  }\n\n  store.dispatch('updateProxyPort', value)\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateProxyUsername(value) {\n  if (useProxy.value) {\n    debouncedEnableProxy()\n  }\n\n  store.dispatch('updateProxyUsername', value)\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateProxyPassword(value) {\n  if (useProxy.value) {\n    debouncedEnableProxy()\n  }\n\n  store.dispatch('updateProxyPassword', value)\n}\n\nfunction enableProxy() {\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.enableProxy(proxyUrl.value)\n  }\n}\n\nconst debouncedEnableProxy = debounce(enableProxy, 200)\n\nfunction disableProxy() {\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.disableProxy()\n  }\n\n  dataAvailable.value = false\n  proxyIp.value = ''\n  proxyCountry.value = ''\n  proxyRegion.value = ''\n  proxyCity.value = ''\n}\n\nasync function testProxy() {\n  isLoading.value = true\n\n  if (!useProxy.value) {\n    enableProxy()\n  }\n\n  try {\n    const response = await fetch(proxyTestUrl.value)\n    const json = await response.json()\n\n    proxyIp.value = json.ip\n    proxyCountry.value = json.country\n    proxyRegion.value = json.region\n    proxyCity.value = json.city\n    dataAvailable.value = true\n  } catch (error) {\n    console.error('errored while testing proxy:', error)\n    showToast(t('Settings.Proxy Settings[\"Error getting network information. Is your proxy configured properly?\"]'))\n    dataAvailable.value = false\n  } finally {\n    if (!useProxy.value) {\n      disableProxy()\n    }\n\n    isLoading.value = false\n  }\n}\n</script>\n\n<style scoped src=\"./ProxySettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/SideNav/SideNav.css",
    "content": ".sideNav {\n  display: block;\n  block-size: calc(100vh - 60px);\n  inline-size: 200px;\n  overflow-x: hidden;\n  position: sticky;\n  inset-inline-start: 0;\n  inset-block-start: 60px;\n  z-index: 3;\n  box-shadow: 1px -1px 1px -1px var(--primary-shadow-color);\n  background-color: var(--side-nav-color);\n  transition-property: inline-size;\n  transition-duration: 150ms;\n  transition-timing-function: ease-in-out;\n  user-select: none;\n}\n\n.inner {\n  block-size: 100%;\n  inline-size: 200px;\n  overflow: hidden auto;\n}\n\n.closed .inner {\n  inline-size: 80px;\n}\n\n.closed .hiddenLabels {\n  inline-size: 60px;\n}\n\n.closed.hiddenLabels {\n  inline-size: 60px;\n}\n\n.topNavOption {\n  margin-block-start: 10px;\n}\n\n.navOption,\n.navChannel {\n  position: relative;\n  padding: 5px;\n  min-block-size: 35px;\n}\n\n.navOption {\n  -webkit-user-drag: none;\n}\n\n.moreOption {\n  display: none;\n}\n\n.navOption,\n.channelLink {\n  display: block;\n  color: inherit;\n  text-decoration: inherit;\n}\n\n\n.navOption .navLabel {\n  margin-inline-start: 40px;\n  overflow: hidden;\n  overflow-wrap: break-word;\n}\n\n.navOption:hover,\n.navChannel:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.navOption:active,\n.navChannel:active {\n  background-color: var(--side-nav-active-color);\n  color: var(--side-nav-active-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.navIcon {\n  block-size: 1em;\n  inline-size: 1.25em;\n  margin-inline-start: 10px;\n}\n\n.navIcon.fa-user-check {\n  /* This icon is too big by default */\n  inline-size: 1em;\n\n  /* Align icon according to torso */\n  transform: translateX(0.2em);\n}\n\n.navChannel .navLabel {\n  overflow: hidden;\n  /* stylelint-disable-next-line liberty/use-logical-spec */\n  margin-left: 40px;\n  overflow-wrap: break-word;\n  font-size: 12px;\n}\n\n/* stylelint-disable liberty/use-logical-spec */\n:global(body[dir='rtl'] .navChannel .navLabel) {\n  margin-left: initial;\n  margin-right: 40px;\n}\n/* stylelint-enable liberty/use-logical-spec */\n\n.thumbnailContainer {\n  inline-size: 35px;\n  margin: 0;\n  position: absolute;\n  inset-block-start: 50%;\n  transform: translateY(-50%);\n  text-align: center;\n}\n\n.channelThumbnail {\n  border-radius: 50%;\n  vertical-align: middle;\n}\n\n.noThumbnail {\n  /* font-size is used for font-icon */\n  font-size: 35px;\n}\n\n.closed {\n  inline-size: 80px;\n}\n\n.sideNav hr {\n  inline-size: 90%;\n  block-size: 1px;\n  border: 0;\n  background-color: var(--primary-color);\n}\n\n.refreshIcon {\n  position: absolute;\n  inset-block-start: 20px;\n  inset-inline-end: 20px;\n}\n\n.closed .refreshIcon {\n  display: none;\n}\n\n.closed .navOption {\n  inline-size: 100%;\n  padding-block: 5px;\n  padding-inline: 0;\n}\n\n.closed .navIcon {\n  margin-inline-start: 0;\n  inline-size: 100%;\n  display: block;\n  margin-block-end: 0;\n}\n\n.closed .navIconExpand {\n  block-size: 1.3em;\n}\n\n.closed .navIconExpand.fa-user-check {\n  /* This icon is too big by default */\n  block-size: 1.15em;\n}\n\n.closed .navLabel {\n  margin-inline: 0;\n  inline-size: 100%;\n  text-align: center;\n  inset-inline-start: 0;\n  font-size: 11px;\n  margin-block-end: 0;\n}\n\n.closed .navChannel {\n  inline-size: 100%;\n  block-size: 45px;\n  padding-block: 5px;\n  padding-inline: 0;\n}\n\n.closed .thumbnailContainer {\n  position: static;\n  display: block;\n  float: none;\n  margin-inline: auto;\n  inset-block-start: 0;\n  transform: none;\n  margin-block: 0.3em;\n}\n\n@media only screen and (width > 680px) {\n  ::-webkit-scrollbar {\n    inline-size: 10px;\n    block-size: 10px;\n  }\n}\n\n@media only screen and (width <= 680px) {\n  .inner {\n    display: contents; /* sunglasses emoji */\n  }\n\n  hr,\n  .mobileHidden,\n  .refreshIcon {\n    display: none;\n  }\n\n  .sideNav {\n    position: fixed;\n    inset-inline-start: 0;\n    inset-block-end: 0;\n    display: flex;\n  }\n\n  .topNavOption {\n    margin-block-start: 0;\n    padding-inline: 10px;\n  }\n\n  .sideNav,\n  .closed {\n    margin-block-start: 0;\n    block-size: 60px;\n    inline-size: 100%;\n    inset-block: auto 0;\n    overflow-y: hidden;\n  }\n\n  .navOption,\n  .closed .navOption {\n    inline-size: 70px;\n    block-size: 40px;\n    padding: 0;\n    padding-block: 10px;\n  }\n\n  .navLabel {\n    margin-inline: 0;\n    inline-size: 100%;\n    text-align: center;\n    inset-inline-start: 0;\n    font-size: 11px;\n  }\n\n  .moreOption {\n    display: block;\n  }\n\n  .closed.hiddenLabels {\n    inline-size: 100%;\n  }\n}\n\n@media only screen and (width <= 400px) {\n  /* Hide settings so that they appear in the more dropdown on smaller screens */\n  .smallMobileOnlyHidden {\n    display: none;\n  }\n}\n\n@media only screen and (width > 400px) {\n  .smallMobileOnlyHidden {\n    display: block;\n  }\n}\n\n"
  },
  {
    "path": "src/renderer/components/SideNav/SideNav.vue",
    "content": "<template>\n  <FtFlexBox\n    class=\"sideNav\"\n    :class=\"[{closed: !isOpen}, applyHiddenLabels]\"\n    role=\"navigation\"\n  >\n    <div\n      class=\"inner\"\n      :class=\"applyHiddenLabels\"\n    >\n      <router-link\n        class=\"navOption topNavOption mobileShow \"\n        role=\"button\"\n        to=\"/subscriptions\"\n        :title=\"$t('Subscriptions.Subscriptions')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'rss']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Subscriptions.Subscriptions\") }}\n        </p>\n      </router-link>\n      <router-link\n        class=\"navOption mobileHidden\"\n        role=\"button\"\n        to=\"/subscribedchannels\"\n        :title=\"$t('Channels.Channels')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'user-check']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Channels.Channels\") }}\n        </p>\n      </router-link>\n      <router-link\n        v-if=\"SUPPORTS_LOCAL_API && !hideTrendingVideos && (backendFallback || backendPreference === 'local')\"\n        class=\"navOption mobileHidden\"\n        role=\"button\"\n        to=\"/trending\"\n        :title=\"$t('Trending.Trending')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'fire']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Trending.Trending\") }}\n        </p>\n      </router-link>\n      <router-link\n        v-if=\"!hidePopularVideos && (backendFallback || backendPreference === 'invidious')\"\n        class=\"navOption mobileHidden\"\n        role=\"button\"\n        to=\"/popular\"\n        :title=\"$t('Most Popular')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'users']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Most Popular\") }}\n        </p>\n      </router-link>\n      <router-link\n        v-if=\"!hidePlaylists\"\n        class=\"navOption mobileShow\"\n        role=\"button\"\n        to=\"/userplaylists\"\n        :title=\"$t('Playlists')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'bookmark']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Playlists\") }}\n        </p>\n      </router-link>\n      <SideNavMoreOptions />\n      <router-link\n        class=\"navOption mobileShow\"\n        role=\"button\"\n        to=\"/history\"\n        :title=\"historyTitle\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'history']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"History.History\") }}\n        </p>\n      </router-link>\n      <hr>\n      <router-link\n        class=\"navOption mobileShow smallMobileOnlyHidden\"\n        role=\"button\"\n        to=\"/settings\"\n        :title=\"settingsTitle\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'sliders-h']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t('Settings.Settings') }}\n        </p>\n      </router-link>\n      <router-link\n        class=\"navOption mobileHidden\"\n        role=\"button\"\n        to=\"/about\"\n        :title=\"$t('About.About')\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'info-circle']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideText\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"About.About\") }}\n        </p>\n      </router-link>\n      <hr>\n      <div\n        v-if=\"!hideActiveSubscriptions\"\n        class=\"mobileHidden\"\n      >\n        <router-link\n          v-for=\"channel in activeSubscriptions\"\n          :key=\"channel.id\"\n          :to=\"`/channel/${channel.id}`\"\n          class=\"navChannel channelLink mobileHidden\"\n          :title=\"channel.name\"\n          role=\"button\"\n        >\n          <div\n            class=\"thumbnailContainer\"\n          >\n            <img\n              v-if=\"channel.thumbnail != null\"\n              class=\"channelThumbnail\"\n              height=\"35\"\n              width=\"35\"\n              loading=\"lazy\"\n              :src=\"channel.thumbnail\"\n              :alt=\"isOpen ? '' : channel.name\"\n            >\n            <FontAwesomeIcon\n              v-else\n              class=\"channelThumbnail noThumbnail\"\n              :icon=\"['fas', 'circle-user']\"\n            />\n          </div>\n          <p\n            v-if=\"isOpen\"\n            class=\"navLabel\"\n            dir=\"auto\"\n          >\n            {{ channel.name }}\n          </p>\n        </router-link>\n      </div>\n    </div>\n  </FtFlexBox>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport SideNavMoreOptions from '../SideNavMoreOptions/SideNavMoreOptions.vue'\n\nimport store from '../../store/index'\n\nimport { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\nimport { deepCopy, localizeAndAddKeyboardShortcutToActionTitle } from '../../helpers/utils'\nimport { KeyboardShortcuts } from '../../../constants'\n\nconst { locale, t } = useI18n()\n\nconst SUPPORTS_LOCAL_API = process.env.SUPPORTS_LOCAL_API\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isOpen = computed(() => {\n  return store.getters.getIsSideNavOpen\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => {\n  return store.getters.getBackendFallback\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\n/** @type {import('vue').ComputedRef<object>} */\nconst activeProfile = computed(() => {\n  return store.getters.getActiveProfile\n})\n\nconst activeSubscriptions = computed(() => {\n  /** @type {any[]} */\n  const subscriptions = deepCopy(activeProfile.value.subscriptions)\n\n  subscriptions.forEach(channel => {\n    // Change thumbnail size to 35x35, as that's the size we display it\n    // so we don't need to download a bigger image (the default is 176x176)\n    channel.thumbnail = channel.thumbnail?.replace(/=s\\d+/, '=s35')\n  })\n\n  const locale_ = locale.value\n  subscriptions.sort((a, b) => {\n    return a.name?.toLowerCase().localeCompare(b.name?.toLowerCase(), locale_)\n  })\n\n  if (backendPreference.value === 'invidious') {\n    const instanceUrl = currentInvidiousInstanceUrl.value\n\n    subscriptions.forEach((channel) => {\n      channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, instanceUrl)\n    })\n  }\n\n  return subscriptions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePopularVideos = computed(() => {\n  return store.getters.getHidePopularVideos\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hidePlaylists = computed(() => {\n  return store.getters.getHidePlaylists\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideTrendingVideos = computed(() => {\n  return store.getters.getHideTrendingVideos\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideActiveSubscriptions = computed(() => {\n  return store.getters.getHideActiveSubscriptions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideText = computed(() => {\n  return !isOpen.value && store.getters.getHideLabelsSideBar\n})\n\nconst applyNavIconExpand = computed(() => {\n  return {\n    navIconExpand: hideText.value\n  }\n})\n\nconst applyHiddenLabels = computed(() => {\n  return {\n    hiddenLabels: hideText.value\n  }\n})\n\nconst historyTitle = computed(() => {\n  const shortcut = process.platform === 'darwin'\n    ? KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_HISTORY_MAC\n    : KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_HISTORY\n\n  return localizeAndAddKeyboardShortcutToActionTitle(\n    t('History.History'),\n    shortcut\n  )\n})\n\nconst settingsTitle = computed(() => {\n  return localizeAndAddKeyboardShortcutToActionTitle(\n    t('Settings.Settings'),\n    KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_SETTINGS\n  )\n})\n</script>\n\n<style scoped src=\"./SideNav.css\" />\n"
  },
  {
    "path": "src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.css",
    "content": ".sideNavMoreOptions {\n  display: none;\n}\n\n.navOption {\n  position: relative;\n  padding: 5px;\n  cursor: pointer;\n  color: inherit;\n  text-decoration: none;\n  display: block;\n}\n\n.navOption:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.navOption:active {\n  background-color: var(--side-nav-active-color);\n  color: var(--side-nav-active-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.moreOptionContainer {\n  position: fixed;\n  background-color: var(--side-nav-color);\n  inset-block-end: 60px;\n  inline-size: 70px;\n  z-index: 0;\n  box-shadow: 3px -3px 5px 0 rgb(0 0 0 / 20%);\n}\n\n@media only screen and (width <= 680px) {\n  .sideNavMoreOptions {\n    display: block;\n  }\n\n  .sideNav,\n  .closed {\n    margin-block-start: 0;\n    block-size: 60px;\n    inline-size: 100%;\n    inset-block: auto 0;\n    overflow-y: inherit;\n  }\n\n  .navOption,\n  .closed .navOption {\n    inline-size: 70px;\n    block-size: 40px;\n    padding-block: 10px;\n    padding-inline: 0;\n  }\n\n  .navLabel {\n    margin-inline-start: 0;\n    inline-size: 100%;\n    text-align: center;\n    inset-inline-start: 0;\n    font-size: 11px;\n  }\n\n  .navIcon {\n    margin-inline-start: 0;\n    inline-size: 100%;\n    display: block;\n    margin-block-start: 0.5em;\n  }\n\n  .navIcon.fa-user-check {\n    /* Align icon according to torso */\n    transform: translateX(0.2em);\n  }\n\n  .moreOption {\n    display: block;\n  }\n\n  .closed .navIconExpand {\n    block-size: 1.3em;\n  }\n}\n\n@media only screen and (width <= 400px) {\n  /* Show settings in more dropdown on smaller screens */\n  .smallMobileOnlyShow {\n    display: block;\n  }\n}\n\n@media only screen and (width > 400px) {\n  .smallMobileOnlyShow {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.vue",
    "content": "<template>\n  <div\n    ref=\"menuRef\"\n    class=\"sideNavMoreOptions\"\n  >\n    <div\n      class=\"navOption moreOptionNav\"\n      tabindex=\"0\"\n      role=\"button\"\n      aria-labelledby=\"moreNavLabel\"\n      :title=\"$t('More')\"\n      @click=\"openMoreOptions = !openMoreOptions\"\n      @keydown.space.prevent=\"openMoreOptions = !openMoreOptions\"\n      @keydown.enter.prevent=\"openMoreOptions = !openMoreOptions\"\n    >\n      <FontAwesomeIcon\n        :icon=\"['fas', 'ellipsis-h']\"\n        class=\"navIcon\"\n        :class=\"applyNavIconExpand\"\n      />\n      <p\n        v-if=\"!hideLabelsSideBar\"\n        id=\"moreNavLabel\"\n        class=\"navLabel\"\n      >\n        {{ $t(\"More\") }}\n      </p>\n    </div>\n    <div\n      v-if=\"openMoreOptions\"\n      class=\"moreOptionContainer\"\n    >\n      <router-link\n        class=\"navOption mobileHidden\"\n        :title=\"$t('Channels.Channels')\"\n        :aria-label=\"hideLabelsSideBar ? $t('Channels.Channels') : null\"\n        to=\"/subscribedchannels\"\n        @click=\"closeMenu\"\n      >\n        <div\n          class=\"thumbnailContainer\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'user-check']\"\n            class=\"navIcon\"\n            :class=\"applyNavIconExpand\"\n          />\n        </div>\n        <p\n          v-if=\"!hideLabelsSideBar\"\n          id=\"channelLabel\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Channels.Channels\") }}\n        </p>\n      </router-link>\n      <router-link\n        v-if=\" SUPPORTS_LOCAL_API && trendingVisible\"\n        class=\"navOption\"\n        :title=\"$t('Trending.Trending')\"\n        :aria-label=\"hideLabelsSideBar ? $t('Trending.Trending') : null\"\n        to=\"/trending\"\n        @click=\"closeMenu\"\n      >\n        <FontAwesomeIcon\n          :icon=\"['fas', 'fire']\"\n          class=\"navIcon\"\n          :class=\"applyNavIconExpand\"\n        />\n        <p\n          v-if=\"!hideLabelsSideBar\"\n          id=\"trendingNavLabel\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Trending.Trending\") }}\n        </p>\n      </router-link>\n      <router-link\n        v-if=\"popularVisible\"\n        class=\"navOption\"\n        :title=\"$t('Most Popular')\"\n        :aria-label=\"hideLabelsSideBar ? $t('Most Popular') : null\"\n        to=\"/popular\"\n        @click=\"closeMenu\"\n      >\n        <FontAwesomeIcon\n          :icon=\"['fas', 'users']\"\n          class=\"navIcon\"\n          :class=\"applyNavIconExpand\"\n        />\n        <p\n          v-if=\"!hideLabelsSideBar\"\n          id=\"mostPopularNavLabel\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Most Popular\") }}\n        </p>\n      </router-link>\n      <router-link\n        class=\"navOption\"\n        :title=\"$t('About.About')\"\n        :aria-label=\"hideLabelsSideBar ? $t('About.About') : null\"\n        to=\"/about\"\n        @click=\"closeMenu\"\n      >\n        <FontAwesomeIcon\n          :icon=\"['fas', 'info-circle']\"\n          class=\"navIcon\"\n          :class=\"applyNavIconExpand\"\n        />\n        <p\n          v-if=\"!hideLabelsSideBar\"\n          id=\"aboutNavLabel\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"About.About\") }}\n        </p>\n      </router-link>\n      <router-link\n        class=\"navOption smallMobileOnlyShow\"\n        :title=\"$t('Settings.Settings')\"\n        :aria-label=\"hideLabelsSideBar ? $t('Settings.Settings') : null\"\n        to=\"/settings\"\n        @click=\"closeMenu\"\n      >\n        <FontAwesomeIcon\n          :icon=\"['fas', 'sliders-h']\"\n          class=\"navIcon\"\n          :class=\"applyNavIconExpand\"\n        />\n        <p\n          id=\"settingsNavLabel\"\n          class=\"navLabel\"\n        >\n          {{ $t(\"Settings.Settings\") }}\n        </p>\n      </router-link>\n    </div>\n    <router-link\n      class=\"navOption mobileShow\"\n      :title=\"$t('History.History')\"\n      :aria-label=\"hideLabelsSideBar ? $t('History.History'): null\"\n      to=\"/history\"\n    >\n      <FontAwesomeIcon\n        :icon=\"['fas', 'history']\"\n        class=\"navIcon\"\n        :class=\"applyNavIconExpand\"\n      />\n      <p\n        id=\"historyNavLabel\"\n        class=\"navLabel\"\n      >\n        {{ $t(\"History.History\") }}\n      </p>\n    </router-link>\n    <hr>\n    <router-link\n      class=\"navOption mobileShow\"\n      :title=\"$t('Settings.Settings')\"\n      :aria-label=\"hideLabelsSideBar ? $t('Settings.Settings') : null\"\n      to=\"/settings\"\n    >\n      <FontAwesomeIcon\n        :icon=\"['fas', 'sliders-h']\"\n        class=\"navIcon\"\n        :class=\"applyNavIconExpand\"\n      />\n      <p\n        id=\"settingsNavLabel\"\n        class=\"navLabel\"\n      >\n        {{ $t(\"Settings.Settings\") }}\n      </p>\n    </router-link>\n    <router-link\n      class=\"navOption mobileHidden\"\n      :title=\"$t('About.About')\"\n      to=\"/about\"\n      :aria-label=\"hideLabelsSideBar ? $t('About.About') : null\"\n    >\n      <FontAwesomeIcon\n        :icon=\"['fas', 'info-circle']\"\n        class=\"navIcon\"\n        :class=\"applyNavIconExpand\"\n      />\n      <p\n        v-if=\"!hideLabelsSideBar\"\n        class=\"navLabel\"\n      >\n        {{ $t(\"About.About\") }}\n      </p>\n    </router-link>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, ref, onMounted, onBeforeUnmount, useTemplateRef } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport store from '../../store/index'\n\nconst SUPPORTS_LOCAL_API = process.env.SUPPORTS_LOCAL_API\n\nconst openMoreOptions = ref(false)\n\nconst menuRef = useTemplateRef('menuRef')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst trendingVisible = computed(() => {\n  return !store.getters.getHideTrendingVideos &&\n    (store.getters.getBackendFallback || store.getters.getBackendPreference === 'local')\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLabelsSideBar = computed(() => {\n  return store.getters.getHideLabelsSideBar\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst popularVisible = computed(() => {\n  return !store.getters.getHidePopularVideos &&\n    (store.getters.getBackendFallback || store.getters.getBackendPreference === 'invidious')\n})\n\nconst applyNavIconExpand = computed(() => {\n  return {\n    navIconExpand: hideLabelsSideBar.value\n  }\n})\n\nfunction closeMenu() {\n  openMoreOptions.value = false\n}\n\nfunction handleClickOutside(event) {\n  if (openMoreOptions.value && menuRef.value && !menuRef.value.contains(event.target)) {\n    closeMenu()\n  }\n}\n\nconst router = useRouter()\n\nonMounted(() => {\n  document.addEventListener('click', handleClickOutside)\n  router.afterEach(() => {\n    closeMenu()\n  })\n})\nonBeforeUnmount(() => {\n  document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<style scoped src=\"./SideNavMoreOptions.css\" />\n"
  },
  {
    "path": "src/renderer/components/SponsorBlockSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.SponsorBlock Settings.SponsorBlock Settings')\"\n  >\n    <FtFlexBox class=\"settingsFlexStart500px\">\n      <FtToggleSwitch\n        :label=\"$t('Settings.SponsorBlock Settings.Enable SponsorBlock')\"\n        :default-value=\"useSponsorBlock\"\n        @change=\"handleUpdateSponsorBlock\"\n      />\n      <FtToggleSwitch\n        :label=\"$t('Settings.SponsorBlock Settings.UseDeArrowTitles')\"\n        :default-value=\"useDeArrowTitles\"\n        :tooltip=\"$t('Tooltips.SponsorBlock Settings.UseDeArrowTitles')\"\n        @change=\"handleUpdateUseDeArrowTitles\"\n      />\n      <FtToggleSwitch\n        :label=\"$t('Settings.SponsorBlock Settings.UseDeArrowThumbnails')\"\n        :default-value=\"useDeArrowThumbnails\"\n        :tooltip=\"$t('Tooltips.SponsorBlock Settings.UseDeArrowThumbnails')\"\n        @change=\"handleUpdateUseDeArrowThumbnails\"\n      />\n    </FtFlexBox>\n    <template\n      v-if=\"useSponsorBlock || useDeArrowTitles || useDeArrowThumbnails\"\n    >\n      <FtFlexBox\n        v-if=\"useSponsorBlock\"\n        class=\"settingsFlexStart500px\"\n      >\n        <FtToggleSwitch\n          :label=\"$t('Settings.SponsorBlock Settings.Notify when sponsor segment is skipped')\"\n          :default-value=\"sponsorBlockShowSkippedToast\"\n          @change=\"handleUpdateSponsorBlockShowSkippedToast\"\n        />\n      </FtFlexBox>\n      <FtFlexBox>\n        <FtInput\n          :placeholder=\"$t('Settings.SponsorBlock Settings[\\'SponsorBlock API Url (Default is https://sponsor.ajay.app)\\']')\"\n          :show-action-button=\"false\"\n          :show-label=\"true\"\n          :value=\"sponsorBlockUrl\"\n          @input=\"handleUpdateSponsorBlockUrl\"\n        />\n      </FtFlexBox>\n      <FtFlexBox\n        v-if=\"useDeArrowThumbnails\"\n      >\n        <FtInput\n          v-if=\"useDeArrowThumbnails\"\n          :placeholder=\"$t('Settings.SponsorBlock Settings[\\'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)\\']')\"\n          :show-action-button=\"false\"\n          :show-label=\"true\"\n          :value=\"deArrowThumbnailGeneratorUrl\"\n          @input=\"handleUpdateDeArrowThumbnailGeneratorUrl\"\n        />\n      </FtFlexBox>\n\n      <FtFlexBox\n        v-if=\"useSponsorBlock\"\n      >\n        <FtSponsorBlockCategory\n          v-for=\"category in CATEGORIES\"\n          :key=\"category\"\n          :category-name=\"category\"\n        />\n      </FtFlexBox>\n    </template>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'\nimport FtToggleSwitch from './FtToggleSwitch/FtToggleSwitch.vue'\nimport FtInput from './FtInput/FtInput.vue'\nimport FtFlexBox from './ft-flex-box/ft-flex-box.vue'\nimport FtSponsorBlockCategory from './FtSponsorBlockCategory/FtSponsorBlockCategory.vue'\n\nimport store from '../store/index'\n\nconst CATEGORIES = [\n  'sponsor',\n  'self-promotion',\n  'interaction',\n  'intro',\n  'outro',\n  'recap',\n  'music offtopic',\n  'filler'\n]\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useSponsorBlock = computed(() => store.getters.getUseSponsorBlock)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst sponsorBlockUrl = computed(() => store.getters.getSponsorBlockUrl)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst sponsorBlockShowSkippedToast = computed(() => store.getters.getSponsorBlockShowSkippedToast)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useDeArrowTitles = computed(() => store.getters.getUseDeArrowTitles)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useDeArrowThumbnails = computed(() => store.getters.getUseDeArrowThumbnails)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst deArrowThumbnailGeneratorUrl = computed(() => store.getters.getDeArrowThumbnailGeneratorUrl)\n\n/**\n * @param {boolean} value\n */\nfunction handleUpdateSponsorBlock(value) {\n  store.dispatch('updateUseSponsorBlock', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction handleUpdateUseDeArrowTitles(value) {\n  store.dispatch('updateUseDeArrowTitles', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction handleUpdateUseDeArrowThumbnails(value) {\n  store.dispatch('updateUseDeArrowThumbnails', value)\n}\n\n/**\n * @param {boolean} value\n */\nfunction handleUpdateSponsorBlockShowSkippedToast(value) {\n  store.dispatch('updateSponsorBlockShowSkippedToast', value)\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateSponsorBlockUrl(value) {\n  store.dispatch('updateSponsorBlockUrl', cleanupUrl(value))\n}\n\n/**\n * @param {string} value\n */\nfunction handleUpdateDeArrowThumbnailGeneratorUrl(value) {\n  store.dispatch('updateDeArrowThumbnailGeneratorUrl', cleanupUrl(value))\n}\n\n/**\n * @param {string} url\n */\nfunction cleanupUrl(url) {\n  return url\n    .replace(/\\/$/, '')\n    .replace(/\\/api$/, '')\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/SubscriptionSettings/SubscriptionSettings.css",
    "content": ".onlyShowLatestFromChannelNumber {\n  inline-size: calc(100% - 44px);\n  padding-inline-start: 44px;\n}\n"
  },
  {
    "path": "src/renderer/components/SubscriptionSettings/SubscriptionSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Subscription Settings.Subscription Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Subscription Settings.Fetch Automatically')\"\n          :default-value=\"fetchSubscriptionsAutomatically\"\n          :tooltip=\"$t('Tooltips.Subscription Settings.Fetch Automatically')\"\n          compact\n          @change=\"updateFetchSubscriptionsAutomatically\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Subscription Settings.Fetch Feeds from RSS')\"\n          :default-value=\"useRssFeeds\"\n          :tooltip=\"$t('Tooltips.Subscription Settings.Fetch Feeds from RSS')\"\n          compact\n          @change=\"updateUseRssFeeds\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Subscription Settings.Confirm Before Unsubscribing')\"\n          :default-value=\"unsubscriptionPopupStatus\"\n          compact\n          @change=\"updateUnsubscriptionPopupStatus\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Subscription Settings.Limit the number of videos displayed for each channel')\"\n          :default-value=\"onlyShowLatestFromChannel\"\n          compact\n          @change=\"updateOnlyShowLatestFromChannel\"\n        />\n        <div class=\"onlyShowLatestFromChannelNumber\">\n          <FtSlider\n            :label=\"$t('Settings.Subscription Settings.To')\"\n            :default-value=\"onlyShowLatestFromChannelNumber\"\n            :disabled=\"!onlyShowLatestFromChannel\"\n            :min-value=\"1\"\n            :max-value=\"30\"\n            :step=\"1\"\n            @change=\"updateOnlyShowLatestFromChannelNumber\"\n          />\n        </div>\n      </div>\n    </div>\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\n\nimport FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'\nimport FtSlider from '../FtSlider/FtSlider.vue'\nimport FtToggleSwitch from '../FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../../store/index'\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => store.getters.getFetchSubscriptionsAutomatically)\n\n/**\n * @param {boolean} value\n */\nfunction updateFetchSubscriptionsAutomatically(value) {\n  store.dispatch('updateFetchSubscriptionsAutomatically', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useRssFeeds = computed(() => store.getters.getUseRssFeeds)\n\n/**\n * @param {boolean} value\n */\nfunction updateUseRssFeeds(value) {\n  store.dispatch('updateUseRssFeeds', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst unsubscriptionPopupStatus = computed(() => store.getters.getUnsubscriptionPopupStatus)\n\n/**\n * @param {boolean} value\n */\nfunction updateUnsubscriptionPopupStatus(value) {\n  store.dispatch('updateUnsubscriptionPopupStatus', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst onlyShowLatestFromChannel = computed(() => store.getters.getOnlyShowLatestFromChannel)\n\n/**\n * @param {boolean} value\n */\nfunction updateOnlyShowLatestFromChannel(value) {\n  store.dispatch('updateOnlyShowLatestFromChannel', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst onlyShowLatestFromChannelNumber = computed(() => store.getters.getOnlyShowLatestFromChannelNumber)\n\n/**\n * @param {number} value\n */\nfunction updateOnlyShowLatestFromChannelNumber(value) {\n  store.dispatch('updateOnlyShowLatestFromChannelNumber', value)\n}\n</script>\n\n<style scoped src=\"./SubscriptionSettings.css\" />\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsLive.vue",
    "content": "<template>\n  <SubscriptionsTabUi\n    :is-loading=\"isLoading\"\n    :video-list=\"videoList\"\n    :error-channels=\"errorChannels\"\n    :attempted-fetch=\"attemptedFetch\"\n    :last-refresh-timestamp=\"lastLiveRefreshTimestamp\"\n    :title=\"t('Global.Live')\"\n    @refresh=\"loadVideosForSubscriptionsFromRemote\"\n  />\n</template>\n\n<script setup>\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport SubscriptionsTabUi from './SubscriptionsTabUi/SubscriptionsTabUi.vue'\n\nimport store from '../store/index'\n\nimport {\n  getChannelPlaylistId,\n  copyToClipboard,\n  getRelativeTimeFromDate,\n  showToast\n} from '../helpers/utils'\nimport { getInvidiousChannelLive, invidiousFetch } from '../helpers/api/invidious'\nimport { getLocalChannelLiveStreams } from '../helpers/api/local'\nimport { parseYouTubeRSSFeed, updateVideoListAfterProcessing } from '../helpers/subscriptions'\n\nconst { t } = useI18n()\n\nconst isLoading = ref(true)\nconst videoList = shallowRef([])\nconst errorChannels = ref([])\nconst attemptedFetch = ref(false)\n/** @type {import('vue').Ref<number | null>} */\nconst lastRemoteRefreshSuccessTimestamp = ref(null)\n\nlet alreadyLoadedRemotely = false\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst subscriptionCacheReady = computed(() => store.getters.getSubscriptionCacheReady)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useRssFeeds = computed(() => store.getters.getUseRssFeeds)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => store.getters.getFetchSubscriptionsAutomatically)\n\nconst activeSubscriptionList = computed(() => store.getters.getActiveProfile.subscriptions)\n\nconst cacheEntriesForAllActiveProfileChannels = computed(() => {\n  const liveCache = store.getters.getLiveCache\n  const entries = []\n\n  activeSubscriptionList.value.forEach((channel) => {\n    const cacheEntry = liveCache[channel.id]\n\n    if (cacheEntry != null) {\n      entries.push(cacheEntry)\n    }\n  })\n\n  return entries\n})\n\nconst videoCacheForAllActiveProfileChannelsPresent = computed(() => {\n  if (\n    cacheEntriesForAllActiveProfileChannels.value.length === 0 ||\n    cacheEntriesForAllActiveProfileChannels.value.length < activeSubscriptionList.value.length\n  ) {\n    return false\n  }\n\n  return cacheEntriesForAllActiveProfileChannels.value.every((cacheEntry) => {\n    return cacheEntry.videos != null\n  })\n})\n\nconst lastLiveRefreshTimestamp = computed(() => {\n  // Cache is not ready when data is just loaded from remote\n  if (lastRemoteRefreshSuccessTimestamp.value) {\n    return getRelativeTimeFromDate(lastRemoteRefreshSuccessTimestamp.value, true)\n  }\n\n  if (\n    !videoCacheForAllActiveProfileChannelsPresent.value ||\n    cacheEntriesForAllActiveProfileChannels.value.length === 0\n  ) {\n    return ''\n  }\n\n  let minTimestamp = null\n  cacheEntriesForAllActiveProfileChannels.value.forEach((cacheEntry) => {\n    if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) {\n      minTimestamp = cacheEntry.timestamp\n    }\n  })\n\n  return getRelativeTimeFromDate(minTimestamp.getTime(), true)\n})\n\nwatch(activeSubscriptionList, () => {\n  lastRemoteRefreshSuccessTimestamp.value = null\n  isLoading.value = true\n  loadVideosFromCacheSometimes()\n}, { deep: true })\n\nif (!subscriptionCacheReady.value) {\n  watch(subscriptionCacheReady, () => {\n    if (!alreadyLoadedRemotely) {\n      loadVideosFromCacheSometimes()\n    }\n  })\n}\n\nonMounted(() => {\n  loadVideosFromRemoteFirstPerWindowSometimes()\n})\n\nfunction loadVideosFromRemoteFirstPerWindowSometimes() {\n  if (\n    !fetchSubscriptionsAutomatically.value ||\n    // Only auto fetch once per window\n    store.getters.getSubscriptionForLiveStreamsFirstAutoFetchRun\n  ) {\n    loadVideosFromCacheSometimes()\n    return\n  }\n\n  alreadyLoadedRemotely = true\n  loadVideosForSubscriptionsFromRemote()\n  store.commit('setSubscriptionForLiveStreamsFirstAutoFetchRun')\n}\n\nfunction loadVideosFromCacheSometimes() {\n  // Can only load reliably when cache ready\n  if (!subscriptionCacheReady.value) { return }\n\n  // This method is called on view visible\n  if (videoCacheForAllActiveProfileChannelsPresent.value) {\n    loadVideosFromCacheForAllActiveProfileChannels()\n    return\n  }\n\n  if (fetchSubscriptionsAutomatically.value) {\n    // `isLoading.value = false` is called inside `loadVideosForSubscriptionsFromRemote` when needed\n    loadVideosForSubscriptionsFromRemote()\n    return\n  }\n\n  // Auto fetch disabled, not enough cache for profile = show nothing\n  videoList.value = []\n  attemptedFetch.value = false\n  isLoading.value = false\n}\n\nfunction loadVideosFromCacheForAllActiveProfileChannels() {\n  const videoList_ = cacheEntriesForAllActiveProfileChannels.value.flatMap((cacheEntry) => {\n    return cacheEntry.videos\n  })\n\n  videoList.value = updateVideoListAfterProcessing(videoList_)\n  isLoading.value = false\n}\n\nasync function loadVideosForSubscriptionsFromRemote() {\n  if (activeSubscriptionList.value.length === 0) {\n    isLoading.value = false\n    videoList.value = []\n    return\n  }\n\n  const channelsToLoadFromRemote = activeSubscriptionList.value\n  let channelCount = 0\n  isLoading.value = true\n\n  let useRss = useRssFeeds.value\n  if (channelsToLoadFromRemote.length >= 125 && !useRss) {\n    showToast(\n      t('Subscriptions[\"This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting\"]'),\n      10000\n    )\n    useRss = true\n  }\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n  attemptedFetch.value = true\n\n  errorChannels.value = []\n  const subscriptionUpdates = []\n\n  const videoListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => {\n    let videos, name, thumbnailUrl\n\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      if (useRss) {\n        ({ videos, name, thumbnailUrl } = await getChannelLiveInvidiousRSS(channel))\n      } else {\n        ({ videos, name, thumbnailUrl } = await getChannelLiveInvidious(channel))\n      }\n    } else {\n      if (useRss) {\n        ({ videos, name, thumbnailUrl } = await getChannelLiveLocalRSS(channel))\n      } else {\n        ({ videos, name, thumbnailUrl } = await getChannelLiveLocal(channel))\n      }\n    }\n\n    channelCount++\n    const percentageComplete = (channelCount / channelsToLoadFromRemote.length) * 100\n    store.commit('setProgressBarPercentage', percentageComplete)\n\n    if (videos != null) {\n      store.dispatch('updateSubscriptionLiveCacheByChannel', {\n        channelId: channel.id,\n        videos: videos\n      })\n    }\n\n    if (name || thumbnailUrl) {\n      subscriptionUpdates.push({\n        channelId: channel.id,\n        channelName: name,\n        channelThumbnailUrl: thumbnailUrl\n      })\n    }\n\n    return videos ?? []\n  }))).flat()\n\n  videoList.value = updateVideoListAfterProcessing(videoListFromRemote)\n  isLoading.value = false\n  store.commit('setShowProgressBar', false)\n  lastRemoteRefreshSuccessTimestamp.value = Date.now()\n\n  store.dispatch('batchUpdateSubscriptionDetails', subscriptionUpdates)\n}\n\nasync function getChannelLiveLocal(channel, failedAttempts = 0) {\n  try {\n    const result = await getLocalChannelLiveStreams(channel.id)\n\n    if (result === null) {\n      errorChannels.value.push(channel)\n      return {\n        videos: []\n      }\n    }\n\n    return result\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelLiveLocalRSS(channel, failedAttempts + 1)\n      case 1:\n        if (backendFallback.value) {\n          showToast(t('Falling back to Invidious API'))\n          return await getChannelLiveInvidious(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelLiveLocalRSS(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelLiveLocalRSS(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'live', 'newest')\n  const feedUrl = `https://www.youtube.com/feeds/videos.xml?playlist_id=${playlistId}`\n\n  try {\n    const response = await fetch(feedUrl)\n\n    if (response.status === 403) {\n      return {\n        videos: null\n      }\n    }\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}`, {\n        method: 'HEAD'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return {\n        videos: []\n      }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelLiveLocal(channel, failedAttempts + 1)\n      case 1:\n        if (backendFallback.value) {\n          showToast(t('Falling back to Invidious API'))\n          return await getChannelLiveInvidiousRSS(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelLiveLocal(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelLiveInvidious(channel, failedAttempts = 0) {\n  try {\n    const result = await getInvidiousChannelLive(channel.id)\n\n    let name\n\n    if (result.videos.length > 0) {\n      name = result.videos.find(video => video.type === 'video' && video.author).author\n    }\n\n    return {\n      name,\n      videos: result.videos\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelLiveInvidiousRSS(channel, failedAttempts + 1)\n      case 1:\n        if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n          showToast(t('Falling back to Local API'))\n          return await getChannelLiveLocal(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelLiveInvidiousRSS(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelLiveInvidiousRSS(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'live', 'newest')\n  const feedUrl = `${currentInvidiousInstanceUrl.value}/feed/playlist/${playlistId}`\n\n  try {\n    const response = await invidiousFetch(feedUrl)\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`${currentInvidiousInstanceUrl.value}/feed/channel/${channel.id}`, {\n        method: 'GET'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return {\n        videos: []\n      }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelLiveInvidious(channel, failedAttempts + 1)\n      case 1:\n        if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n          showToast(t('Falling back to Local API'))\n          return await getChannelLiveLocalRSS(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelLiveInvidious(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsPosts.vue",
    "content": "<template>\n  <SubscriptionsTabUi\n    :is-loading=\"isLoading\"\n    :video-list=\"postList\"\n    :error-channels=\"errorChannels\"\n    :attempted-fetch=\"attemptedFetch\"\n    :is-community=\"true\"\n    :initial-data-limit=\"20\"\n    :last-refresh-timestamp=\"lastPostsRefreshTimestamp\"\n    :title=\"t('Global.Posts')\"\n    @refresh=\"loadPostsForSubscriptionsFromRemote\"\n  />\n</template>\n\n<script setup>\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport SubscriptionsTabUi from './SubscriptionsTabUi/SubscriptionsTabUi.vue'\n\nimport store from '../store/index'\n\nimport { copyToClipboard, getRelativeTimeFromDate, showToast } from '../helpers/utils'\nimport { getLocalChannelCommunity } from '../helpers/api/local'\nimport { invidiousGetCommunityPosts } from '../helpers/api/invidious'\n\nconst { t } = useI18n()\n\nconst isLoading = ref(true)\nconst postList = shallowRef([])\nconst errorChannels = ref([])\nconst attemptedFetch = ref(false)\n/** @type {import('vue').Ref<number | null>} */\nconst lastRemoteRefreshSuccessTimestamp = ref(null)\n\nlet alreadyLoadedRemotely = false\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst subscriptionCacheReady = computed(() => store.getters.getSubscriptionCacheReady)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => store.getters.getFetchSubscriptionsAutomatically)\n\nconst activeSubscriptionList = computed(() => store.getters.getActiveProfile.subscriptions)\n\nconst cacheEntriesForAllActiveProfileChannels = computed(() => {\n  const postsCache = store.getters.getPostsCache\n  const entries = []\n\n  activeSubscriptionList.value.forEach((channel) => {\n    const cacheEntry = postsCache[channel.id]\n\n    if (cacheEntry != null) {\n      entries.push(cacheEntry)\n    }\n  })\n\n  return entries\n})\n\nconst postCacheForAllActiveProfileChannelsPresent = computed(() => {\n  if (\n    cacheEntriesForAllActiveProfileChannels.value.length === 0 ||\n    cacheEntriesForAllActiveProfileChannels.value.length < activeSubscriptionList.value.length\n  ) {\n    return false\n  }\n\n  return cacheEntriesForAllActiveProfileChannels.value.every((cacheEntry) => {\n    return cacheEntry.posts != null\n  })\n})\n\nconst lastPostsRefreshTimestamp = computed(() => {\n  // Cache is not ready when data is just loaded from remote\n  if (lastRemoteRefreshSuccessTimestamp.value) {\n    return getRelativeTimeFromDate(lastRemoteRefreshSuccessTimestamp.value, true)\n  }\n\n  if (\n    !postCacheForAllActiveProfileChannelsPresent.value ||\n    cacheEntriesForAllActiveProfileChannels.value.length === 0\n  ) {\n    return ''\n  }\n\n  let minTimestamp = null\n  cacheEntriesForAllActiveProfileChannels.value.forEach((cacheEntry) => {\n    if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) {\n      minTimestamp = cacheEntry.timestamp\n    }\n  })\n\n  return getRelativeTimeFromDate(minTimestamp.getTime(), true)\n})\n\nwatch(activeSubscriptionList, () => {\n  lastRemoteRefreshSuccessTimestamp.value = null\n  isLoading.value = true\n  loadPostsFromCacheSometimes()\n}, { deep: true })\n\nif (!subscriptionCacheReady.value) {\n  watch(subscriptionCacheReady, () => {\n    if (!alreadyLoadedRemotely) {\n      loadPostsFromCacheSometimes()\n    }\n  })\n}\n\nonMounted(() => {\n  loadPostsFromRemoteFirstPerWindowSometimes()\n})\n\nfunction loadPostsFromRemoteFirstPerWindowSometimes() {\n  if (\n    !fetchSubscriptionsAutomatically.value ||\n    // Only auto fetch once per window\n    store.getters.getSubscriptionForPostsFirstAutoFetchRun\n  ) {\n    loadPostsFromCacheSometimes()\n    return\n  }\n\n  alreadyLoadedRemotely = true\n  loadPostsForSubscriptionsFromRemote()\n  store.commit('setSubscriptionForPostsFirstAutoFetchRun')\n}\n\nfunction loadPostsFromCacheSometimes() {\n  // Can only load reliably when cache ready\n  if (!subscriptionCacheReady.value) { return }\n\n  // This method is called on view visible\n  if (postCacheForAllActiveProfileChannelsPresent.value) {\n    loadPostsFromCacheForAllActiveProfileChannels()\n    return\n  }\n\n  if (fetchSubscriptionsAutomatically.value) {\n    // `isLoading.value = false` is called inside `loadPostsForSubscriptionsFromRemote` when needed\n    loadPostsForSubscriptionsFromRemote()\n    return\n  }\n\n  // Auto fetch disabled, not enough cache for profile = show nothing\n  postList.value = []\n  attemptedFetch.value = false\n  isLoading.value = false\n}\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst forbiddenTitles = computed(() => {\n  return JSON.parse(store.getters.getForbiddenTitles.toLowerCase())\n})\n\nfunction loadPostsFromCacheForAllActiveProfileChannels() {\n  const postList_ = cacheEntriesForAllActiveProfileChannels.value.flatMap((cacheEntry) => {\n    return cacheEntry.posts\n  })\n\n  postList_.sort((a, b) => {\n    return b.publishedTime - a.publishedTime\n  })\n\n  postList.value = postList_.filter(post => !forbiddenTitles.value.some(text => post.author.toLowerCase().includes(text)))\n  isLoading.value = false\n}\n\nasync function loadPostsForSubscriptionsFromRemote() {\n  if (activeSubscriptionList.value.length === 0) {\n    isLoading.value = false\n    postList.value = []\n    return\n  }\n\n  const channelsToLoadFromRemote = activeSubscriptionList.value\n  let channelCount = 0\n  isLoading.value = true\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n  attemptedFetch.value = true\n\n  errorChannels.value = []\n  const subscriptionUpdates = []\n\n  const postListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => {\n    let posts\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      posts = await getChannelPostsInvidious(channel)\n    } else {\n      posts = await getChannelPostsLocal(channel)\n    }\n\n    channelCount++\n    const percentageComplete = (channelCount / channelsToLoadFromRemote.length) * 100\n    store.commit('setProgressBarPercentage', percentageComplete)\n\n    store.dispatch('updateSubscriptionPostsCacheByChannel', {\n      channelId: channel.id,\n      posts\n    })\n\n    if (posts.length > 0) {\n      const post = posts.find(post => post.authorId === channel.id)\n\n      if (post) {\n        const name = post.author\n        let thumbnailUrl = post.authorThumbnails?.[0]?.url\n\n        if (name || thumbnailUrl) {\n          if (thumbnailUrl?.startsWith('//')) {\n            thumbnailUrl = 'https:' + thumbnailUrl\n          }\n\n          subscriptionUpdates.push({\n            channelId: channel.id,\n            channelName: name,\n            channelThumbnailUrl: thumbnailUrl\n          })\n        }\n      }\n    }\n\n    posts = posts.filter(post => !forbiddenTitles.value.some(text => post.author.toLowerCase().includes(text)))\n    return posts\n  }))).flat()\n\n  postListFromRemote.sort((a, b) => {\n    return b.publishedTime - a.publishedTime\n  })\n\n  postList.value = postListFromRemote\n  isLoading.value = false\n  store.commit('setShowProgressBar', false)\n  lastRemoteRefreshSuccessTimestamp.value = Date.now()\n\n  store.dispatch('batchUpdateSubscriptionDetails', subscriptionUpdates)\n}\n\nasync function getChannelPostsLocal(channel) {\n  try {\n    const entries = await getLocalChannelCommunity(channel.id)\n\n    if (entries === null) {\n      errorChannels.value.push(channel)\n      return []\n    }\n\n    return entries\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      return await getChannelPostsInvidious(channel)\n    }\n\n    return []\n  }\n}\n\nasync function getChannelPostsInvidious(channel) {\n  try {\n    const result = await invidiousGetCommunityPosts(channel.id)\n\n    return result.posts\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      return await getChannelPostsLocal(channel)\n    } else {\n      return []\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsShorts.vue",
    "content": "<template>\n  <SubscriptionsTabUi\n    :is-loading=\"isLoading\"\n    :video-list=\"videoList\"\n    :error-channels=\"errorChannels\"\n    :attempted-fetch=\"attemptedFetch\"\n    :last-refresh-timestamp=\"lastShortRefreshTimestamp\"\n    :title=\"t('Global.Shorts')\"\n    @refresh=\"loadVideosForSubscriptionsFromRemote\"\n  />\n</template>\n\n<script setup>\nimport { computed, shallowRef, ref, watch, onMounted } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport SubscriptionsTabUi from './SubscriptionsTabUi/SubscriptionsTabUi.vue'\n\nimport store from '../store/index'\n\nimport { parseYouTubeRSSFeed, updateVideoListAfterProcessing } from '../helpers/subscriptions'\nimport {\n  copyToClipboard,\n  getChannelPlaylistId,\n  getRelativeTimeFromDate,\n  showToast\n} from '../helpers/utils'\nimport { invidiousFetch } from '../helpers/api/invidious'\n\nconst { t } = useI18n()\n\nconst isLoading = ref(true)\nconst videoList = shallowRef([])\nconst errorChannels = ref([])\nconst attemptedFetch = ref(false)\n/** @type {import('vue').Ref<number | null>} */\nconst lastRemoteRefreshSuccessTimestamp = ref(null)\n\nlet alreadyLoadedRemotely = false\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst subscriptionCacheReady = computed(() => store.getters.getSubscriptionCacheReady)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => store.getters.getFetchSubscriptionsAutomatically)\n\nconst activeSubscriptionList = computed(() => store.getters.getActiveProfile.subscriptions)\n\nconst cacheEntriesForAllActiveProfileChannels = computed(() => {\n  const shortsCache = store.getters.getShortsCache\n  const entries = []\n\n  activeSubscriptionList.value.forEach((channel) => {\n    const cacheEntry = shortsCache[channel.id]\n\n    if (cacheEntry != null) {\n      entries.push(cacheEntry)\n    }\n  })\n\n  return entries\n})\n\nconst videoCacheForAllActiveProfileChannelsPresent = computed(() => {\n  if (\n    cacheEntriesForAllActiveProfileChannels.value.length === 0 ||\n    cacheEntriesForAllActiveProfileChannels.value.length < activeSubscriptionList.value.length\n  ) {\n    return false\n  }\n\n  return cacheEntriesForAllActiveProfileChannels.value.every((cacheEntry) => {\n    return cacheEntry.videos != null\n  })\n})\n\nconst lastShortRefreshTimestamp = computed(() => {\n  // Cache is not ready when data is just loaded from remote\n  if (lastRemoteRefreshSuccessTimestamp.value) {\n    return getRelativeTimeFromDate(lastRemoteRefreshSuccessTimestamp.value, true)\n  }\n\n  if (\n    !videoCacheForAllActiveProfileChannelsPresent.value ||\n    cacheEntriesForAllActiveProfileChannels.value.length === 0\n  ) {\n    return ''\n  }\n\n  let minTimestamp = null\n  cacheEntriesForAllActiveProfileChannels.value.forEach((cacheEntry) => {\n    if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) {\n      minTimestamp = cacheEntry.timestamp\n    }\n  })\n  return getRelativeTimeFromDate(minTimestamp.getTime(), true)\n})\n\nwatch(activeSubscriptionList, () => {\n  lastRemoteRefreshSuccessTimestamp.value = null\n  isLoading.value = true\n  loadVideosFromCacheSometimes()\n}, { deep: true })\n\nif (!subscriptionCacheReady.value) {\n  watch(subscriptionCacheReady, () => {\n    if (!alreadyLoadedRemotely) {\n      loadVideosFromCacheSometimes()\n    }\n  })\n}\n\nonMounted(() => {\n  loadVideosFromRemoteFirstPerWindowSometimes()\n})\n\nfunction loadVideosFromRemoteFirstPerWindowSometimes() {\n  if (\n    !fetchSubscriptionsAutomatically.value ||\n    // Only auto fetch once per window\n    store.getters.getSubscriptionForShortsFirstAutoFetchRun\n  ) {\n    loadVideosFromCacheSometimes()\n    return\n  }\n\n  alreadyLoadedRemotely = true\n  loadVideosForSubscriptionsFromRemote()\n  store.commit('setSubscriptionForShortsFirstAutoFetchRun')\n}\n\nfunction loadVideosFromCacheSometimes() {\n  // Can only load reliably when cache ready\n  if (!subscriptionCacheReady.value) { return }\n\n  // This method is called on view visible\n  if (videoCacheForAllActiveProfileChannelsPresent.value) {\n    loadVideosFromCacheForAllActiveProfileChannels()\n    return\n  }\n\n  if (fetchSubscriptionsAutomatically.value) {\n    // `isLoading.value = false` is called inside `loadVideosForSubscriptionsFromRemote` when needed\n    loadVideosForSubscriptionsFromRemote()\n    return\n  }\n\n  // Auto fetch disabled, not enough cache for profile = show nothing\n  videoList.value = []\n  attemptedFetch.value = false\n  isLoading.value = false\n}\n\nfunction loadVideosFromCacheForAllActiveProfileChannels() {\n  const videoList_ = cacheEntriesForAllActiveProfileChannels.value.flatMap((cacheEntry) => {\n    return cacheEntry.videos\n  })\n\n  videoList.value = updateVideoListAfterProcessing(videoList_)\n  isLoading.value = false\n}\n\nasync function loadVideosForSubscriptionsFromRemote() {\n  if (activeSubscriptionList.value.length === 0) {\n    isLoading.value = false\n    videoList.value = []\n    return\n  }\n\n  const channelsToLoadFromRemote = activeSubscriptionList.value\n  let channelCount = 0\n  isLoading.value = true\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n  attemptedFetch.value = true\n\n  errorChannels.value = []\n  const subscriptionUpdates = []\n\n  const videoListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => {\n    let videos, name\n\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      ({ videos, name } = await getChannelShortsInvidious(channel))\n    } else {\n      ({ videos, name } = await getChannelShortsLocal(channel))\n    }\n\n    channelCount++\n    const percentageComplete = (channelCount / channelsToLoadFromRemote.length) * 100\n    store.commit('setProgressBarPercentage', percentageComplete)\n\n    if (videos != null) {\n      store.dispatch('updateSubscriptionShortsCacheByChannel', {\n        channelId: channel.id,\n        videos: videos\n      })\n    }\n\n    if (name) {\n      subscriptionUpdates.push({\n        channelId: channel.id,\n        channelName: name\n      })\n    }\n\n    return videos ?? []\n  }))).flat()\n\n  videoList.value = updateVideoListAfterProcessing(videoListFromRemote)\n  isLoading.value = false\n  store.commit('setShowProgressBar', false)\n  lastRemoteRefreshSuccessTimestamp.value = Date.now()\n\n  store.dispatch('batchUpdateSubscriptionDetails', subscriptionUpdates)\n}\n\nasync function getChannelShortsLocal(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'shorts', 'newest')\n  const feedUrl = `https://www.youtube.com/feeds/videos.xml?playlist_id=${playlistId}`\n\n  try {\n    const response = await fetch(feedUrl)\n\n    if (response.status === 403) {\n      return {\n        videos: null\n      }\n    }\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}`, {\n        method: 'HEAD'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return {\n        videos: []\n      }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        if (backendFallback.value) {\n          showToast(t('Falling back to Invidious API'))\n          return await getChannelShortsInvidious(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelShortsInvidious(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'shorts', 'newest')\n  const feedUrl = `${currentInvidiousInstanceUrl.value}/feed/playlist/${playlistId}`\n\n  try {\n    const response = await invidiousFetch(feedUrl)\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`${currentInvidiousInstanceUrl.value}/feed/channel/${channel.id}`, {\n        method: 'GET'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return { videos: [] }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n          showToast(t('Falling back to Local API'))\n          return await getChannelShortsLocal(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsTabUi/SubscriptionsTabUi.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsTabUi/SubscriptionsTabUi.vue",
    "content": "<template>\n  <div>\n    <FtLoader\n      v-if=\"isLoading\"\n    />\n    <div\n      v-if=\"!isLoading && errorChannels.length !== 0\"\n    >\n      <h3> {{ $t(\"Subscriptions.Error Channels\") }}</h3>\n      <FtFlexBox>\n        <FtChannelBubble\n          v-for=\"channel in errorChannels\"\n          :key=\"channel.id\"\n          :channel-name=\"channel.name\"\n          :channel-id=\"channel.id\"\n          :channel-thumbnail=\"channel.thumbnail\"\n        />\n      </FtFlexBox>\n    </div>\n    <FtFlexBox\n      v-if=\"!isLoading && activeVideoList.length === 0\"\n    >\n      <p\n        v-if=\"!activeProfileHasSubscriptions\"\n        class=\"message\"\n      >\n        {{ $t(\"Subscriptions['Your Subscription list is currently empty. Start adding subscriptions to see them here.']\") }}\n      </p>\n      <p\n        v-else-if=\"!fetchSubscriptionsAutomatically && !attemptedFetch\"\n        class=\"message\"\n      >\n        {{ $t(\"Subscriptions.Disabled Automatic Fetching\") }}\n      </p>\n      <p\n        v-else\n        class=\"message\"\n      >\n        {{ isCommunity ? $t(\"Subscriptions.Empty Posts\") : $t(\"Subscriptions.Empty Channels\") }}\n      </p>\n    </FtFlexBox>\n    <FtElementList\n      v-if=\"!isLoading && activeVideoList.length > 0\"\n      :data=\"activeVideoList\"\n      :use-channels-hidden-preference=\"false\"\n      :display=\"isCommunity ? 'list' : ''\"\n    />\n    <FtAutoLoadNextPageWrapper\n      v-if=\"!isLoading && videoList.length > dataLimit\"\n      @load-next-page=\"increaseLimit\"\n    >\n      <FtFlexBox>\n        <FtButton\n          :label=\"isCommunity ? $t('Subscriptions.Load More Posts') : $t('Subscriptions.Load More Videos')\"\n          background-color=\"var(--primary-color)\"\n          text-color=\"var(--text-with-main-color)\"\n          @click=\"increaseLimit\"\n        />\n      </FtFlexBox>\n    </FtAutoLoadNextPageWrapper>\n\n    <FtRefreshWidget\n      :disable-refresh=\"isLoading || !activeProfileHasSubscriptions\"\n      :last-refresh-timestamp=\"lastRefreshTimestamp\"\n      :title=\"title\"\n      @click=\"refresh\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\n\nimport FtAutoLoadNextPageWrapper from '../FtAutoLoadNextPageWrapper.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport FtChannelBubble from '../FtChannelBubble/FtChannelBubble.vue'\nimport FtElementList from '../FtElementList/FtElementList.vue'\nimport FtFlexBox from '../ft-flex-box/ft-flex-box.vue'\nimport FtLoader from '../FtLoader/FtLoader.vue'\nimport FtRefreshWidget from '../FtRefreshWidget/FtRefreshWidget.vue'\n\nimport store from '../../store/index'\n\nimport { KeyboardShortcuts } from '../../../constants'\n\nconst props = defineProps({\n  isLoading: {\n    type: Boolean,\n    default: false\n  },\n  videoList: {\n    type: Array,\n    default: () => []\n  },\n  isCommunity: {\n    type: Boolean,\n    default: false\n  },\n  errorChannels: {\n    type: Array,\n    default: () => []\n  },\n  attemptedFetch: {\n    type: Boolean,\n    default: false\n  },\n  initialDataLimit: {\n    type: Number,\n    default: 100\n  },\n  lastRefreshTimestamp: {\n    type: String,\n    required: true\n  },\n  title: {\n    type: String,\n    required: true\n  }\n})\n\nconst emit = defineEmits(['refresh'])\n\nconst subscriptionLimit = sessionStorage.getItem('subscriptionLimit')\n\nconst dataLimit = ref(subscriptionLimit !== null ? parseInt(subscriptionLimit) : props.initialDataLimit)\n\nconst activeVideoList = computed(() => {\n  if (filteredVideoList.value.length < dataLimit.value) {\n    return filteredVideoList.value\n  } else {\n    return filteredVideoList.value.slice(0, dataLimit.value)\n  }\n})\n\nconst activeProfileHasSubscriptions = computed(() => {\n  return store.getters.getActiveProfile.subscriptions.length > 0\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => {\n  return store.getters.getFetchSubscriptionsAutomatically\n})\n\nconst historyCacheById = computed(() => {\n  return store.getters.getHistoryCacheById\n})\n\nconst hideWatchedSubs = computed(() => {\n  return store.getters.getHideWatchedSubs\n})\n\nconst filteredVideoList = computed(() => {\n  if (hideWatchedSubs.value && !props.isCommunity) {\n    return props.videoList.filter((video) => {\n      return historyCacheById.value[video.videoId] === undefined\n    })\n  } else {\n    return props.videoList\n  }\n})\n\nfunction increaseLimit() {\n  dataLimit.value += props.initialDataLimit\n  sessionStorage.setItem('subscriptionLimit', dataLimit.value.toFixed(0))\n}\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  if (document.activeElement.classList.contains('ft-input')) {\n    return\n  }\n  // Avoid handling events due to user holding a key (not released)\n  // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat\n  if (event.repeat) { return }\n\n  switch (event.key.toLowerCase()) {\n    case 'f5':\n    case KeyboardShortcuts.APP.SITUATIONAL.REFRESH:\n      if (!props.isLoading && activeProfileHasSubscriptions.value) {\n        refresh()\n      }\n      break\n  }\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n\nfunction refresh() {\n  emit('refresh')\n}\n</script>\n\n<style scoped src=\"./SubscriptionsTabUi.css\" />\n"
  },
  {
    "path": "src/renderer/components/SubscriptionsVideos.vue",
    "content": "<template>\n  <SubscriptionsTabUi\n    :is-loading=\"isLoading\"\n    :video-list=\"videoList\"\n    :error-channels=\"errorChannels\"\n    :last-refresh-timestamp=\"lastVideoRefreshTimestamp\"\n    :attempted-fetch=\"attemptedFetch\"\n    :title=\"t('Global.Videos')\"\n    @refresh=\"loadVideosForSubscriptionsFromRemote\"\n  />\n</template>\n\n<script setup>\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport SubscriptionsTabUi from './SubscriptionsTabUi/SubscriptionsTabUi.vue'\n\nimport store from '../store/index'\n\nimport {\n  copyToClipboard,\n  getRelativeTimeFromDate,\n  showToast,\n  getChannelPlaylistId\n} from '../helpers/utils'\nimport { getInvidiousChannelVideos, invidiousFetch } from '../helpers/api/invidious'\nimport { getLocalChannelVideos } from '../helpers/api/local'\nimport { parseYouTubeRSSFeed, updateVideoListAfterProcessing } from '../helpers/subscriptions'\n\nconst { t } = useI18n()\n\nconst isLoading = ref(true)\nconst videoList = shallowRef([])\nconst errorChannels = ref([])\nconst attemptedFetch = ref(false)\n/** @type {import('vue').Ref<number | null>} */\nconst lastRemoteRefreshSuccessTimestamp = ref(null)\n\nlet alreadyLoadedRemotely = false\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst subscriptionCacheReady = computed(() => store.getters.getSubscriptionCacheReady)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useRssFeeds = computed(() => store.getters.getUseRssFeeds)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst fetchSubscriptionsAutomatically = computed(() => store.getters.getFetchSubscriptionsAutomatically)\n\nconst activeSubscriptionList = computed(() => store.getters.getActiveProfile.subscriptions)\n\nconst cacheEntriesForAllActiveProfileChannels = computed(() => {\n  const videoCache = store.getters.getVideoCache\n  const entries = []\n\n  activeSubscriptionList.value.forEach((channel) => {\n    const cacheEntry = videoCache[channel.id]\n\n    if (cacheEntry != null) {\n      entries.push(cacheEntry)\n    }\n  })\n\n  return entries\n})\n\nconst videoCacheForAllActiveProfileChannelsPresent = computed(() => {\n  if (\n    cacheEntriesForAllActiveProfileChannels.value.length === 0 ||\n    cacheEntriesForAllActiveProfileChannels.value.length < activeSubscriptionList.value.length\n  ) {\n    return false\n  }\n\n  return cacheEntriesForAllActiveProfileChannels.value.every((cacheEntry) => {\n    return cacheEntry.videos != null\n  })\n})\n\nconst lastVideoRefreshTimestamp = computed(() => {\n  // Cache is not ready when data is just loaded from remote\n  if (lastRemoteRefreshSuccessTimestamp.value) {\n    return getRelativeTimeFromDate(lastRemoteRefreshSuccessTimestamp.value, true)\n  }\n\n  if (\n    !videoCacheForAllActiveProfileChannelsPresent.value ||\n     cacheEntriesForAllActiveProfileChannels.value.length === 0\n  ) {\n    return ''\n  }\n\n  let minTimestamp = null\n  cacheEntriesForAllActiveProfileChannels.value.forEach((cacheEntry) => {\n    if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) {\n      minTimestamp = cacheEntry.timestamp\n    }\n  })\n  return getRelativeTimeFromDate(minTimestamp.getTime(), true)\n})\n\nwatch(activeSubscriptionList, () => {\n  lastRemoteRefreshSuccessTimestamp.value = null\n  isLoading.value = true\n  loadVideosFromCacheSometimes()\n}, { deep: true })\n\nif (!subscriptionCacheReady.value) {\n  watch(subscriptionCacheReady, () => {\n    if (!alreadyLoadedRemotely) {\n      loadVideosFromCacheSometimes()\n    }\n  })\n}\n\nonMounted(() => {\n  loadVideosFromRemoteFirstPerWindowSometimes()\n})\n\nfunction loadVideosFromRemoteFirstPerWindowSometimes() {\n  if (\n    !fetchSubscriptionsAutomatically.value ||\n    // Only auto fetch once per window\n    store.getters.getSubscriptionForVideosFirstAutoFetchRun\n  ) {\n    loadVideosFromCacheSometimes()\n    return\n  }\n\n  alreadyLoadedRemotely = true\n  loadVideosForSubscriptionsFromRemote()\n  store.commit('setSubscriptionForVideosFirstAutoFetchRun')\n}\n\nfunction loadVideosFromCacheSometimes() {\n  // Can only load reliably when cache ready\n  if (!subscriptionCacheReady.value) { return }\n\n  // This method is called on view visible\n  if (videoCacheForAllActiveProfileChannelsPresent.value) {\n    loadVideosFromCacheForAllActiveProfileChannels()\n    return\n  }\n\n  if (fetchSubscriptionsAutomatically.value) {\n    // `isLoading.value = false` is called inside `loadVideosForSubscriptionsFromRemote` when needed\n    loadVideosForSubscriptionsFromRemote()\n    return\n  }\n\n  // Auto fetch disabled, not enough cache for profile = show nothing\n  videoList.value = []\n  attemptedFetch.value = false\n  isLoading.value = false\n}\n\nfunction loadVideosFromCacheForAllActiveProfileChannels() {\n  const videoList_ = cacheEntriesForAllActiveProfileChannels.value.flatMap((cacheEntry) => {\n    return cacheEntry.videos\n  })\n\n  videoList.value = updateVideoListAfterProcessing(videoList_)\n  isLoading.value = false\n}\n\nasync function loadVideosForSubscriptionsFromRemote() {\n  if (activeSubscriptionList.value.length === 0) {\n    isLoading.value = false\n    videoList.value = []\n    return\n  }\n\n  const channelsToLoadFromRemote = activeSubscriptionList.value\n  let channelCount = 0\n  isLoading.value = true\n\n  let useRss = useRssFeeds.value\n  if (channelsToLoadFromRemote.length >= 125 && !useRss) {\n    showToast(\n      t('Subscriptions[\"This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting\"]'),\n      10000\n    )\n    useRss = true\n  }\n\n  store.commit('setShowProgressBar', true)\n  store.commit('setProgressBarPercentage', 0)\n  attemptedFetch.value = true\n\n  errorChannels.value = []\n  const subscriptionUpdates = []\n\n  const videoListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => {\n    let videos, name, thumbnailUrl\n\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      if (useRss) {\n        ({ videos, name, thumbnailUrl } = await getChannelVideosInvidiousRSS(channel))\n      } else {\n        ({ videos, name, thumbnailUrl } = await getChannelVideosInvidiousScraper(channel))\n      }\n    } else {\n      if (useRss) {\n        ({ videos, name, thumbnailUrl } = await getChannelVideosLocalRSS(channel))\n      } else {\n        ({ videos, name, thumbnailUrl } = await getChannelVideosLocalScraper(channel))\n      }\n    }\n\n    channelCount++\n    const percentageComplete = (channelCount / channelsToLoadFromRemote.length) * 100\n    store.commit('setProgressBarPercentage', percentageComplete)\n\n    if (videos != null) {\n      store.dispatch('updateSubscriptionVideosCacheByChannel', {\n        channelId: channel.id,\n        videos: videos\n      })\n    }\n\n    if (name || thumbnailUrl) {\n      subscriptionUpdates.push({\n        channelId: channel.id,\n        channelName: name,\n        channelThumbnailUrl: thumbnailUrl\n      })\n    }\n\n    return videos ?? []\n  }))).flat()\n\n  videoList.value = updateVideoListAfterProcessing(videoListFromRemote)\n  isLoading.value = false\n  store.commit('setShowProgressBar', false)\n  lastRemoteRefreshSuccessTimestamp.value = Date.now()\n\n  store.dispatch('batchUpdateSubscriptionDetails', subscriptionUpdates)\n}\n\nasync function getChannelVideosLocalScraper(channel, failedAttempts = 0) {\n  try {\n    const result = await getLocalChannelVideos(channel.id)\n\n    if (result === null) {\n      errorChannels.value.push(channel)\n      return {\n        videos: []\n      }\n    }\n\n    return result\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelVideosLocalRSS(channel, failedAttempts + 1)\n      case 1:\n        if (backendFallback.value) {\n          showToast(t('Falling back to Invidious API'))\n          return await getChannelVideosInvidiousScraper(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelVideosLocalRSS(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelVideosLocalRSS(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'videos', 'newest')\n  const feedUrl = `https://www.youtube.com/feeds/videos.xml?playlist_id=${playlistId}`\n\n  try {\n    const response = await fetch(feedUrl)\n\n    if (response.status === 403) {\n      return {\n        videos: null\n      }\n    }\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}`, {\n        method: 'HEAD'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return {\n        videos: []\n      }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelVideosLocalScraper(channel, failedAttempts + 1)\n      case 1:\n        if (backendFallback.value) {\n          showToast(t('Falling back to Invidious API'))\n          return await getChannelVideosInvidiousRSS(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelVideosLocalScraper(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelVideosInvidiousScraper(channel, failedAttempts = 0) {\n  try {\n    const result = await getInvidiousChannelVideos(channel.id)\n\n    let name\n\n    if (result.videos.length > 0) {\n      name = result.videos.find(video => video.type === 'video' && video.author).author\n    }\n\n    return {\n      name,\n      videos: result.videos\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelVideosInvidiousRSS(channel, failedAttempts + 1)\n      case 1:\n        if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n          showToast(t('Falling back to Local API'))\n          return await getChannelVideosLocalScraper(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelVideosInvidiousRSS(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n\nasync function getChannelVideosInvidiousRSS(channel, failedAttempts = 0) {\n  const playlistId = getChannelPlaylistId(channel.id, 'videos', 'newest')\n  const feedUrl = `${currentInvidiousInstanceUrl.value}/feed/playlist/${playlistId}`\n\n  try {\n    const response = await invidiousFetch(feedUrl)\n\n    if (response.status === 404) {\n      // playlists don't exist if the channel was terminated but also if it doesn't have the tab,\n      // so we need to check the channel feed too before deciding it errored, as that only 404s if the channel was terminated\n\n      const response2 = await fetch(`${currentInvidiousInstanceUrl.value}/feed/channel/${channel.id}`, {\n        method: 'GET'\n      })\n\n      if (response2.status === 404) {\n        errorChannels.value.push(channel)\n      }\n\n      return {\n        videos: []\n      }\n    }\n\n    return await parseYouTubeRSSFeed(await response.text(), channel.id)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    switch (failedAttempts) {\n      case 0:\n        return await getChannelVideosInvidiousScraper(channel, failedAttempts + 1)\n      case 1:\n        if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n          showToast(t('Falling back to Local API'))\n          return await getChannelVideosLocalRSS(channel, failedAttempts + 1)\n        } else {\n          return {\n            videos: []\n          }\n        }\n      case 2:\n        return await getChannelVideosInvidiousScraper(channel, failedAttempts + 1)\n      default:\n        return {\n          videos: []\n        }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/ThemeSettings.vue",
    "content": "<template>\n  <FtSettingsSection\n    :title=\"$t('Settings.Theme Settings.Theme Settings')\"\n  >\n    <div class=\"switchColumnGrid\">\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Theme Settings.Match Top Bar with Main Color')\"\n          compact\n          :default-value=\"barColor\"\n          @change=\"updateBarColor\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Theme Settings.Expand Side Bar by Default')\"\n          compact\n          :default-value=\"expandSideBar\"\n          @change=\"handleExpandSideBar\"\n        />\n        <FtToggleSwitch\n          v-if=\"usingElectron\"\n          :label=\"$t('Settings.Theme Settings.Disable Smooth Scrolling')\"\n          compact\n          :default-value=\"disableSmoothScrollingToggleValue\"\n          @change=\"handleRestartPrompt\"\n        />\n      </div>\n      <div class=\"switchColumn\">\n        <FtToggleSwitch\n          :label=\"$t('Settings.Theme Settings.Hide Side Bar Labels')\"\n          compact\n          :default-value=\"hideLabelsSideBar\"\n          @change=\"updateHideLabelsSideBar\"\n        />\n        <FtToggleSwitch\n          :label=\"$t('Settings.Theme Settings.Hide FreeTube Header Logo')\"\n          compact\n          :default-value=\"hideHeaderLogo\"\n          @change=\"updateHideHeaderLogo\"\n        />\n      </div>\n    </div>\n    <template v-if=\"usingElectron\">\n      <FtFlexBox>\n        <FtSlider\n          :label=\"$t('Settings.Theme Settings.UI Scale')\"\n          :default-value=\"uiScale\"\n          :min-value=\"50\"\n          :max-value=\"300\"\n          :step=\"5\"\n          value-extension=\"%\"\n          @change=\"updateUiScale\"\n        />\n      </FtFlexBox>\n      <br>\n    </template>\n    <FtFlexBox>\n      <FtSelect\n        :placeholder=\"$t('Settings.Theme Settings.Base Theme.Base Theme')\"\n        :value=\"baseTheme\"\n        :select-names=\"baseThemeNames\"\n        :select-values=\"BASE_THEME_VALUES\"\n        :icon=\"['fas', 'palette']\"\n        @change=\"updateBaseTheme\"\n      />\n      <FtSelect\n        :placeholder=\"$t('Settings.Theme Settings.Main Color Theme.Main Color Theme')\"\n        :value=\"mainColor\"\n        :select-names=\"colorNames\"\n        :select-values=\"COLOR_VALUES\"\n        :disabled=\"!areColorThemesEnabled\"\n        :icon=\"['fas', 'palette']\"\n        icon-color=\"var(--primary-color)\"\n        @change=\"updateMainColor\"\n      />\n      <FtSelect\n        :placeholder=\"$t('Settings.Theme Settings.Secondary Color Theme')\"\n        :value=\"secColor\"\n        :select-names=\"colorNames\"\n        :select-values=\"COLOR_VALUES\"\n        :disabled=\"!areColorThemesEnabled\"\n        :icon=\"['fas', 'palette']\"\n        icon-color=\"var(--accent-color)\"\n        @change=\"updateSecColor\"\n      />\n    </FtFlexBox>\n    <FtPrompt\n      v-if=\"showRestartPrompt\"\n      :label=\"$t('Settings[\\'The app needs to restart for changes to take effect. Restart and apply change?\\']')\"\n      :option-names=\"restartPromptNames\"\n      :option-values=\"RESTART_PROMPT_VALUES\"\n      @click=\"handleSmoothScrolling\"\n    />\n  </FtSettingsSection>\n</template>\n\n<script setup>\nimport { computed, ref } from 'vue'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'\nimport FtSelect from './FtSelect/FtSelect.vue'\nimport FtToggleSwitch from './FtToggleSwitch/FtToggleSwitch.vue'\nimport FtSlider from './FtSlider/FtSlider.vue'\nimport FtFlexBox from './ft-flex-box/ft-flex-box.vue'\nimport FtPrompt from './FtPrompt/FtPrompt.vue'\n\nimport store from '../store/index'\n\nimport { colors } from '../helpers/colors'\nimport { useColorTranslations } from '../composables/colors'\n\nconst { t } = useI18n()\n\n// Themes are devided into 3 groups.\n// The first group contains the default themes.\n// The second group are themes that don't have specific primary and secondary colors.\n// The third group are themes that do have specific primary and secondary colors available.\n\nconst BASE_THEME_VALUES = [\n  // First group\n  'system',\n  'light',\n  'dark',\n  'black',\n  // Second group\n  'nordic',\n  'hotPink',\n  'pastelPink',\n  // Third group\n  'catppuccinFrappe',\n  'catppuccinLatte',\n  'catppuccinMocha',\n  'dracula',\n  'everforestDarkHard',\n  'everforestDarkMedium',\n  'everforestDarkLow',\n  'everforestLightHard',\n  'everforestLightMedium',\n  'everforestLightLow',\n  'gruvboxDark',\n  'gruvboxLight',\n  'solarizedDark',\n  'solarizedLight'\n]\n\nconst baseThemeNames = computed(() => [\n  // First group\n  t('Settings.Theme Settings.Base Theme.System Default'),\n  t('Settings.Theme Settings.Base Theme.Light'),\n  t('Settings.Theme Settings.Base Theme.Dark'),\n  t('Settings.Theme Settings.Base Theme.Black'),\n  // Second group\n  t('Settings.Theme Settings.Base Theme.Nordic'),\n  t('Settings.Theme Settings.Base Theme.Hot Pink'),\n  t('Settings.Theme Settings.Base Theme.Pastel Pink'),\n  // Third group\n  t('Settings.Theme Settings.Base Theme.Catppuccin Frappe'),\n  t('Settings.Theme Settings.Base Theme.Catppuccin Latte'),\n  t('Settings.Theme Settings.Base Theme.Catppuccin Mocha'),\n  t('Settings.Theme Settings.Base Theme.Dracula'),\n  t('Settings.Theme Settings.Base Theme.Everforest Dark Hard'),\n  t('Settings.Theme Settings.Base Theme.Everforest Dark Medium'),\n  t('Settings.Theme Settings.Base Theme.Everforest Dark Low'),\n  t('Settings.Theme Settings.Base Theme.Everforest Light Hard'),\n  t('Settings.Theme Settings.Base Theme.Everforest Light Medium'),\n  t('Settings.Theme Settings.Base Theme.Everforest Light Low'),\n  t('Settings.Theme Settings.Base Theme.Gruvbox Dark'),\n  t('Settings.Theme Settings.Base Theme.Gruvbox Light'),\n  t('Settings.Theme Settings.Base Theme.Solarized Dark'),\n  t('Settings.Theme Settings.Base Theme.Solarized Light')\n])\n\nconst COLOR_VALUES = colors.map(color => color.name)\nconst colorNames = useColorTranslations()\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst barColor = computed(() => {\n  return store.getters.getBarColor\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateBarColor(value) {\n  store.dispatch('updateBarColor', value)\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst baseTheme = computed(() => {\n  return store.getters.getBaseTheme\n})\n\n/**\n * @param {string} value\n */\nfunction updateBaseTheme(value) {\n  store.dispatch('updateBaseTheme', value)\n}\n\nconst areColorThemesEnabled = computed(() => baseTheme.value !== 'hotPink')\n\n/** @type {import('vue').ComputedRef<string>} */\nconst mainColor = computed(() => {\n  return store.getters.getMainColor\n})\n\n/**\n * @param {string} value\n */\nfunction updateMainColor(value) {\n  store.dispatch('updateMainColor', value)\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst secColor = computed(() => {\n  return store.getters.getSecColor\n})\n\n/**\n * @param {string} value\n */\nfunction updateSecColor(value) {\n  store.dispatch('updateSecColor', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst expandSideBar = computed(() => {\n  return store.getters.getexpandSideBar\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isSideNavOpen = computed(() => {\n  return store.getters.getIsSideNavOpen\n})\n\n/**\n * @param {boolean} value\n */\nfunction handleExpandSideBar(value) {\n  if (isSideNavOpen.value !== value) {\n    store.commit('toggleSideNav')\n  }\n\n  store.dispatch('updateExpandSideBar', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLabelsSideBar = computed(() => {\n  return store.getters.getHideLabelsSideBar\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateHideLabelsSideBar(value) {\n  store.dispatch('updateHideLabelsSideBar', value)\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideHeaderLogo = computed(() => {\n  return store.getters.getHideHeaderLogo\n})\n\n/**\n * @param {boolean} value\n */\nfunction updateHideHeaderLogo(value) {\n  store.dispatch('updateHideHeaderLogo', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst uiScale = computed(() => store.getters.getUiScale)\n\n/**\n * @param {number} value\n */\nfunction updateUiScale(value) {\n  store.dispatch('updateUiScale', value)\n}\n\n/** @type {boolean} */\nconst usingElectron = process.env.IS_ELECTRON\n\nconst RESTART_PROMPT_VALUES = [\n  'restart',\n  'cancel'\n]\n\nconst restartPromptNames = computed(() => [\n  t('Yes, Restart'),\n  t('Cancel')\n])\n\n/** @type {import('vue').Ref<boolean>} */\nconst disableSmoothScrollingToggleValue = ref(store.getters.getDisableSmoothScrolling)\nconst showRestartPrompt = ref(false)\n\n/**\n * @param {boolean} value\n */\nfunction handleRestartPrompt(value) {\n  disableSmoothScrollingToggleValue.value = value\n  showRestartPrompt.value = true\n}\n\n/**\n * @param {'restart' | 'cancel' | null} value\n */\nfunction handleSmoothScrolling(value) {\n  showRestartPrompt.value = false\n\n  if (value === null || value === 'cancel') {\n    disableSmoothScrollingToggleValue.value = !disableSmoothScrollingToggleValue.value\n    return\n  }\n\n  if (process.env.IS_ELECTRON) {\n    store.dispatch('updateDisableSmoothScrolling',\n      disableSmoothScrollingToggleValue.value\n    ).then(() => {\n      window.ftElectron.relaunch()\n    })\n  }\n}\n</script>\n"
  },
  {
    "path": "src/renderer/components/TopNav/TopNav.scss",
    "content": "@mixin top-nav-is-colored {\n  @at-root {\n    .topNavBarColor &,\n    .topNavBarColor#{&} {\n      @content;\n    }\n  }\n}\n\n.topNav {\n  align-content: center;\n  align-items: center;\n  background-color: var(--card-bg-color);\n  box-shadow: 0 2px 1px 0 var(--primary-shadow-color);\n  display: flex;\n  block-size: 60px;\n  inset-inline: 0;\n  line-height: 60px;\n  position: sticky;\n  inset-block-start: 0;\n  inline-size: 100%;\n  z-index: 4;\n\n  @media only screen and (width >= 961px) {\n    display: grid;\n    grid-template-columns: 1fr 440px 1fr;\n  }\n\n  @include top-nav-is-colored {\n    background-color: var(--primary-color);\n  }\n\n  @media only screen and (width <= 680px) {\n    position: fixed;\n\n    &:has(+ .sideNav + .routerView .floatingRefreshSection) {\n      box-shadow: none;\n    }\n  }\n}\n\n.menuButton {\n  @media only screen and (width <= 680px) {\n    display: none;\n  }\n}\n\n.arrowDisabled :deep(.iconButton) {\n  filter: grayscale(1);\n  background-color: inherit;\n  opacity: 0.4;\n  pointer-events: auto;\n  cursor: default;\n  user-select: none;\n}\n\n.navButton {\n  border-radius: 50%;\n  border-style: none;\n  background-color: transparent;\n  color: var(--primary-text-color);\n  cursor: pointer;\n  font-size: 20px;\n  line-height: 1em;\n  padding: 10px;\n  transition: background 0.2s ease-out;\n}\n\n.navButton,\n:deep(.ftIconButton:not(.arrowDisabled) .iconButton) {\n  &:hover {\n    background-color: var(--side-nav-hover-color);\n    color: var(--side-nav-hover-text-color);\n    transition: background 0.2s ease-in;\n  }\n\n  &:active {\n    background-color: var(--tertiary-text-color);\n    color: var(--side-nav-active-text-color);\n    transition: background 0.2s ease-in;\n  }\n}\n\n.navIcon {\n  inline-size: 1em;\n}\n\n.topNavBarColor .navButton,\n.topNavBarColor :deep(.ftIconButton:not(.arrowDisabled) .iconButton) {\n  color: var(--text-with-main-color);\n\n  &:hover {\n    background-color: var(--primary-color-hover);\n  }\n\n  &:active {\n    background-color: var(--primary-color-active);\n  }\n}\n\n\n.navFilterButton {\n  $effect-distance: 20px;\n\n  margin-inline-start: $effect-distance;\n\n  &.filterChanged {\n    /* stylelint-disable-next-line declaration-property-value-no-unknown */\n    box-shadow: 0 0 $effect-distance var(--primary-color);\n    color: var(--primary-color);\n\n    @include top-nav-is-colored {\n      box-shadow: 0 0 $effect-distance var(--text-with-main-color);\n      color: var(--text-with-main-color);\n    }\n  }\n}\n\n.side {\n  align-items: center;\n  display: flex;\n  gap: 3px;\n  margin-block: 0;\n  margin-inline: 6px;\n\n  &.profiles {\n    justify-content: flex-end;\n  }\n\n  .navSearchButton {\n    @media only screen and (width >= 681px) {\n      display: none;\n    }\n  }\n\n  .navNewWindowButton {\n    @media only screen and (width <= 680px) {\n      display: none;\n    }\n  }\n\n  .logo {\n    align-items: center;\n    cursor: pointer;\n    display: flex;\n    padding-block: 0;\n    padding-inline: 10px 25px;\n\n    &:hover {\n      background-color: var(--side-nav-hover-color);\n      color: var(--side-nav-hover-text-color);\n      transition: background 0.2s ease-in;\n\n      @include top-nav-is-colored {\n        background-color: var(--primary-color-hover);\n      }\n    }\n\n    &:active {\n      background-color: var(--tertiary-text-color);\n      transition: background 0.2s ease-in;\n\n      @include top-nav-is-colored {\n        background-color: var(--primary-color-active);\n      }\n    }\n\n    .logoIcon {\n      background-image: var(--logo-icon);\n      background-position: right top;\n      background-repeat: no-repeat;\n      background-size: 25px;\n      block-size: 25px;\n      inline-size: 25px;\n\n      @include top-nav-is-colored {\n        background-image: var(--logo-icon-bar-color);\n      }\n    }\n\n    .logoText {\n      background-image: var(--logo-text);\n      background-position: right top;\n      background-repeat: no-repeat;\n      background-size: 100px;\n      block-size: 40px;\n      margin-inline-start: 5px;\n      position: relative;\n      inset-block-start: -3px;\n      inline-size: 100px;\n\n      @media only screen and (width <= 680px) {\n        display: none;\n      }\n\n      @include top-nav-is-colored {\n        background-image: var(--logo-text-bar-color);\n      }\n    }\n  }\n}\n\n.middle {\n  flex: 1;\n  max-inline-size: 440px;\n\n  .searchContainer {\n    align-items: center;\n    display: flex;\n\n    @media only screen and (width <= 680px) {\n      background-color: var(--side-nav-color);\n      inset-inline: 0;\n      position: fixed;\n      inset-block-start: 60px;\n\n      @include top-nav-is-colored {\n        background-color: var(--primary-color-hover);\n      }\n    }\n\n    .searchInput {\n      flex: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/TopNav/TopNav.vue",
    "content": "<template>\n  <nav\n    class=\"topNav\"\n    :class=\"{ topNavBarColor: barColor }\"\n  >\n    <div class=\"side\">\n      <button\n        class=\"menuButton navButton\"\n        :aria-label=\"expandCollapseSideBarLabel\"\n        :title=\"expandCollapseSideBarLabel\"\n        @click=\"toggleSideNav\"\n      >\n        <FontAwesomeIcon\n          class=\"navIcon\"\n          :icon=\"['fas', 'bars']\"\n        />\n      </button>\n      <FtIconButton\n        class=\"navIconButton\"\n        :disabled=\"isArrowBackwardDisabled\"\n        :class=\"{ arrowDisabled: isArrowBackwardDisabled }\"\n        :icon=\"['fas', 'arrow-left']\"\n        :theme=\"null\"\n        :size=\"20\"\n        :use-shadow=\"false\"\n        dropdown-position-x=\"right\"\n        :dropdown-options=\"navigationHistoryDropdownOptions\"\n        open-on-right-or-long-click\n        :title=\"backwardText\"\n        @click=\"historyBack\"\n      />\n      <FtIconButton\n        class=\"navIconButton\"\n        :disabled=\"isArrowForwardDisabled\"\n        :class=\"{ arrowDisabled: isArrowForwardDisabled }\"\n        :icon=\"['fas', 'arrow-right']\"\n        :theme=\"null\"\n        :size=\"20\"\n        :use-shadow=\"false\"\n        dropdown-position-x=\"right\"\n        :dropdown-options=\"navigationHistoryDropdownOptions\"\n        open-on-right-or-long-click\n        :title=\"forwardText\"\n        @click=\"historyForward\"\n      />\n      <button\n        v-if=\"!hideSearchBar\"\n        class=\"navSearchButton navButton\"\n        @click=\"toggleSearchContainer\"\n      >\n        <FontAwesomeIcon\n          class=\"navIcon\"\n          :icon=\"['fas', 'search']\"\n        />\n      </button>\n      <button\n        class=\"navNewWindowButton navButton\"\n        :aria-label=\"t('Open New Window')\"\n        :title=\"newWindowText\"\n        @click=\"createNewWindow\"\n      >\n        <FontAwesomeIcon\n          class=\"navIcon\"\n          :icon=\"['fas', 'clone']\"\n        />\n      </button>\n      <RouterLink\n        v-if=\"!hideHeaderLogo\"\n        class=\"logo\"\n        dir=\"ltr\"\n        :title=\"headerLogoTitle\"\n        :to=\"landingPage\"\n      >\n        <div\n          class=\"logoIcon\"\n        />\n        <div\n          class=\"logoText\"\n        />\n      </RouterLink>\n    </div>\n    <div class=\"middle\">\n      <div\n        v-if=\"!hideSearchBar\"\n        v-show=\"showSearchContainer\"\n        ref=\"searchContainer\"\n        class=\"searchContainer\"\n      >\n        <FtInput\n          ref=\"searchInput\"\n          :placeholder=\"t('Search / Go to URL')\"\n          class=\"searchInput\"\n          is-search\n          :data-list=\"activeDataList\"\n          :data-list-properties=\"activeDataListProperties\"\n          show-clear-text-button\n          show-data-when-empty\n          @input=\"getSearchSuggestionsDebounce\"\n          @click=\"goToSearch\"\n          @clear=\"clearLastSuggestionQuery\"\n          @remove=\"removeSearchHistoryEntryInDbAndCache\"\n        />\n        <button\n          class=\"navFilterButton navButton\"\n          :class=\"{ filterChanged: searchFilterValueChanged }\"\n          :aria-label=\"t('Search Filters.Search Filters')\"\n          :title=\"t('Search Filters.Search Filters')\"\n          @click=\"showSearchFilters\"\n        >\n          <FontAwesomeIcon\n            class=\"navIcon\"\n            :icon=\"['fas', 'filter']\"\n          />\n        </button>\n      </div>\n    </div>\n    <FtProfileSelector class=\"side profiles\" />\n  </nav>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRoute, useRouter } from 'vue-router'\n\nimport FtInput from '../FtInput/FtInput.vue'\nimport FtProfileSelector from '../FtProfileSelector/FtProfileSelector.vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\n\nimport store from '../../store/index'\n\nimport { KeyboardShortcuts, MOBILE_WIDTH_THRESHOLD, SEARCH_RESULTS_DISPLAY_LIMIT } from '../../../constants'\nimport { debounce, localizeAndAddKeyboardShortcutToActionTitle, openInternalPath } from '../../helpers/utils'\nimport { translateWindowTitle } from '../../helpers/strings'\nimport { clearLocalSearchSuggestionsSession, getLocalSearchSuggestions } from '../../helpers/api/local'\nimport { getInvidiousSearchSuggestions } from '../../helpers/api/invidious'\n\nconst { t } = useI18n()\nconst router = useRouter()\nconst route = useRoute()\n\nconst showSearchContainer = ref(true)\n/** @type {import('vue').ShallowRef<string[]>} */\nconst navigationHistoryDropdownOptions = shallowRef([])\n/** @type {import('vue').ShallowRef<string[]>} */\nconst searchSuggestionsDataList = shallowRef([])\nconst lastSuggestionQuery = ref('')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSearchBar = computed(() => store.getters.getHideSearchBar)\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideHeaderLogo = computed(() => store.getters.getHideHeaderLogo)\n/** @type {import('vue').ComputedRef<boolean>} */\nconst enableSearchSuggestions = computed(() => store.getters.getEnableSearchSuggestions)\n/** @type {import('vue').ComputedRef<string>} */\nconst barColor = computed(() => store.getters.getBarColor)\n\nconst expandCollapseSideBarLabel = computed(() => {\n  return store.getters.getIsSideNavOpen ? t('Compact side navigation') : t('Expand side navigation')\n})\n\nconst landingPage = computed(() => '/' + store.getters.getLandingPage)\n\nconst headerLogoTitle = computed(() => {\n  return t('Go to page', {\n    page: translateWindowTitle(\n      router.getRoutes()\n        .find((route) => route.path === landingPage.value)\n        .meta.title)\n  })\n})\n\nconst navigationHistoryAddendum = computed(() => {\n  return navigationHistoryDropdownOptions.value.length === 0\n    ? ''\n    : `\\n${t('Right-click or hold to see history')}`\n})\n\nconst backwardText = computed(() => {\n  const shortcuts = process.platform === 'darwin'\n    ? [\n        KeyboardShortcuts.APP.GENERAL.HISTORY_BACKWARD,\n        KeyboardShortcuts.APP.GENERAL.HISTORY_BACKWARD_ALT_MAC\n      ]\n    : KeyboardShortcuts.APP.GENERAL.HISTORY_BACKWARD\n\n  return localizeAndAddKeyboardShortcutToActionTitle(\n    t('Back'),\n    shortcuts\n  ) + navigationHistoryAddendum.value\n})\n\nconst forwardText = computed(() => {\n  const shortcuts = process.platform === 'darwin'\n    ? [\n        KeyboardShortcuts.APP.GENERAL.HISTORY_FORWARD,\n        KeyboardShortcuts.APP.GENERAL.HISTORY_FORWARD_ALT_MAC\n      ]\n    : KeyboardShortcuts.APP.GENERAL.HISTORY_FORWARD\n\n  return localizeAndAddKeyboardShortcutToActionTitle(\n    t('Forward'),\n    shortcuts\n  ) + navigationHistoryAddendum.value\n})\n\n/**\n * @param {number} offset\n */\nfunction goToOffset(offset) {\n  // no point navigating to the current route\n  if (offset !== 0) {\n    router.go(offset)\n  }\n}\n\n/**\n * @param {number} [offset]\n */\nfunction historyBack(offset) {\n  if (offset != null) {\n    goToOffset(offset)\n  } else {\n    router.back()\n  }\n}\n\n/**\n * @param {number} [offset]\n */\nfunction historyForward(offset) {\n  if (offset != null) {\n    goToOffset(offset)\n  } else {\n    router.forward()\n  }\n}\n\nconst newWindowText = computed(() => {\n  return localizeAndAddKeyboardShortcutToActionTitle(\n    t('Open New Window'),\n    KeyboardShortcuts.APP.GENERAL.NEW_WINDOW\n  )\n})\n\nfunction createNewWindow() {\n  const url = new URL(window.location.href)\n  url.hash = landingPage.value\n\n  window.open(url.toString(), '_blank', 'noreferrer')\n}\n\nconst usingOnlySearchHistoryResults = computed(() => lastSuggestionQuery.value.length === 0)\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst latestMatchingSearchHistoryNames = computed(() => {\n  return store.getters.getLatestMatchingSearchHistoryNames(lastSuggestionQuery.value)\n})\n\n/** @type {import('vue').ComputedRef<string[]>} */\nconst latestSearchHistoryNames = computed(() => store.getters.getLatestSearchHistoryNames)\n\nconst activeDataList = computed(() => {\n  // show latest search history when the search bar is empty\n  if (usingOnlySearchHistoryResults.value) {\n    return latestSearchHistoryNames.value\n  }\n\n  const searchResults = [...latestMatchingSearchHistoryNames.value]\n\n  if (enableSearchSuggestions.value) {\n    for (const searchSuggestion of searchSuggestionsDataList.value) {\n      // prevent duplicate results between search history entries and YT search suggestions\n      if (latestMatchingSearchHistoryNames.value.includes(searchSuggestion)) {\n        continue\n      }\n\n      searchResults.push(searchSuggestion)\n\n      if (searchResults.length === SEARCH_RESULTS_DISPLAY_LIMIT) {\n        break\n      }\n    }\n  }\n\n  return searchResults\n})\n\nconst activeDataListProperties = computed(() => {\n  const searchHistoryEntriesCount = usingOnlySearchHistoryResults.value\n    ? latestSearchHistoryNames.value.length\n    : latestMatchingSearchHistoryNames.value.length\n\n  const properties = []\n\n  for (let i = 0; i < activeDataList.value.length; i++) {\n    properties.push(i < searchHistoryEntriesCount\n      ? { isRemoveable: true, iconName: 'clock-rotate-left' }\n      : { isRemoveable: false, iconName: 'magnifying-glass' }\n    )\n  }\n\n  return properties\n})\n\nconst isArrowBackwardDisabled = ref(true)\nconst isArrowForwardDisabled = ref(true)\n\nif (process.env.IS_ELECTRON || 'navigation' in window) {\n  watch(route, () => {\n    setNavigationHistoryDropdownOptions()\n\n    isArrowForwardDisabled.value = !window.navigation.canGoForward\n    isArrowBackwardDisabled.value = !window.navigation.canGoBack\n  }, { deep: true })\n} else {\n  // If the Navigation API isn't supported (Firefox and Safari)\n  // keep the back and forwards buttons always enabled\n  isArrowBackwardDisabled.value = false\n  isArrowForwardDisabled.value = false\n}\n\nlet navigationHistoryDropdownActiveEntry = null\nlet isLoadingNavigationHistory = false\nlet pendingNavigationHistoryLabel = null\n\nasync function setNavigationHistoryDropdownOptions() {\n  if (process.env.IS_ELECTRON) {\n    isLoadingNavigationHistory = true\n    const dropdownOptions = await window.ftElectron.getNavigationHistory()\n\n    const activeEntry = dropdownOptions.find(option => option.active)\n\n    if (pendingNavigationHistoryLabel) {\n      activeEntry.label = pendingNavigationHistoryLabel\n    }\n\n    navigationHistoryDropdownOptions.value = dropdownOptions\n    navigationHistoryDropdownActiveEntry = activeEntry\n    isLoadingNavigationHistory = false\n  }\n}\n\n/** @type {import('vue').ComputedRef<string>} */\nconst appTitle = computed(() => store.getters.getAppTitle)\n\nwatch(appTitle, (value) => {\n  nextTick(() => {\n    if (isLoadingNavigationHistory) {\n      pendingNavigationHistoryLabel = value\n    } else if (navigationHistoryDropdownActiveEntry) {\n      navigationHistoryDropdownActiveEntry.label = value\n    }\n  })\n})\n\nfunction toggleSideNav() {\n  store.commit('toggleSideNav')\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst searchFilterValueChanged = computed(() => store.getters.getSearchFilterValueChanged)\n\nfunction showSearchFilters() {\n  store.dispatch('showSearchFilters')\n}\n\nconst searchContainer = useTemplateRef('searchContainer')\nconst searchInput = useTemplateRef('searchInput')\n\n/** @type {import('vue').ComputedRef<any>} */\nconst searchSettings = computed(() => store.getters.getSearchSettings)\n\n/**\n * @param {string} queryText\n * @param {object} options\n * @param {MouseEvent} options.event\n */\nfunction goToSearch(queryText, { event }) {\n  const doCreateNewWindow = event && event.shiftKey\n\n  if (window.innerWidth <= MOBILE_WIDTH_THRESHOLD) {\n    searchContainer.value.blur()\n    showSearchContainer.value = false\n  } else {\n    searchInput.value.blur()\n  }\n\n  clearLocalSearchSuggestionsSession()\n\n  store.dispatch('getYoutubeUrlInfo', queryText).then((result) => {\n    switch (result.urlType) {\n      case 'video': {\n        const { videoId, timestamp, playlistId } = result\n\n        const query = {}\n        if (timestamp) {\n          query.timestamp = timestamp\n        }\n        if (playlistId && playlistId.length > 0) {\n          query.playlistId = playlistId\n        }\n\n        openInternalPath({\n          path: `/watch/${videoId}`,\n          query,\n          doCreateNewWindow,\n          searchQueryText: queryText,\n        })\n        break\n      }\n\n      case 'playlist': {\n        const { playlistId, query } = result\n\n        openInternalPath({\n          path: `/playlist/${playlistId}`,\n          query,\n          doCreateNewWindow,\n          searchQueryText: queryText,\n        })\n        break\n      }\n\n      case 'search': {\n        const { searchQuery, query } = result\n\n        openInternalPath({\n          path: `/search/${encodeURIComponent(searchQuery)}`,\n          query,\n          doCreateNewWindow,\n          searchQueryText: searchQuery,\n        })\n        break\n      }\n\n      case 'hashtag': {\n        const { hashtag } = result\n        openInternalPath({\n          path: `/hashtag/${encodeURIComponent(hashtag)}`,\n          doCreateNewWindow,\n          searchQueryText: `#${hashtag}`,\n        })\n\n        break\n      }\n\n      case 'post': {\n        const { postId, query } = result\n\n        openInternalPath({\n          path: `/post/${postId}`,\n          query,\n          doCreateNewWindow,\n          searchQueryText: queryText,\n        })\n        break\n      }\n\n      case 'channel': {\n        const { channelId, subPath, url } = result\n\n        openInternalPath({\n          path: `/channel/${channelId}/${subPath}`,\n          doCreateNewWindow,\n          query: {\n            url,\n          },\n          searchQueryText: queryText,\n        })\n        break\n      }\n\n      case 'trending':\n      case 'subscriptions':\n      case 'history':\n      case 'userplaylists':\n        openInternalPath({\n          path: `/${result.urlType}`,\n          doCreateNewWindow,\n          searchQueryText: queryText\n        })\n        break\n\n      case 'invalid_url':\n      default: {\n        openInternalPath({\n          path: `/search/${encodeURIComponent(queryText)}`,\n          query: {\n            sortBy: searchSettings.value.sortBy,\n            time: searchSettings.value.time,\n            type: searchSettings.value.type,\n            duration: searchSettings.value.duration,\n            // Array proxy cannot be cloned during IPC call\n            features: [...searchSettings.value.features],\n          },\n          doCreateNewWindow,\n          searchQueryText: queryText,\n        })\n      }\n    }\n\n    if (doCreateNewWindow) {\n      // Query text copied to new window = can be removed from current window\n      updateSearchInputText('')\n    }\n  })\n}\n\nfunction clearLastSuggestionQuery() {\n  lastSuggestionQuery.value = ''\n}\n\n/**\n * @param {string} text\n */\nfunction updateSearchInputText(text) {\n  searchInput.value?.setText(text)\n}\n\n/**\n * @param {string} query\n */\nfunction getSearchSuggestionsDebounce(query) {\n  if (query === lastSuggestionQuery.value) {\n    return\n  }\n\n  lastSuggestionQuery.value = query\n\n  if (enableSearchSuggestions.value) {\n    debounceSearchResults(query.trim())\n  }\n}\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\nconst debounceSearchResults = debounce(/** @param {string} query */(query) => {\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    getSearchSuggestionsInvidious(query)\n  } else {\n    getSearchSuggestionsLocal(query)\n  }\n}, 200)\n\n/**\n * @param {string} query\n */\nasync function getSearchSuggestionsLocal(query) {\n  searchSuggestionsDataList.value = query.length > 0\n    ? await getLocalSearchSuggestions(query)\n    : []\n}\n\nasync function getSearchSuggestionsInvidious(query) {\n  if (query === '') {\n    searchSuggestionsDataList.value = []\n    return\n  }\n\n  try {\n    searchSuggestionsDataList.value = (await getInvidiousSearchSuggestions(query)).suggestions\n  } catch (err) {\n    console.error(err)\n\n    if (process.env.SUPPORTS_LOCAL_API && backendFallback.value) {\n      console.error(\n        'Error gettings search suggestions.  Falling back to Local API'\n      )\n      getSearchSuggestionsLocal(query)\n    }\n  }\n}\n\n/**\n * @param {string} query\n */\nfunction removeSearchHistoryEntryInDbAndCache(query) {\n  store.dispatch('removeSearchHistoryEntry', query)\n  store.commit('removeFromSessionSearchHistory', query)\n}\n\nfunction toggleSearchContainer() {\n  showSearchContainer.value = !showSearchContainer.value\n}\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction handleKeyboardShortcuts(event) {\n  const ctrlOrCommandPressed = (process.platform !== 'darwin' && event.ctrlKey) ||\n    (process.platform === 'darwin' && event.metaKey)\n\n  if (\n    !hideSearchBar.value &&\n    (\n      (ctrlOrCommandPressed && (event.key === 'L' || event.key === 'l')) ||\n      (event.altKey && (event.key === 'D' || event.key === 'd' || (process.platform === 'darwin' && event.key === '∂')))\n    )\n  ) {\n    event.preventDefault()\n\n    // In order to prevent Klipper's \"Synchronize contents of the clipboard\n    // and the selection\" feature from being triggered when running\n    // Chromium on KDE Plasma, it seems both focus() focus and\n    // select() have to be called asynchronously (see issue #2019).\n    setTimeout(() => {\n      searchInput.value?.focus()\n      searchInput.value?.select()\n    }, 0)\n  }\n}\n\nlet previousWindowWidth\n\nfunction handleWindowResize() {\n  // Don't change the status of showSearchContainer if only the height of the window changes\n  // Opening the virtual keyboard can trigger this resize event, but it won't change the width\n  if (previousWindowWidth !== window.innerWidth) {\n    showSearchContainer.value = window.innerWidth > MOBILE_WIDTH_THRESHOLD\n    previousWindowWidth = window.innerWidth\n  }\n}\n\nonMounted(() => {\n  previousWindowWidth = window.innerWidth\n  if (window.innerWidth <= MOBILE_WIDTH_THRESHOLD) {\n    showSearchContainer.value = false\n  }\n\n  // Store is not up-to-date when the component mounts, so we use timeout.\n  setTimeout(() => {\n    if (store.getters.getExpandSideBar) {\n      toggleSideNav()\n    }\n  }, 0)\n\n  window.addEventListener('resize', handleWindowResize)\n\n  if (process.env.IS_ELECTRON) {\n    window.addEventListener('keydown', handleKeyboardShortcuts)\n\n    window.ftElectron.handleUpdateSearchInputText((searchQueryText) => {\n      if (searchQueryText) {\n        updateSearchInputText(searchQueryText)\n      }\n    })\n  }\n})\n\nonBeforeUnmount(() => {\n  window.removeEventListener('resize', handleWindowResize)\n\n  if (process.env.IS_ELECTRON) {\n    window.removeEventListener('keydown', handleKeyboardShortcuts)\n\n    window.ftElectron.handleUpdateSearchInputText(null)\n  }\n})\n</script>\n\n<style scoped lang=\"scss\" src=\"./TopNav.scss\" />\n"
  },
  {
    "path": "src/renderer/components/WatchVideoChapters/WatchVideoChapters.css",
    "content": ".videoChapters {\n  overflow-y: hidden;\n}\n\n.chaptersSummary {\n  margin-block: 10px 0;\n  cursor: pointer;\n  list-style: none;\n}\n\n.chaptersTitle {\n  margin-block: 0;\n}\n\n.currentChapter {\n  font-size: 15px;\n}\n\n.chaptersWrapper {\n  margin-block-start: 15px;\n  max-block-size: 250px;\n  overflow-y: scroll;\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n}\n\n.chaptersWrapper.compact {\n  max-block-size: 200px;\n}\n\n.chaptersChevron {\n  vertical-align: middle;\n}\n\n.chaptersDetails[open] .chaptersChevron {\n  transform: translateX(4px) rotate(90deg);\n}\n\n.chaptersDetails[open]:dir(rtl) .chaptersChevron {\n  transform: translateX(-4px) rotate(90deg);\n}\n\n.chapter {\n  display: grid;\n  grid-template:\n    'thumbnail title' 2fr\n    'thumbnail timestamp' 2fr / auto 1fr;\n  column-gap: 10px;\n  cursor: pointer;\n  font-size: 15px;\n}\n\n.chaptersWrapper.compact .chapter {\n  display: flex;\n  flex-direction: row;\n}\n\n.chapterThumbnail {\n  grid-area: thumbnail;\n  inline-size: 130px;\n  margin: 3px;\n}\n\n.chapter.current .chapterThumbnail {\n  border: solid 3px var(--accent-color);\n  margin: 0;\n}\n\n.chapterTitle {\n  grid-area: title;\n  align-self: center;\n  margin: 0;\n}\n\n.chapter.current .chapterTitle {\n  font-weight: bold;\n}\n\n.chapterTimestamp {\n  grid-area: timestamp;\n  place-self: flex-start start;\n  padding-block: 3px;\n  padding-inline: 4px;\n  border-radius: 5px;\n  background-color: var(--accent-color);\n  color: var(--text-with-accent-color);\n}\n"
  },
  {
    "path": "src/renderer/components/WatchVideoChapters/WatchVideoChapters.vue",
    "content": "<template>\n  <FtCard class=\"videoChapters\">\n    <details\n      class=\"chaptersDetails\"\n      @toggle=\"chaptersToggled\"\n    >\n      <summary\n        class=\"chaptersSummary\"\n      >\n        <h3 class=\"chaptersTitle\">\n          {{ kind === 'keyMoments' ? $t('Chapters.Key Moments') : $t(\"Chapters.Chapters\") }}\n\n          <span class=\"currentChapter\">\n            • <bdi>{{ currentTitle }}</bdi>\n          </span>\n\n          <FontAwesomeIcon\n            class=\"chaptersChevron\"\n            :icon=\"['fas', 'chevron-right']\"\n          />\n        </h3>\n      </summary>\n\n      <div\n        ref=\"chaptersWrapper\"\n        v-observe-visibility=\"observeVisibilityOptions\"\n        class=\"chaptersWrapper\"\n        :class=\"{ compact }\"\n        @keydown.arrow-up.stop.prevent=\"navigateChapters('up')\"\n        @keydown.arrow-down.stop.prevent=\"navigateChapters('down')\"\n      >\n        <div\n          v-for=\"(chapter, index) in chapters\"\n          :key=\"index\"\n          class=\"chapter\"\n          role=\"button\"\n          tabindex=\"0\"\n          :aria-selected=\"index === currentIndex\"\n          :class=\"{ current: index === currentIndex }\"\n          @click=\"changeChapter(index)\"\n          @keydown.space.stop.prevent=\"changeChapter(index)\"\n          @keydown.enter.stop.prevent=\"changeChapter(index)\"\n        >\n          <!-- Setting the aspect ratio avoids layout shifts when the images load -->\n          <img\n            v-if=\"!compact\"\n            alt=\"\"\n            aria-hidden=\"true\"\n            class=\"chapterThumbnail\"\n            loading=\"lazy\"\n            :src=\"chapter.thumbnail.url\"\n            :style=\"{ aspectRatio: chapter.thumbnail.width / chapter.thumbnail.height }\"\n          >\n          <div class=\"chapterTimestamp\">\n            {{ chapter.timestamp }}\n          </div>\n          <p\n            class=\"chapterTitle\"\n            dir=\"auto\"\n          >\n            {{ chapter.title }}\n          </p>\n        </div>\n      </div>\n    </details>\n  </FtCard>\n</template>\n\n<script setup>\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\n\nimport FtCard from '../ft-card/ft-card.vue'\n\nconst props = defineProps({\n  chapters: {\n    type: Array,\n    required: true\n  },\n  currentChapterIndex: {\n    type: Number,\n    required: true\n  },\n  kind: {\n    type: String,\n    default: 'chapters'\n  }\n})\n\nconst emit = defineEmits(['timestamp-event'])\n\nconst chaptersWrapper = useTemplateRef('chaptersWrapper')\n\nlet chaptersVisible = false\nconst currentIndex = ref(props.currentChapterIndex)\n\nwatch(() => props.currentChapterIndex, (value) => {\n  if (currentIndex.value !== value) {\n    currentIndex.value = value\n  }\n})\n\nconst currentChapter = computed(() => {\n  return props.chapters[currentIndex.value]\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentTitle = computed(() => {\n  return currentChapter.value.title\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst compact = computed(() => {\n  return !props.chapters[0].thumbnail\n})\n\nconst observeVisibilityOptions = {\n  callback: (isVisible, _entry) => {\n    // This is also fired when **hidden**\n    // No point doing anything if not visible\n    if (!isVisible) { return }\n    // Only auto scroll when expanded\n    if (!chaptersVisible) { return }\n\n    scrollToCurrentChapter()\n  },\n  intersection: {\n    // Only when it intersects with N% above bottom\n    rootMargin: '0% 0% 0% 0%',\n  },\n  // Callback responsible for scolling to current chapter multiple times\n  once: false,\n}\n\n/**\n * @param {number} index\n */\nfunction changeChapter(index) {\n  currentIndex.value = index\n  emit('timestamp-event', props.chapters[index].startSeconds)\n  window.scrollTo(0, 0)\n}\n\n/**\n * @param {'up' | 'down'} direction\n */\nfunction navigateChapters(direction) {\n  const chapterElements = Array.from(chaptersWrapper.value.children)\n  const focusedIndex = chapterElements.indexOf(document.activeElement)\n\n  let newIndex = focusedIndex\n  if (direction === 'up') {\n    if (focusedIndex === 0) {\n      newIndex = chapterElements.length - 1\n    } else {\n      newIndex--\n    }\n  } else {\n    if (focusedIndex === chapterElements.length - 1) {\n      newIndex = 0\n    } else {\n      newIndex++\n    }\n  }\n\n  chapterElements[newIndex].focus()\n}\n\n/**\n * @param {ToggleEvent} event\n */\nfunction chaptersToggled(event) {\n  chaptersVisible = event.target.open\n\n  if (chaptersVisible) {\n    scrollToCurrentChapter()\n  }\n}\n\nfunction scrollToCurrentChapter() {\n  const container = chaptersWrapper.value\n  const currentItem = container ? Array.from(container.children)[currentIndex.value] : null\n\n  if (currentItem != null) {\n    container.scrollTop = currentItem.offsetTop - container.offsetTop\n  }\n}\n</script>\n\n<style scoped src=\"./WatchVideoChapters.css\" />\n"
  },
  {
    "path": "src/renderer/components/WatchVideoDescription/WatchVideoDescription.css",
    "content": ".videoDescription {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  overflow-y: auto;\n  max-block-size: 20lh;\n}\n\n.description {\n  font-family: Roboto, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n  font-size: 17px;\n  white-space: pre-wrap;\n  overflow-wrap: anywhere;\n}\n\n.descriptionStatus {\n  margin: 0;\n  text-decoration: underline;\n  cursor: pointer;\n  color: var(--title-color);\n}\n\n.videoDescription.short {\n  cursor: pointer;\n}\n\n.videoDescription.short .descriptionStatus {\n  position: absolute;\n  inset-block-end: calc(1lh + 12px);\n  padding-block: 2px;\n  inset-inline-end: 16px;\n  padding-inline-start: 40px;\n  background: linear-gradient(270deg, var(--card-bg-color) 75%, transparent 100%);\n  text-decoration: none;\n}\n\n.videoDescription:not(.short) .descriptionStatus {\n  position: relative;\n  margin-block-start: 1em;\n}\n\n.videoDescription.short .descriptionStatus:dir(rtl) {\n  background: linear-gradient(270deg, transparent 0%, var(--card-bg-color) 25%);\n}\n\n.videoDescription.short .description {\n  max-block-size: 4lh;\n  overflow: hidden;\n}\n\n.license {\n  margin-block: 1em;\n}\n"
  },
  {
    "path": "src/renderer/components/WatchVideoDescription/WatchVideoDescription.vue",
    "content": "<template>\n  <FtCard\n    v-if=\"shownDescription.length > 0\"\n    :class=\"{ videoDescription: true, short: !showFullDescription }\"\n  >\n    <span\n      v-if=\"showControls && !showFullDescription\"\n      class=\"descriptionStatus\"\n      role=\"button\"\n      tabindex=\"0\"\n      @click=\"expandDescription\"\n      @keydown.space.prevent=\"expandDescription\"\n      @keydown.enter.prevent=\"expandDescription\"\n    >\n      {{ $t(\"Description.Expand Description\") }}\n    </span>\n    <FtTimestampCatcher\n      ref=\"descriptionContainer\"\n      class=\"description\"\n      :input-html=\"processedShownDescription\"\n      :link-tab-index=\"linkTabIndex\"\n      @timestamp-event=\"onTimestamp\"\n      @click=\"expandDescriptionWithClick\"\n    />\n    <bdi\n      v-if=\"license && showFullDescription\"\n      class=\"license\"\n    >\n      {{ license }}\n    </bdi>\n    <span\n      v-if=\"showControls && showFullDescription\"\n      class=\"descriptionStatus\"\n      role=\"button\"\n      tabindex=\"0\"\n      @click=\"collapseDescription\"\n      @keydown.space.prevent=\"collapseDescription\"\n      @keydown.enter.prevent=\"collapseDescription\"\n    >\n      {{ $t(\"Description.Collapse Description\") }}\n    </span>\n  </FtCard>\n</template>\n\n<script setup>\nimport autolinker from 'autolinker'\n\nimport { onMounted, ref, computed, useTemplateRef } from 'vue'\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtTimestampCatcher from '../FtTimestampCatcher.vue'\n\nconst props = defineProps({\n  description: {\n    type: String,\n    default: ''\n  },\n  descriptionHtml: {\n    type: String,\n    default: ''\n  },\n  license: {\n    type: String,\n    default: null,\n  }\n})\n\nconst emit = defineEmits(['timestamp-event'])\n\nlet shownDescription = ''\nconst descriptionContainer = useTemplateRef('descriptionContainer')\nconst showFullDescription = ref(false)\nconst showControls = ref(false)\n\nif (props.descriptionHtml !== '') {\n  const parsed = parseDescriptionHtml(props.descriptionHtml)\n\n  // the invidious API returns emtpy html elements when the description is empty\n  // so we need to parse it to see if there is any meaningful text in the html\n  // or if it's just empty html elements e.g. `<p></p>`\n\n  const testDiv = document.createElement('div')\n  testDiv.innerHTML = parsed\n\n  if (!/^\\s*$/.test(testDiv.innerText)) {\n    shownDescription = parsed\n  }\n} else {\n  if (!/^\\s*$/.test(props.description)) {\n    shownDescription = autolinker.link(props.description)\n  }\n}\n\nconst processedShownDescription = computed(() => {\n  if (shownDescription === '') { return shownDescription }\n\n  return processDescriptionHtml(shownDescription, linkTabIndex.value)\n})\n\nconst linkTabIndex = computed(() => {\n  return showFullDescription.value ? '0' : '-1'\n})\n\n/**\n * @param {number} timestamp\n */\nfunction onTimestamp(timestamp) {\n  emit('timestamp-event', timestamp)\n}\n\n/**\n @param {PointerEvent} e\n */\nfunction expandDescriptionWithClick(e) {\n  // Ignore link clicks\n  if (e.target.tagName === 'A') { return }\n\n  expandDescription()\n}\n\n/**\n * Enables user to view entire contents of description\n */\nfunction expandDescription() {\n  showFullDescription.value = true\n}\n\n/**\n * Enables user to collapse contents of description\n */\nfunction collapseDescription() {\n  showFullDescription.value = false\n}\n\n/**\n * Returns true when description content does not overflow description container\n * Useful for hiding description expansion/contraction controls\n */\nfunction isShortDescription() {\n  const descriptionElem = descriptionContainer.value?.$el\n  return descriptionElem?.clientHeight >= descriptionElem?.scrollHeight\n}\n\nonMounted(() => {\n  // To verify whether or not the description is too short for displaying\n  // description controls, we need to check the description's dimensions.\n  // The only way to make this work is to check on mount.\n  showFullDescription.value = isShortDescription()\n  showControls.value = !showFullDescription.value\n})\n\n/**\n * @param {string} descriptionText\n * @returns {string}\n */\nfunction parseDescriptionHtml(descriptionText) {\n  return descriptionText\n    .replaceAll('target=\"_blank\"', '')\n    .replaceAll(/\\/redirect.+?(?=q=)/g, '')\n    .replaceAll('q=', '')\n    .replaceAll(/rel=\"nofollow\\snoopener\"/g, '')\n    .replaceAll(/class=.+?(?=\")./g, '')\n    .replaceAll(/id=.+?(?=\")./g, '')\n    .replaceAll(/data-target-new-window=.+?(?=\")./g, '')\n    .replaceAll(/data-url=.+?(?=\")./g, '')\n    .replaceAll(/data-sessionlink=.+?(?=\")./g, '')\n    .replaceAll('&amp;', '&')\n    .replaceAll('%3A', ':')\n    .replaceAll('%2F', '/')\n    .replaceAll(/&v.+?(?=\")/g, '')\n    .replaceAll(/&redirect-token.+?(?=\")/g, '')\n    .replaceAll(/&redir_token.+?(?=\")/g, '')\n    .replaceAll('href=\"/', 'href=\"https://www.youtube.com/')\n    .replaceAll('href=\"/hashtag/', 'href=\"https://wwww.youtube.com/hashtag/')\n    .replaceAll('yt.www.watch.player.seekTo', 'changeDuration')\n}\n\n/**\n * @param {string} descriptionText\n * @param {string} tabIndex\n * @returns {string}\n */\nfunction processDescriptionHtml(descriptionText, tabIndex) {\n  return descriptionText\n    .replaceAll('<a', `<a tabindex=\"${tabIndex}\"`)\n}\n</script>\n\n<style scoped src=\"./WatchVideoDescription.css\" />\n"
  },
  {
    "path": "src/renderer/components/WatchVideoInfo/WatchVideoInfo.css",
    "content": ".watchVideoInfo {\n  display: flex;\n  flex-direction: column;\n  padding: 16px;\n  gap: 8px;\n}\n\n.videoTitle {\n  display: block;\n  font-size: 22px;\n  font-weight: normal;\n  margin-block: 0;\n  margin-inline: 0;\n  overflow-wrap: break-word;\n}\n\n.videoMetrics,\n.videoButtons {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  gap: 10px;\n}\n\n.unlistedBadge {\n  background-color: var(--secondary-card-bg-color);\n  border-radius: 5px;\n  display: inline;\n  padding-inline: 5px;\n  padding-block: 2px;\n  white-space: nowrap;\n  font-size: 13px;\n  font-weight: 500;\n}\n\n.profileRow {\n  display: flex;\n  align-items: center;\n}\n\n.channelThumbnail {\n  border-radius: 50%;\n  cursor: pointer;\n  margin-inline-end: 10px;\n  inline-size: 56px;\n}\n\n.channelName {\n  color: inherit;\n  cursor: pointer;\n  display: block;\n  margin-inline-start: 6px;\n  margin-block-end: 3px;\n  position: relative;\n  text-decoration: inherit;\n  inset-block-start: -2px;\n}\n\n.videoMetrics {\n  font-size: 14px;\n  color: var(--tertiary-text-color);\n}\n\n.likeSection {\n  color: var(--tertiary-text-color);\n  display: flex;\n  flex-direction: column;\n  margin-inline-start: auto;\n  margin-block-start: 4px;\n  max-inline-size: 210px;\n  text-align: end;\n}\n\n.likeBar {\n  border-radius: 4px;\n  block-size: 8px;\n  margin-block-end: 4px;\n}\n\n.likeCount {\n  margin-inline-end: 0;\n  display: flex;\n  gap: 3px;\n}\n\n.videoViews {\n  white-space: nowrap;\n}\n\n.videoOptions {\n  display: flex;\n  gap: 4px;\n}\n\n.videoOptionsMobileRow {\n  display: flex;\n  gap: 4px;\n}\n\n@media screen and (width <= 730px) {\n  .videoButtons {\n    flex-direction: column;\n    align-items: flex-start;\n    margin-block-start: 10px;\n  }\n}\n\n@media screen and (width <= 680px) {\n  .likeSection {\n    margin-inline-start: 0;\n    text-align: start;\n  }\n}\n\n@media screen and (width <= 460px) {\n  .datePublishedAndViewCount {\n    display: flex;\n    justify-content: left;\n    flex-direction: column;\n  }\n\n  .seperator {\n    display: none;\n  }\n}\n\n@media screen and (width <= 380px) {\n  .videoOptions {\n    flex-direction: column;\n    align-items: flex-start;\n    margin-block-start: 10px;\n  }\n\n  .videoOptionsMobileRow :deep(.iconDropdown) {\n    inset-inline: 0 auto;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/WatchVideoInfo/WatchVideoInfo.vue",
    "content": "<template>\n  <FtCard class=\"watchVideoInfo\">\n    <div>\n      <h1\n        class=\"videoTitle\"\n        dir=\"auto\"\n      >\n        {{ title }}\n      </h1>\n      <div\n        v-if=\"isUnlisted\"\n        class=\"unlistedBadge\"\n      >\n        {{ t('Video.Unlisted') }}\n      </div>\n    </div>\n    <div class=\"videoMetrics\">\n      <div class=\"datePublishedAndViewCount\">\n        {{ publishedString }} {{ dateString }}\n        <template\n          v-if=\"!hideVideoViews\"\n        >\n          <span class=\"seperator\">• </span><span class=\"videoViews\">{{ parsedViewCount }}</span>\n        </template>\n      </div>\n      <div\n        v-if=\"!hideVideoLikesAndDislikes\"\n        class=\"likeBarContainer\"\n      >\n        <div\n          class=\"likeSection\"\n        >\n          <span class=\"likeCount\"><FontAwesomeIcon :icon=\"['fas', 'thumbs-up']\" /> {{ parsedLikeCount }}</span>\n        </div>\n      </div>\n    </div>\n    <div class=\"videoButtons\">\n      <div\n        class=\"profileRow\"\n      >\n        <div\n          v-if=\"!hideUploader\"\n        >\n          <RouterLink\n            :to=\"`/channel/${channelId}`\"\n          >\n            <img\n              :src=\"channelThumbnail\"\n              class=\"channelThumbnail\"\n              alt=\"\"\n            >\n          </RouterLink>\n        </div>\n        <div>\n          <div\n            v-if=\"!hideUploader\"\n          >\n            <RouterLink\n              :to=\"`/channel/${channelId}`\"\n              class=\"channelName\"\n              dir=\"auto\"\n            >\n              {{ channelName }}\n            </RouterLink>\n          </div>\n          <FtSubscribeButton\n            v-if=\"!hideUnsubscribeButton\"\n            :channel-id=\"channelId\"\n            :channel-name=\"channelName\"\n            :channel-thumbnail=\"channelThumbnail\"\n            :subscription-count-text=\"subscriptionCountText\"\n          />\n        </div>\n      </div>\n      <div class=\"videoOptions\">\n        <span class=\"videoOptionsMobileRow\">\n          <FtIconButton\n            v-if=\"showPlaylists && !isUpcoming\"\n            :title=\"t('User Playlists.Add to Playlist')\"\n            :icon=\"['fas', 'plus']\"\n            theme=\"base\"\n            @click=\"togglePlaylistPrompt\"\n          />\n          <FtIconButton\n            v-if=\"isQuickBookmarkEnabled\"\n            :title=\"quickBookmarkIconText\"\n            :icon=\"isInQuickBookmarkPlaylist ? ['fas', 'check'] : ['fas', 'bookmark']\"\n            class=\"quickBookmarkVideoIcon\"\n            :class=\"{\n              bookmarked: isInQuickBookmarkPlaylist,\n            }\"\n            :theme=\"quickBookmarkIconTheme\"\n            @click=\"toggleQuickBookmarked\"\n          />\n          <FtIconButton\n            v-if=\"canSaveWatchedProgress && watchedProgressSavingInSemiAutoMode\"\n            :title=\"t('Video.Save Watched Progress')\"\n            :icon=\"['fas', 'bars-progress']\"\n            @click=\"saveWatchedProgressManually\"\n          />\n        </span>\n        <span class=\"videoOptionsMobileRow\">\n          <FtIconButton\n            v-if=\"USING_ELECTRON && externalPlayer !== ''\"\n            :title=\"t('Video.External Player.OpenInTemplate', { externalPlayer })\"\n            :icon=\"['fas', 'external-link-alt']\"\n            theme=\"secondary\"\n            @click=\"handleExternalPlayer\"\n          />\n          <FtIconButton\n            v-if=\"!isUpcoming\"\n            :title=\"t('Change Format.Change Media Formats')\"\n            theme=\"secondary\"\n            :icon=\"['fas', 'file-video']\"\n            :dropdown-options=\"formatTypeOptions\"\n            @click=\"changeFormat\"\n          />\n          <FtShareButton\n            v-if=\"!hideSharingActions\"\n            :id=\"id\"\n            :get-timestamp=\"getTimestamp\"\n            :playlist-id=\"playlistId\"\n          />\n        </span>\n      </div>\n    </div>\n  </FtCard>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onMounted } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\nimport FtShareButton from '../FtShareButton/FtShareButton.vue'\nimport FtSubscribeButton from '../FtSubscribeButton/FtSubscribeButton.vue'\n\nimport store from '../../store'\n\nimport { formatNumber, showToast } from '../../helpers/utils'\n\nconst props = defineProps({\n  id: {\n    type: String,\n    required: true\n  },\n  title: {\n    type: String,\n    required: true\n  },\n  channelId: {\n    type: String,\n    required: true\n  },\n  channelName: {\n    type: String,\n    required: true\n  },\n  channelThumbnail: {\n    type: String,\n    required: true\n  },\n  published: {\n    type: Number,\n    required: true\n  },\n  premiereDate: {\n    type: Date,\n    default: undefined\n  },\n  viewCount: {\n    type: Number,\n    default: null\n  },\n  subscriptionCountText: {\n    type: String,\n    required: true\n  },\n  likeCount: {\n    type: Number,\n    default: 0\n  },\n  dislikeCount: {\n    type: Number,\n    default: 0\n  },\n  getTimestamp: {\n    type: Function,\n    required: true\n  },\n  isLive: {\n    type: Boolean,\n    required: false\n  },\n  isLiveContent: {\n    type: Boolean,\n    required: true\n  },\n  isUpcoming: {\n    type: Boolean,\n    required: true\n  },\n  playlistId: {\n    type: String,\n    default: null\n  },\n  getPlaylistIndex: {\n    type: Function,\n    required: true\n  },\n  getPlaylistReverse: {\n    type: Function,\n    required: true\n  },\n  getPlaylistShuffle: {\n    type: Function,\n    required: true\n  },\n  getPlaylistLoop: {\n    type: Function,\n    required: true\n  },\n  lengthSeconds: {\n    type: Number,\n    required: true\n  },\n  videoThumbnail: {\n    type: String,\n    required: true\n  },\n  inUserPlaylist: {\n    type: Boolean,\n    required: true\n  },\n  isUnlisted: {\n    type: Boolean,\n    required: false\n  },\n  canSaveWatchedProgress: {\n    type: Boolean,\n    required: true\n  },\n})\n\nconst emit = defineEmits([\n  'change-format',\n  'pause-player',\n  'save-watched-progress',\n])\n\nconst USING_ELECTRON = process.env.IS_ELECTRON\n\nconst { locale, t } = useI18n()\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSharingActions = computed(() => store.getters.getHideSharingActions)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUnsubscribeButton = computed(() => store.getters.getHideUnsubscribeButton)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUploader = computed(() => store.getters.getHideUploader)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoLikesAndDislikes = computed(() => store.getters.getHideVideoLikesAndDislikes)\n\nconst parsedLikeCount = computed(() => {\n  if (hideVideoLikesAndDislikes.value || props.likeCount === null) {\n    return null\n  }\n\n  return formatNumber(props.likeCount)\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoViews = computed(() => store.getters.getHideVideoViews)\n\nconst parsedViewCount = computed(() => {\n  if (hideVideoViews.value || props.viewCount == null) {\n    return null\n  }\n\n  return t('Global.Counts.View Count', { count: formatNumber(props.viewCount) }, props.viewCount)\n})\n\nconst dateString = computed(() => {\n  const formatter = new Intl.DateTimeFormat([locale.value, 'en'], { dateStyle: 'medium' })\n  const localeDateString = formatter.format(props.published)\n  // replace spaces with no break spaces to make the date act as a single entity while wrapping\n  return localeDateString.replaceAll(' ', '\\u00A0')\n})\n\nconst publishedString = computed(() => {\n  if (props.isLive) {\n    return t('Video.Started streaming on')\n  } else if (props.isLiveContent && !props.isLive) {\n    return t('Video.Streamed on')\n  } else {\n    return t('Video.Published on')\n  }\n})\n\nconst formatTypeOptions = computed(() => [\n  {\n    label: t('Change Format.Use Dash Formats'),\n    value: 'dash'\n  },\n  {\n    label: t('Change Format.Use Legacy Formats'),\n    value: 'legacy'\n  },\n  {\n    label: t('Change Format.Use Audio Formats'),\n    value: 'audio'\n  }\n])\n\n/**\n * @param {'dash' | 'legacy' | 'audio'} value\n */\nfunction changeFormat(value) {\n  emit('change-format', value)\n}\n\nconst watchedProgressSavingInSemiAutoMode = computed(() => {\n  return store.getters.getWatchedProgressSavingMode === 'semi-auto'\n})\n\nfunction saveWatchedProgressManually() {\n  emit('save-watched-progress')\n}\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst rememberHistory = computed(() => store.getters.getRememberHistory)\n\nconst historyEntryExists = computed(() => store.getters.getHistoryCacheById[props.id] !== undefined)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst externalPlayer = computed(() => store.getters.getExternalPlayer)\n\n/** @type {import('vue').ComputedRef<number>} */\nconst defaultPlayback = computed(() => store.getters.getDefaultPlayback)\n\nfunction handleExternalPlayer() {\n  emit('pause-player')\n\n  let payload\n\n  // Only play video in non playlist mode when user playlist detected\n  if (props.inUserPlaylist) {\n    payload = {\n      videoId: props.id,\n      startTime: props.getTimestamp(),\n      playbackRate: defaultPlayback.value,\n    }\n  } else {\n    payload = {\n      videoId: props.id,\n      playlistId: props.playlistId,\n      startTime: props.getTimestamp(),\n      playbackRate: defaultPlayback.value,\n      playlistIndex: props.getPlaylistIndex(),\n      playlistReverse: props.getPlaylistReverse(),\n      playlistShuffle: props.getPlaylistShuffle(),\n      playlistLoop: props.getPlaylistLoop()\n    }\n  }\n\n  if (process.env.IS_ELECTRON) {\n    window.ftElectron.openInExternalPlayer(payload)\n  }\n\n  if (rememberHistory.value) {\n    // Marking as watched\n    const videoData = {\n      videoId: props.id,\n      title: props.title,\n      author: props.channelName,\n      authorId: props.channelId,\n      published: props.published,\n      description: props.description,\n      viewCount: props.viewCount,\n      lengthSeconds: props.lengthSeconds,\n      watchProgress: 0,\n      timeWatched: Date.now(),\n      isLive: false,\n      type: 'video'\n    }\n\n    store.dispatch('updateHistory', videoData)\n\n    if (!historyEntryExists.value) {\n      showToast(t('Video.Video has been marked as watched'))\n    }\n  }\n}\n\nonMounted(() => {\n  if (process.env.IS_ELECTRON || 'mediaSession' in navigator) {\n    navigator.mediaSession.metadata = new MediaMetadata({\n      title: props.title,\n      artist: props.channelName,\n      artwork: [{\n        src: props.videoThumbnail,\n        sizes: '128x128',\n        type: 'img/png'\n      }]\n    })\n  }\n})\n\nconst showPlaylists = computed(() => !store.getters.getHidePlaylists)\n\nfunction togglePlaylistPrompt() {\n  const videoData = {\n    videoId: props.id,\n    title: props.title,\n    author: props.channelName,\n    authorId: props.channelId,\n    description: props.description,\n    viewCount: props.viewCount,\n    lengthSeconds: props.lengthSeconds,\n    published: props.published,\n    premiereDate: props.premiereDate\n  }\n\n  store.dispatch('showAddToPlaylistPromptForManyVideos', { videos: [videoData] })\n}\n\nconst quickBookmarkPlaylist = computed(() => store.getters.getQuickBookmarkPlaylist)\n\nconst isQuickBookmarkEnabled = computed(() => quickBookmarkPlaylist.value != null)\n\nconst isInQuickBookmarkPlaylist = computed(() => {\n  if (!isQuickBookmarkEnabled.value) { return false }\n\n  // Accessing a reactive property has a negligible amount of overhead,\n  // however as we know that some users have playlists that have more than 10k items in them\n  // it adds up quickly. So create a temporary variable outside of the array, so we only have to do it once.\n  // Also the search is retriggered every time any playlist is modified.\n  const id = props.id\n\n  return quickBookmarkPlaylist.value.videos.some((video) => {\n    return video.videoId === id\n  })\n})\n\nconst quickBookmarkIconText = computed(() => {\n  if (!isQuickBookmarkEnabled.value) { return '' }\n\n  const translationProperties = {\n    playlistName: quickBookmarkPlaylist.value.playlistName,\n  }\n  return isInQuickBookmarkPlaylist.value\n    ? t('User Playlists.Remove from Favorites', translationProperties)\n    : t('User Playlists.Add to Favorites', translationProperties)\n})\n\nconst quickBookmarkIconTheme = computed(() => isInQuickBookmarkPlaylist.value ? 'base favorite' : 'base')\n\nfunction toggleQuickBookmarked() {\n  if (!isQuickBookmarkEnabled.value) {\n    // This should be prevented by UI\n    return\n  }\n\n  if (isInQuickBookmarkPlaylist.value) {\n    removeFromQuickBookmarkPlaylist()\n  } else {\n    addToQuickBookmarkPlaylist()\n  }\n}\n\nfunction addToQuickBookmarkPlaylist() {\n  const videoData = {\n    videoId: props.id,\n    title: props.title,\n    author: props.channelName,\n    authorId: props.channelId,\n    lengthSeconds: props.lengthSeconds,\n    published: props.published,\n    premiereDate: props.premiereDate\n  }\n\n  store.dispatch('addVideo', {\n    _id: quickBookmarkPlaylist.value._id,\n    videoData,\n  })\n\n  // TODO: Maybe show playlist name\n  showToast(t('Video.Video has been saved'))\n}\n\nfunction removeFromQuickBookmarkPlaylist() {\n  store.dispatch('removeVideo', {\n    _id: quickBookmarkPlaylist.value._id,\n    // Remove all playlist items with same videoId\n    videoId: props.id,\n  })\n\n  // TODO: Maybe show playlist name\n  showToast(t('Video.Video has been removed from your saved list'))\n}\n</script>\n\n<style scoped src=\"./WatchVideoInfo.css\" />\n"
  },
  {
    "path": "src/renderer/components/WatchVideoLiveChat/WatchVideoLiveChat.css",
    "content": ".card.hasError {\n  block-size: auto !important;\n  padding: 16px;\n}\n\n.relative {\n  position: relative;\n}\n\n.messageContainer {\n  inline-size: 100%;\n  block-size: 100%;\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n}\n\n.messageContainer.hasError {\n  flex-direction: column;\n  row-gap: 16px;\n}\n\n.watchingCount {\n  font-weight: normal;\n  margin-inline-start: 5px;\n  font-size: 15px;\n  color: var(--tertiary-text-color);\n}\n\n.message {\n  font-size: 18px;\n  color: var(--tertiary-text-color);\n  padding: 0;\n  margin: 0;\n  overflow-wrap: break-word;\n}\n\n:deep(.liveChatEmoji) {\n  vertical-align: middle;\n  margin-block: 0;\n  margin-inline: 2px;\n}\n\n.errorIcon {\n  inline-size: 100%;\n  color: var(--tertiary-text-color);\n  font-size: 100px;\n}\n\n.enableLiveChat {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n}\n\n.superChatComments {\n  inline-size: 100%;\n  block-size: 50px;\n  overflow-x: auto;\n  white-space: nowrap;\n}\n\n.superChat {\n  display: inline-block;\n  padding: 1px;\n  padding-inline-end: 10px;\n  margin-inline: 2px;\n  block-size: 30px;\n  cursor: pointer;\n  background-color: var(--primary-color);\n  border-radius: 200px;\n}\n\n.superChatContent {\n  margin-inline-start: 32px;\n  margin-block-start: -25px;\n  color: var(--text-with-main-color);\n}\n\n.channelThumbnail {\n  inline-size: 25px;\n  border-radius: 200px;\n}\n\n.channelName {\n  color: var(--tertiary-text-color);\n  font-weight: bold;\n  padding-inline-end: 5px;\n}\n\n.superChat .channelThumbnail {\n  margin-block-start: 3px;\n  margin-inline-start: 3px;\n  block-size: 25px;\n}\n\n.donationAmount {\n  color: var(--text-with-main-color);\n}\n\n.openedSuperChat {\n  background-color: rgb(0 0 0 / 70%);\n  inline-size: 100%;\n  block-size: 415px;\n  position: absolute;\n  margin-inline-start: -16px;\n  padding-inline-end: 32px;\n  inset-block-end: -15px;\n  cursor: auto;\n  z-index: 1;\n}\n\n.superChatMessage {\n  inline-size: 90%;\n  grid-template-columns: auto;\n  margin-inline: 5%;\n  margin-block: 25px 10px;\n  background-color: var(--primary-color);\n  border-radius: 5px;\n  position: relative;\n}\n\n.upperSuperChatMessage {\n  margin-block-start: -15px;\n  inline-size: 100%;\n  block-size: 55px;\n  background-color: var(--primary-color-hover);\n  border-radius: 5px 5px 0 0;\n}\n\n.openedSuperChat .superChatMessage {\n  position: absolute;\n}\n\n.comment .superChatMessage {\n  padding: 5px;\n}\n\n.comment .upperSuperChatMessage {\n  padding: 0;\n}\n\n.comment {\n  inline-size: 100%;\n  padding-block: 5px 7px;\n  display: grid;\n  grid-template-columns: min-content auto;\n  gap: 5px;\n}\n\n.upperSuperChatMessage .channelThumbnail {\n  inline-size: 45px;\n  margin-inline-start: 10px;\n  margin-block-start: 5px;\n}\n\n.upperSuperChatMessage .channelName {\n  color: var(--text-with-main-color);\n  opacity: 0.7;\n  position: absolute;\n  inset-block-start: -20px;\n  margin-inline-start: 65px;\n}\n\n.upperSuperChatMessage .donationAmount {\n  color: var(--text-with-main-color);\n  font-weight: bold;\n  margin-inline-start: 65px;\n  position: absolute;\n  inset-block-start: 0;\n}\n\n.superChatMessage .chatMessage {\n  color: var(--text-with-main-color);\n  margin-inline-start: 20px;\n}\n\n.liveChatComments {\n  inline-size: 100%;\n  overflow-y: auto;\n}\n\n.chatContent {\n  margin-block: 5px 2px;\n  font-size: 12px;\n  overflow-wrap: break-word;\n}\n\n.member {\n  color: #4caf50;\n}\n\n.moderator {\n  color: #2196f3;\n}\n\n.owner {\n  margin-inline-end: 2px;\n  background-color: var(--primary-color);\n  color: var(--text-with-main-color);\n}\n\n.badgeImage {\n  inline-size: 14px;\n}\n\n.scrollToBottom {\n  background-color: var(--accent-color);\n  inline-size: 35px;\n  block-size: 35px;\n  position: absolute;\n  inset-inline-start: 45%;\n  inset-block-end: 20px;\n  cursor: pointer;\n  border-radius: 200px;\n  text-align: center;\n  transition: background 0.2s ease-out;\n}\n\n.scrollToBottom:hover,\n.scrollToBottom:focus {\n  background-color: var(--accent-color-light);\n  transition: background 0.2s ease-in;\n}\n\n.icon {\n  color: var(--text-with-accent-color);\n  font-size: 22px;\n  position: relative;\n  inset-block-start: 0.45rem;\n}\n\n.title {\n  margin: 0;\n}\n\n.title,\n.popoutChatButton {\n  padding: 10px;\n}\n\n.popoutChatButton {\n  border-radius: 50%;\n  border-style: none;\n  background-color: transparent;\n  line-height: 1em;\n  color: var(--primary-text-color);\n  cursor: pointer;\n  font-size: 20px;\n  transition: background 0.2s ease-out;\n}\n\n.popoutChatButton:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.popoutChatButton:active {\n  background-color: var(--tertiary-text-color);\n  color: var(--side-nav-active-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.popoutChatIcon {\n  inline-size: 1em;\n  pointer-events: none;\n}\n\n.titleContainer {\n  display: flex;\n  justify-content: space-between;\n  margin-block: 1em;\n}\n"
  },
  {
    "path": "src/renderer/components/WatchVideoLiveChat/WatchVideoLiveChat.vue",
    "content": "<template>\n  <FtCard\n    class=\"card relative\"\n    :class=\"{ hasError }\"\n  >\n    <FtLoader\n      v-if=\"isLoading\"\n    />\n    <div\n      v-else-if=\"hasError\"\n      class=\"messageContainer\"\n      :class=\"{ hasError }\"\n    >\n      <p\n        class=\"message\"\n      >\n        {{ errorMessage }}\n      </p>\n      <FontAwesomeIcon\n        :icon=\"['fas', 'exclamation-circle']\"\n        class=\"errorIcon\"\n      />\n      <FtButton\n        v-if=\"showEnableChat\"\n        :label=\"t('Video.Enable Live Chat')\"\n        class=\"enableLiveChat\"\n        @click=\"enableLiveChat\"\n      />\n    </div>\n    <div\n      v-else-if=\"comments.length === 0\"\n      class=\"messageContainer liveChatMessage\"\n    >\n      <p\n        class=\"message\"\n      >\n        {{ t(\"Video['Live chat is enabled. Chat messages will appear here once sent.']\") }}\n      </p>\n    </div>\n    <div\n      v-else\n      class=\"relative\"\n    >\n      <div\n        class=\"titleContainer\"\n      >\n        <h4\n          class=\"title\"\n        >\n          {{ t(\"Video.Live Chat\") }}\n          <span\n            v-if=\"!hideVideoViews && watchingCount !== null\"\n            class=\"watchingCount\"\n          >\n            {{ t('Global.Counts.Watching Count', { count: formattedWatchingCount }, watchingCount) }}\n          </span>\n        </h4>\n        <a\n          :href=\"`https://www.youtube.com/live_chat?is_popout=1&v=${props.videoId}`\"\n          :aria-label=\"t('Video.Popout Live Chat')\"\n          :title=\"t('Video.Popout Live Chat')\"\n          target=\"_blank\"\n          class=\"popoutChatButton\"\n        >\n          <FontAwesomeIcon\n            class=\"popoutChatIcon\"\n            :icon=\"['fas', 'fa-arrow-up-right-from-square']\"\n          />\n        </a>\n      </div>\n      <div\n        v-if=\"superChatComments.length > 0\"\n        class=\"superChatComments\"\n      >\n        <div\n          v-for=\"comment in superChatComments\"\n          :key=\"comment.id\"\n          :aria-label=\"t('Video.Show Super Chat Comment')\"\n          class=\"superChat\"\n          :class=\"comment.superChat.colorClass\"\n          role=\"button\"\n          tabindex=\"0\"\n          @click=\"showSuperChatComment(comment)\"\n          @keydown.space.prevent=\"showSuperChatComment(comment)\"\n          @keydown.enter.prevent=\"showSuperChatComment(comment)\"\n        >\n          <img\n            :src=\"comment.author.thumbnailUrl\"\n            class=\"channelThumbnail\"\n            alt=\"\"\n          >\n          <p\n            class=\"superChatContent\"\n          >\n            <bdi\n              class=\"donationAmount\"\n            >\n              {{ comment.superChat.amount }}\n            </bdi>\n          </p>\n        </div>\n      </div>\n      <div\n        v-if=\"showSuperChat\"\n        class=\"openedSuperChat\"\n        :class=\"superChat.superChat.colorClass\"\n        role=\"button\"\n        tabindex=\"0\"\n        @click=\"hideSuperChat\"\n        @keydown.space.prevent=\"hideSuperChat\"\n        @keydown.enter.prevent=\"hideSuperChat\"\n      >\n        <div\n          class=\"superChatMessage\"\n          @click.stop.prevent\n        >\n          <div\n            class=\"upperSuperChatMessage\"\n          >\n            <img\n              :src=\"superChat.author.thumbnailUrl\"\n              class=\"channelThumbnail\"\n              alt=\"\"\n            >\n            <p\n              class=\"channelName\"\n              dir=\"auto\"\n            >\n              {{ superChat.author.name }}\n            </p>\n            <p\n              class=\"donationAmount\"\n              dir=\"auto\"\n            >\n              {{ superChat.superChat.amount }}\n            </p>\n          </div>\n          <p\n            v-safer-html=\"superChat.message\"\n            class=\"chatMessage\"\n            dir=\"auto\"\n          />\n        </div>\n      </div>\n      <div\n        ref=\"commentsRef\"\n        class=\"liveChatComments\"\n        :style=\"{ blockSize: chatHeight }\"\n        @mousewheel.passive=\"onScroll\"\n        @scrollend=\"e => onScroll(e, true)\"\n      >\n        <div\n          v-for=\"comment in comments\"\n          :key=\"comment.id\"\n          class=\"comment\"\n          :class=\"comment.superChat ? `superChatMessage ${comment.superChat.colorClass}` : ''\"\n        >\n          <template\n            v-if=\"comment.superChat\"\n          >\n            <div\n              class=\"upperSuperChatMessage\"\n            >\n              <img\n                :src=\"comment.author.thumbnailUrl\"\n                class=\"channelThumbnail\"\n                alt=\"\"\n              >\n              <p\n                class=\"channelName\"\n                dir=\"auto\"\n              >\n                {{ comment.author.name }}\n              </p>\n              <p\n                class=\"donationAmount\"\n                dir=\"auto\"\n              >\n                {{ comment.superChat.amount }}\n              </p>\n            </div>\n            <p\n              v-if=\"comment.message\"\n              v-safer-html=\"comment.message\"\n              class=\"chatMessage\"\n              dir=\"auto\"\n            />\n          </template>\n          <template\n            v-else\n          >\n            <img\n              :src=\"comment.author.thumbnailUrl\"\n              class=\"channelThumbnail\"\n              alt=\"\"\n            >\n            <p\n              class=\"chatContent\"\n            >\n              <bdi\n                class=\"channelName\"\n                :class=\"{\n                  member: comment.author.isMember,\n                  moderator: comment.author.isModerator,\n                  owner: comment.author.isOwner\n                }\"\n              >\n                {{ comment.author.name }}\n              </bdi>\n              <span\n                v-if=\"comment.author.badge\"\n                class=\"badge\"\n              >\n                <img\n                  :src=\"comment.author.badge.url\"\n                  alt=\"\"\n                  :title=\"comment.author.badge.tooltip\"\n                  class=\"badgeImage\"\n                >\n              </span>\n              <bdi\n                v-safer-html=\"comment.message\"\n                class=\"chatMessage\"\n              />\n            </p>\n          </template>\n        </div>\n      </div>\n      <div\n        v-if=\"showScrollToBottom\"\n        class=\"scrollToBottom\"\n        :aria-label=\"t('Video.Scroll to Bottom')\"\n        role=\"button\"\n        tabindex=\"0\"\n        @click=\"scrollToBottom\"\n        @keydown.space.prevent=\"scrollToBottom\"\n        @keydown.enter.prevent=\"scrollToBottom\"\n      >\n        <FontAwesomeIcon\n          class=\"icon\"\n          :icon=\"['fas', 'arrow-down']\"\n        />\n      </div>\n    </div>\n  </FtCard>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport autolinker from 'autolinker'\nimport { computed, nextTick, onBeforeUnmount, ref, shallowReactive, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { YTNodes } from 'youtubei.js'\n\nimport FtLoader from '../FtLoader/FtLoader.vue'\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtButton from '../FtButton/FtButton.vue'\nimport { vSaferHtml } from '../../directives/vSaferHtml.js'\n\nimport store from '../../store/index'\n\nimport { formatNumber } from '../../helpers/utils'\nimport { getRandomColorClass } from '../../helpers/colors'\nimport { getLocalVideoInfo, parseLocalTextRuns } from '../../helpers/api/local'\n\nconst props = defineProps({\n  liveChat: {\n    type: EventTarget,\n    default: null\n  },\n  videoId: {\n    type: String,\n    required: true\n  },\n  channelId: {\n    type: String,\n    required: true\n  }\n})\n\nconst { t } = useI18n()\n\n/** @type {import('youtubei.js').YT.LiveChat|null} */\nlet liveChatInstance = null\nlet hasEnded = false\nlet stayAtBottom = false\n\nconst isLoading = ref(true)\nconst hasError = ref(false)\nconst showEnableChat = ref(false)\nconst errorMessage = ref('')\nconst showSuperChat = ref(false)\nconst showScrollToBottom = ref(false)\nconst comments = shallowReactive([])\nconst superChatComments = shallowReactive([])\nconst superChat = ref({\n  id: '',\n  author: {\n    name: '',\n    thumbnailUrl: ''\n  },\n  message: '',\n  superChat: {\n    amount: '',\n    colorClass: ''\n  }\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\nconst chatHeight = computed(() => superChatComments.length > 0 ? '390px' : '445px')\n\nconst scrollingBehaviour = computed(() => {\n  return store.getters.getDisableSmoothScrolling ? 'auto' : 'smooth'\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideVideoViews = computed(() => store.getters.getHideVideoViews)\n\n/** @type {import('vue').Ref<number | null>} */\nconst watchingCount = ref(null)\n\nconst formattedWatchingCount = computed(() => {\n  return watchingCount.value !== null ? formatNumber(watchingCount.value) : '0'\n})\n\nonBeforeUnmount(() => {\n  handleEnd()\n})\n\nif (!process.env.SUPPORTS_LOCAL_API) {\n  hasError.value = true\n  errorMessage.value = t('Video[\"Live Chat is currently not supported in this build.\"]')\n  isLoading.value = false\n} else {\n  switch (backendPreference.value) {\n    case 'local':\n      if (props.liveChat) {\n        liveChatInstance = props.liveChat\n        startLiveChatLocal()\n      } else {\n        showLiveChatUnavailable()\n      }\n      break\n    case 'invidious':\n      if (backendFallback.value) {\n        getLiveChatLocal()\n      } else {\n        hasError.value = true\n        errorMessage.value = t('Video[\"Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.\"]')\n        showEnableChat.value = true\n        isLoading.value = false\n      }\n      break\n  }\n}\n\nfunction enableLiveChat() {\n  hasError.value = false\n  showEnableChat.value = false\n  isLoading.value = true\n  getLiveChatLocal()\n}\n\nasync function getLiveChatLocal() {\n  const videoInfo = await getLocalVideoInfo(props.videoId)\n\n  if (videoInfo.livechat) {\n    liveChatInstance = videoInfo.getLiveChat()\n\n    startLiveChatLocal()\n  } else {\n    showLiveChatUnavailable()\n  }\n}\n\nfunction showLiveChatUnavailable() {\n  hasError.value = true\n  errorMessage.value = t('Video[\"Live Chat is unavailable for this stream. It may have been disabled by the uploader.\"]')\n  isLoading.value = false\n  showEnableChat.value = false\n}\n\nfunction startLiveChatLocal() {\n  liveChatInstance.once('start', handleStart)\n  liveChatInstance.on('chat-update', handleChatUpdate)\n  liveChatInstance.on('metadata-update', handleMetadataUpdate)\n  liveChatInstance.once('error', handleError)\n  liveChatInstance.once('end', handleEnd)\n\n  liveChatInstance.start()\n}\n\nconst commentsRef = useTemplateRef('commentsRef')\n\n/**\n * @param {import ('youtubei.js/dist/src/parser/continuations').LiveChatContinuation} initialData\n */\nfunction handleStart(initialData) {\n  const actions = initialData.actions.filterType(YTNodes.AddChatItemAction)\n\n  for (const { item } of actions) {\n    if (item.is(YTNodes.LiveChatTextMessage)) {\n      parseLiveChatComment(item)\n    } else if (item.is(YTNodes.LiveChatPaidMessage)) {\n      parseLiveChatSuperChat(item)\n    }\n  }\n\n  isLoading.value = false\n\n  nextTick(() => {\n    commentsRef.value?.scrollTo({\n      top: commentsRef.value.scrollHeight,\n      behavior: 'instant'\n    })\n  })\n}\n\n/**\n * @param {import('youtubei.js/dist/src/parser/youtube/LiveChat').ChatAction} action\n */\nfunction handleChatUpdate(action) {\n  if (!hasEnded && action.is(YTNodes.AddChatItemAction)) {\n    if (action.item.is(YTNodes.LiveChatTextMessage)) {\n      parseLiveChatComment(action.item)\n    } else if (action.item.is(YTNodes.LiveChatPaidMessage)) {\n      parseLiveChatSuperChat(action.item)\n    }\n  }\n}\n\n/**\n * @param {import('youtubei.js/dist/src/parser/youtube/LiveChat').LiveMetadata} metadata\n */\nfunction handleMetadataUpdate(metadata) {\n  if (metadata.views && !isNaN(metadata.views.original_view_count)) {\n    watchingCount.value = metadata.views.original_view_count\n  }\n}\n\nfunction handleEnd() {\n  hasEnded = true\n\n  if (liveChatInstance) {\n    liveChatInstance.stop()\n    liveChatInstance.off('start', handleStart)\n    liveChatInstance.off('chat-update', handleChatUpdate)\n    liveChatInstance.off('metadata-update', handleMetadataUpdate)\n    liveChatInstance.off('error', handleError)\n    liveChatInstance.off('end', handleEnd)\n    liveChatInstance = null\n  }\n}\n\n/**\n * @param {Error} error\n */\nfunction handleError(error) {\n  handleEnd()\n\n  console.error(error)\n  errorMessage.value = `[${error.name}] ${error.message}`\n  hasError.value = true\n  isLoading.value = false\n}\n\n/**\n * @param {import('youtubei.js').YTNodes.LiveChatTextMessage} comment\n */\nfunction parseLiveChatComment(comment) {\n  /** @type {import('youtubei.js').YTNodes.LiveChatAuthorBadge | undefined} */\n  const badge = comment.author.badges.find(badge => badge.is(YTNodes.LiveChatAuthorBadge) && badge.custom_thumbnail)\n\n  const parsedComment = {\n    id: comment.id,\n    message: autolinker.link(parseLocalTextRuns(comment.message.runs, 20)),\n    author: {\n      name: comment.author.name,\n      thumbnailUrl: comment.author.thumbnails.at(-1).url,\n      isOwner: comment.author.id === props.channelId,\n      isModerator: comment.author.is_moderator,\n      isMember: !!badge\n    }\n  }\n\n  if (badge) {\n    parsedComment.badge = {\n      url: badge.custom_thumbnail.at(-1)?.url,\n      tooltip: badge.tooltip ?? ''\n    }\n  }\n\n  pushComment(parsedComment)\n}\n\n/**\n * @param {import('youtubei.js').YTNodes.LiveChatPaidMessage} superChat\n */\nfunction parseLiveChatSuperChat(superChat) {\n  const parsedComment = {\n    id: superChat.id,\n    message: autolinker.link(parseLocalTextRuns(superChat.message.runs, 20)),\n    author: {\n      name: superChat.author.name.text,\n      thumbnailUrl: superChat.author.thumbnails[0].url\n    },\n    superChat: {\n      amount: superChat.purchase_amount,\n      colorClass: getRandomColorClass()\n    }\n  }\n\n  superChatComments.unshift(parsedComment)\n\n  setTimeout(() => {\n    removeFromSuperChat(parsedComment)\n  }, 120000)\n\n  pushComment(parsedComment)\n}\n\n/**\n * @param {any} comment\n */\nfunction pushComment(comment) {\n  comments.push(comment)\n\n  if (!isLoading.value && stayAtBottom) {\n    nextTick(() => {\n      commentsRef.value?.scrollTo({\n        top: commentsRef.value.scrollHeight,\n        behavior: scrollingBehaviour.value\n      })\n    })\n  }\n\n  if (comments.length > 150 && stayAtBottom) {\n    comments.splice(0, comments.length - 150)\n  }\n}\n\n/**\n * @param {any} comment\n */\nfunction removeFromSuperChat(comment) {\n  const index = superChatComments.indexOf(comment)\n\n  superChatComments.splice(index, 1)\n}\n\n/**\n * @param {any} comment\n */\nfunction showSuperChatComment(comment) {\n  if (superChat.value.id === comment.id && showSuperChat.value) {\n    showSuperChat.value = false\n  } else {\n    superChat.value = comment\n    showSuperChat.value = true\n  }\n}\n\n/**\n * @param {any} event\n * @param {boolean} [isScrollEnd]\n */\nfunction onScroll(event, isScrollEnd = false) {\n  const liveChatComments = commentsRef.value\n  if (event.wheelDelta >= 0 && stayAtBottom) {\n    stayAtBottom = false\n\n    if (liveChatComments.scrollHeight > liveChatComments.clientHeight) {\n      showScrollToBottom.value = true\n    }\n  } else if ((isScrollEnd || event.wheelDelta < 0) && !stayAtBottom && (liveChatComments.scrollHeight - liveChatComments.scrollTop) === liveChatComments.clientHeight) {\n    scrollToBottom()\n  }\n}\n\nfunction hideSuperChat() {\n  showSuperChat.value = false\n}\n\nfunction scrollToBottom() {\n  commentsRef.value.scrollTo({\n    top: commentsRef.value.scrollHeight,\n    behavior: scrollingBehaviour.value\n  })\n\n  stayAtBottom = true\n  showScrollToBottom.value = false\n}\n\n</script>\n\n<style scoped src=\"./WatchVideoLiveChat.css\" />\n"
  },
  {
    "path": "src/renderer/components/WatchVideoRecommendations/WatchVideoRecommendations.css",
    "content": ".relative {\n  position: relative;\n}\n\n.watchVideoRecommendations {\n  display: grid;\n  gap: 8px;\n}\n\n.VideoRecommendationsTopBar {\n  display: flex;\n  justify-content: space-between;\n}\n"
  },
  {
    "path": "src/renderer/components/WatchVideoRecommendations/WatchVideoRecommendations.vue",
    "content": "<template>\n  <FtCard\n    class=\"relative watchVideoRecommendations\"\n  >\n    <div class=\"VideoRecommendationsTopBar\">\n      <h3>\n        {{ $t(\"Up Next\") }}\n      </h3>\n    </div>\n    <FtListVideoLazy\n      v-for=\"video in data\"\n      :key=\"video.videoId\"\n      :data=\"video\"\n      appearance=\"recommendation\"\n      force-list-type=\"list\"\n      :use-channels-hidden-preference=\"true\"\n      @pause-player=\"pausePlayer\"\n    />\n  </FtCard>\n</template>\n\n<script setup>\n\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtListVideoLazy from '../FtListVideoLazy.vue'\n\ndefineProps({\n  data: {\n    type: Array,\n    required: true\n  }\n})\n\nconst emit = defineEmits(['pause-player'])\n\nfunction pausePlayer() {\n  emit('pause-player')\n}\n</script>\n\n<style scoped src=\"./WatchVideoRecommendations.css\" />\n"
  },
  {
    "path": "src/renderer/components/ft-card/ft-card.css",
    "content": ".ft-card {\n  background-color: var(--card-bg-color);\n  margin: 8px;\n  padding-block: 3px 16px;\n  padding-inline: 16px;\n  box-shadow: 0 1px 2px rgb(0 0 0 / 10%);\n}\n"
  },
  {
    "path": "src/renderer/components/ft-card/ft-card.js",
    "content": "import { defineComponent } from 'vue'\n\nexport default defineComponent({\n  name: 'FtCard'\n})\n"
  },
  {
    "path": "src/renderer/components/ft-card/ft-card.vue",
    "content": "<template>\n  <div\n    class=\"ft-card\"\n  >\n    <slot />\n  </div>\n</template>\n\n<script src=\"./ft-card.js\" />\n<style scoped src=\"./ft-card.css\" />\n"
  },
  {
    "path": "src/renderer/components/ft-flex-box/ft-flex-box.css",
    "content": ".ft-flex-box {\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: space-evenly;\n  user-select: none;\n}\n"
  },
  {
    "path": "src/renderer/components/ft-flex-box/ft-flex-box.js",
    "content": "import { defineComponent } from 'vue'\n\nexport default defineComponent({\n  name: 'FtFlexBox'\n})\n"
  },
  {
    "path": "src/renderer/components/ft-flex-box/ft-flex-box.vue",
    "content": "<template>\n  <div class=\"ft-flex-box\">\n    <slot class=\"flex-container\" />\n  </div>\n</template>\n\n<script src=\"./ft-flex-box.js\" />\n<style scoped src=\"./ft-flex-box.css\" />\n"
  },
  {
    "path": "src/renderer/components/ft-list-video/ft-list-video.js",
    "content": "import { defineComponent } from 'vue'\nimport FtIconButton from '../FtIconButton/FtIconButton.vue'\nimport { mapActions } from 'vuex'\nimport {\n  copyToClipboard,\n  formatDurationAsTimestamp,\n  formatNumber,\n  getRelativeTimeFromDate,\n  openExternalLink,\n  showToast,\n  toDistractionFreeTitle,\n  deepCopy,\n  debounce\n} from '../../helpers/utils'\nimport { deArrowData, deArrowThumbnail } from '../../helpers/sponsorblock'\nimport thumbnailPlaceholder from '../../assets/img/thumbnail_placeholder.svg'\nimport { vSaferHtml } from '../../directives/vSaferHtml.js'\n\nexport default defineComponent({\n  name: 'FtListVideo',\n  components: {\n    'ft-icon-button': FtIconButton\n  },\n  directives: {\n    'safer-html': vSaferHtml\n  },\n  props: {\n    data: {\n      type: Object,\n      required: true\n    },\n    playlistId: {\n      type: String,\n      default: null\n    },\n    playlistType: {\n      type: String,\n      default: null\n    },\n    playlistItemId: {\n      type: String,\n      default: null\n    },\n    playlistIndex: {\n      type: Number,\n      default: null\n    },\n    playlistReverse: {\n      type: Boolean,\n      default: false\n    },\n    playlistShuffle: {\n      type: Boolean,\n      default: false\n    },\n    playlistLoop: {\n      type: Boolean,\n      default: false\n    },\n    forceListType: {\n      type: String,\n      default: null\n    },\n    appearance: {\n      type: String,\n      required: true\n    },\n    showVideoWithLastViewedPlaylist: {\n      type: Boolean,\n      default: false\n    },\n    alwaysShowAddToPlaylistButton: {\n      type: Boolean,\n      default: false,\n    },\n    quickBookmarkButtonEnabled: {\n      type: Boolean,\n      default: true,\n    },\n    canMoveVideoUp: {\n      type: Boolean,\n      default: false,\n    },\n    canMoveVideoDown: {\n      type: Boolean,\n      default: false,\n    },\n    canRemoveFromPlaylist: {\n      type: Boolean,\n      default: false,\n    },\n  },\n  emits: ['move-video-down', 'move-video-up', 'pause-player', 'remove-from-playlist'],\n  data: function () {\n    return {\n      id: '',\n      title: '',\n      channelName: null,\n      channelId: null,\n      viewCount: 0,\n      parsedViewCount: '',\n      uploadedTime: '',\n      lengthSeconds: 0,\n      duration: '',\n      description: '',\n      published: undefined,\n      isLive: false,\n      is4k: false,\n      is8k: false,\n      isNew: false,\n      isVr180: false,\n      isVr360: false,\n      is3D: false,\n      hasCaptions: false,\n      isUpcoming: false,\n      isPremium: false,\n      hideViews: false,\n      addToPlaylistPromptCloseCallback: null,\n      debounceGetDeArrowThumbnail: null,\n      deArrowTogglePinned: false,\n      showDeArrowTitle: false,\n      showDeArrowThumbnail: false,\n    }\n  },\n  computed: {\n    historyEntry: function () {\n      return this.$store.getters.getHistoryCacheById[this.id]\n    },\n\n    historyEntryExists: function () {\n      return typeof this.historyEntry !== 'undefined'\n    },\n\n    watchProgress: function () {\n      if (!this.historyEntryExists || !this.watchedProgressSavingEnabled) {\n        return 0\n      }\n\n      return this.historyEntry.watchProgress\n    },\n\n    listType: function () {\n      return this.$store.getters.getListType\n    },\n\n    effectiveListTypeIsList: function () {\n      return (this.listType === 'list' || this.forceListType === 'list') && this.forceListType !== 'grid'\n    },\n\n    thumbnailPreference: function () {\n      return this.$store.getters.getThumbnailPreference\n    },\n\n    blurThumbnails: function () {\n      return this.$store.getters.getBlurThumbnails\n    },\n\n    blurThumbnailsStyle: function () {\n      return this.blurThumbnails ? 'blur(20px)' : null\n    },\n\n    backendPreference: function () {\n      return this.$store.getters.getBackendPreference\n    },\n\n    currentInvidiousInstanceUrl: function () {\n      return this.$store.getters.getCurrentInvidiousInstanceUrl\n    },\n\n    showPlaylists: function () {\n      return !this.$store.getters.getHidePlaylists\n    },\n\n    inHistory: function () {\n      // When in the history page, showing relative dates isn't very useful.\n      // We want to show the exact date instead\n      return this.$route.name === 'history'\n    },\n\n    inSubscriptions: function () {\n      return this.$route.name === 'subscriptions' || this.$route.name === 'default'\n    },\n\n    inUserPlaylist: function () {\n      return this.playlistTypeFinal === 'user' || this.selectedUserPlaylist != null\n    },\n\n    selectedUserPlaylist: function () {\n      if (this.playlistIdFinal == null) { return null }\n      if (this.playlistIdFinal === '') { return null }\n\n      return this.$store.getters.getPlaylist(this.playlistIdFinal)\n    },\n\n    playlistSharable() {\n      // `playlistId` can be undefined\n      // User playlist ID should not be shared\n      return this.playlistIdFinal && this.playlistIdFinal.length !== 0 && !this.inUserPlaylist\n    },\n\n    invidiousUrl: function () {\n      let videoUrl = `${this.currentInvidiousInstanceUrl}/watch?v=${this.id}`\n      // `playlistId` can be undefined\n      if (this.playlistSharable) {\n        // `index` seems can be ignored\n        videoUrl += `&list=${this.playlistIdFinal}`\n      }\n      return videoUrl\n    },\n\n    invidiousChannelUrl: function () {\n      return `${this.currentInvidiousInstanceUrl}/channel/${this.channelId}`\n    },\n\n    youtubeUrl: function () {\n      let videoUrl = `https://www.youtube.com/watch?v=${this.id}`\n      if (this.playlistSharable) {\n        // `index` seems can be ignored\n        videoUrl += `&list=${this.playlistIdFinal}`\n      }\n      return videoUrl\n    },\n\n    youtubeShareUrl: function () {\n      const videoUrl = `https://youtu.be/${this.id}`\n      if (this.playlistSharable) {\n        // `index` seems can be ignored\n        return `${videoUrl}?list=${this.playlistIdFinal}`\n      }\n      return videoUrl\n    },\n\n    youtubeChannelUrl: function () {\n      return `https://youtube.com/channel/${this.channelId}`\n    },\n\n    youtubeEmbedUrl: function () {\n      return `https://www.youtube-nocookie.com/embed/${this.id}`\n    },\n\n    progressPercentage: function () {\n      if (typeof this.lengthSeconds !== 'number' || this.lengthSeconds === 0) {\n        return 0\n      }\n      const percentage = (this.watchProgress / this.lengthSeconds) * 100\n      return Math.min(percentage, 100)\n    },\n\n    hideSharingActions: function() {\n      return this.$store.getters.getHideSharingActions\n    },\n\n    showInvidiousShareOptions: function () {\n      return this.backendPreference === 'invidious' || this.$store.getters.getBackendFallback\n    },\n\n    dropdownOptions: function () {\n      const options = [\n        {\n          label: this.historyEntryExists\n            ? this.$t('Video.Remove From History')\n            : this.$t('Video.Mark As Watched'),\n          value: 'history'\n        }\n      ]\n      if (!this.hideSharingActions) {\n        options.push(\n          {\n            type: 'divider'\n          },\n          {\n            label: this.$t('Video.Copy YouTube Link'),\n            value: 'copyYoutube'\n          },\n          {\n            label: this.$t('Video.Copy YouTube Embedded Player Link'),\n            value: 'copyYoutubeEmbed'\n          },\n          ...this.showInvidiousShareOptions\n            ? [{\n                label: this.$t('Video.Copy Invidious Link'),\n                value: 'copyInvidious'\n              }]\n            : [],\n          {\n            type: 'divider'\n          },\n          {\n            label: this.$t('Video.Open in YouTube'),\n            value: 'openYoutube'\n          },\n          {\n            label: this.$t('Video.Open YouTube Embedded Player'),\n            value: 'openYoutubeEmbed'\n          },\n          ...this.showInvidiousShareOptions\n            ? [{\n                label: this.$t('Video.Open in Invidious'),\n                value: 'openInvidious'\n              }]\n            : [],\n        )\n        if (this.channelId !== null) {\n          options.push(\n            {\n              type: 'divider'\n            },\n            {\n              label: this.$t('Video.Copy YouTube Channel Link'),\n              value: 'copyYoutubeChannel'\n            },\n            ...this.showInvidiousShareOptions\n              ? [{\n                  label: this.$t('Video.Copy Invidious Channel Link'),\n                  value: 'copyInvidiousChannel'\n                }]\n              : [],\n            {\n              type: 'divider'\n            },\n            {\n              label: this.$t('Video.Open Channel in YouTube'),\n              value: 'openYoutubeChannel'\n            },\n            ...this.showInvidiousShareOptions\n              ? [{\n                  label: this.$t('Video.Open Channel in Invidious'),\n                  value: 'openInvidiousChannel'\n                }]\n              : [],\n          )\n        }\n      }\n\n      if (this.channelId !== null && !this.inSubscriptions) {\n        const hiddenChannels = JSON.parse(this.$store.getters.getChannelsHidden)\n        const channelShouldBeHidden = hiddenChannels.some(c => c.name === this.channelId)\n\n        options.push(\n          {\n            type: 'divider'\n          },\n\n          channelShouldBeHidden\n            ? {\n                label: this.$t('Video.Unhide Channel'),\n                value: 'unhideChannel'\n              }\n            : {\n                label: this.$t('Video.Hide Channel'),\n                value: 'hideChannel'\n              }\n        )\n      }\n\n      return options\n    },\n\n    thumbnail: function () {\n      if (this.thumbnailPreference === 'hidden') {\n        return thumbnailPlaceholder\n      }\n\n      if (this.showDeArrowThumbnail && this.deArrowCache?.thumbnail != null) {\n        return this.deArrowCache.thumbnail\n      }\n\n      let baseUrl\n      if (this.backendPreference === 'invidious') {\n        baseUrl = this.currentInvidiousInstanceUrl\n      } else {\n        baseUrl = 'https://i.ytimg.com'\n      }\n\n      switch (this.thumbnailPreference) {\n        case 'start':\n          return `${baseUrl}/vi/${this.id}/mq1.jpg`\n        case 'middle':\n          return `${baseUrl}/vi/${this.id}/mq2.jpg`\n        case 'end':\n          return `${baseUrl}/vi/${this.id}/mq3.jpg`\n        default:\n          return `${baseUrl}/vi/${this.id}/mqdefault.jpg`\n      }\n    },\n\n    hideVideoViews: function () {\n      return this.$store.getters.getHideVideoViews\n    },\n\n    addWatchedStyle: function () {\n      return this.historyEntryExists && !this.inHistory\n    },\n\n    currentLocale: function () {\n      return this.$i18n.locale\n    },\n\n    externalPlayer: function () {\n      return this.$store.getters.getExternalPlayer\n    },\n\n    externalPlayerIsDefaultViewingMode: function () {\n      return process.env.IS_ELECTRON && this.externalPlayer !== '' && this.$store.getters.getDefaultViewingMode === 'external_player'\n    },\n\n    defaultPlayback: function () {\n      return this.$store.getters.getDefaultPlayback\n    },\n\n    watchedProgressSavingEnabled: function () {\n      return ['auto', 'semi-auto'].includes(this.$store.getters.getWatchedProgressSavingMode)\n    },\n    rememberHistory: function () {\n      return this.$store.getters.getRememberHistory\n    },\n\n    saveVideoHistoryWithLastViewedPlaylist: function () {\n      return this.$store.getters.getSaveVideoHistoryWithLastViewedPlaylist\n    },\n\n    showDistractionFreeTitles: function () {\n      return this.$store.getters.getShowDistractionFreeTitles\n    },\n\n    displayTitle: function () {\n      let title\n      if (this.showDeArrowTitle && this.deArrowCache?.title) {\n        title = this.deArrowCache.title\n      } else {\n        title = this.title\n      }\n\n      if (this.showDistractionFreeTitles) {\n        return toDistractionFreeTitle(title)\n      } else {\n        return title\n      }\n    },\n\n    displayDuration: function () {\n      if (this.useDeArrowTitles && (this.duration === '' || this.duration === '0:00') && this.deArrowCache?.videoDuration) {\n        return formatDurationAsTimestamp(this.deArrowCache.videoDuration)\n      }\n      return this.duration\n    },\n\n    playlistIdTypePairFinal() {\n      if (this.playlistId) {\n        return {\n          playlistId: this.playlistId,\n          playlistType: this.playlistType,\n          playlistItemId: this.playlistItemId,\n        }\n      }\n\n      // Get playlist ID from history ONLY if option enabled\n      if (!this.showVideoWithLastViewedPlaylist) { return }\n      if (!this.saveVideoHistoryWithLastViewedPlaylist) { return }\n\n      return {\n        playlistId: this.historyEntry?.lastViewedPlaylistId,\n        playlistType: this.historyEntry?.lastViewedPlaylistType,\n        playlistItemId: this.historyEntry?.lastViewedPlaylistItemId,\n      }\n    },\n\n    playlistIdFinal: function () {\n      return this.playlistIdTypePairFinal?.playlistId\n    },\n    playlistTypeFinal: function () {\n      return this.playlistIdTypePairFinal?.playlistType\n    },\n    playlistItemIdFinal: function () {\n      return this.playlistIdTypePairFinal?.playlistItemId\n    },\n\n    quickBookmarkPlaylist() {\n      return this.$store.getters.getQuickBookmarkPlaylist\n    },\n    isQuickBookmarkEnabled() {\n      return this.quickBookmarkPlaylist != null\n    },\n    isInQuickBookmarkPlaylist: function () {\n      if (!this.isQuickBookmarkEnabled) { return false }\n\n      // Accessing a reactive property has a negligible amount of overhead,\n      // however as we know that some users have playlists that have more than 10k items in them\n      // it adds up quickly, especially as there are usually lots of ft-list-video instances active at the same time.\n      // So create a temporary variable outside of the array, so we only have to do it once.\n      // Also the search is retriggered every time any playlist is modified.\n      const id = this.id\n\n      return this.quickBookmarkPlaylist.videos.some((video) => {\n        return video.videoId === id\n      })\n    },\n    quickBookmarkIconText: function () {\n      if (!this.isQuickBookmarkEnabled) { return false }\n\n      const translationProperties = {\n        playlistName: this.quickBookmarkPlaylist.playlistName,\n      }\n      return this.isInQuickBookmarkPlaylist\n        ? this.$t('User Playlists.Remove from Favorites', translationProperties)\n        : this.$t('User Playlists.Add to Favorites', translationProperties)\n    },\n    quickBookmarkIconTheme: function () {\n      return this.isInQuickBookmarkPlaylist ? 'base favorite' : 'base'\n    },\n\n    watchVideoRouterLink() {\n    // For `router-link` attribute `to`\n      if (!this.externalPlayerIsDefaultViewingMode) {\n        return {\n          path: `/watch/${this.id}`,\n          query: this.watchPageLinkQuery,\n        }\n      } else {\n        return {}\n      }\n    },\n\n    watchPageLinkQuery() {\n      const query = {}\n      if (this.playlistIdFinal) { query.playlistId = this.playlistIdFinal }\n      if (this.playlistTypeFinal) { query.playlistType = this.playlistTypeFinal }\n      if (this.playlistItemIdFinal) { query.playlistItemId = this.playlistItemIdFinal }\n      return query\n    },\n\n    useDeArrowTitles: function () {\n      return this.$store.getters.getUseDeArrowTitles\n    },\n    useDeArrowThumbnails: function () {\n      return this.$store.getters.getUseDeArrowThumbnails\n    },\n    deArrowChangedContent: function () {\n      return (this.useDeArrowThumbnails && this.deArrowCache?.thumbnail) ||\n        (this.useDeArrowTitles && this.deArrowCache?.title &&\n          this.data.title.localeCompare(this.deArrowCache.title, undefined, { sensitivity: 'accent' }) !== 0)\n    },\n\n    deArrowToggleTitle: function() {\n      return this.deArrowTogglePinned\n        ? this.$t('Video.DeArrow.Show Modified Details')\n        : this.$t('Video.DeArrow.Show Original Details')\n    },\n\n    deArrowCache: function () {\n      return this.$store.getters.getDeArrowCache[this.id]\n    },\n  },\n  watch: {\n    showAddToPlaylistPrompt(value) {\n      if (value) { return }\n      // Execute on prompt close\n\n      if (this.addToPlaylistPromptCloseCallback == null) { return }\n      this.addToPlaylistPromptCloseCallback()\n    },\n  },\n  created: function () {\n    this.parseVideoData()\n\n    this.showDeArrowTitle = this.useDeArrowTitles\n    this.showDeArrowThumbnail = this.useDeArrowThumbnails\n\n    if ((this.showDeArrowTitle || this.showDeArrowThumbnail) && !this.deArrowCache) {\n      this.fetchDeArrowData()\n    }\n\n    if (this.showDeArrowThumbnail && this.deArrowCache && this.deArrowCache.thumbnail == null) {\n      if (this.debounceGetDeArrowThumbnail == null) {\n        this.debounceGetDeArrowThumbnail = debounce(this.fetchDeArrowThumbnail, 1000)\n      }\n\n      this.debounceGetDeArrowThumbnail()\n    }\n  },\n  methods: {\n    handleWatchPageLinkClick: function() {\n      if (this.externalPlayerIsDefaultViewingMode) {\n        this.handleExternalPlayer()\n      }\n    },\n    fetchDeArrowThumbnail: async function() {\n      if (this.thumbnailPreference === 'hidden') { return }\n      const videoId = this.id\n      const thumbnail = await deArrowThumbnail(videoId, this.deArrowCache.thumbnailTimestamp)\n      if (thumbnail) {\n        const deArrowCacheClone = deepCopy(this.deArrowCache)\n        deArrowCacheClone.thumbnail = thumbnail\n        this.$store.commit('addThumbnailToDeArrowCache', deArrowCacheClone)\n      }\n    },\n    fetchDeArrowData: async function() {\n      const videoId = this.id\n      const data = await deArrowData(this.id)\n      const cacheData = { videoId, title: null, videoDuration: null, thumbnail: null, thumbnailTimestamp: null }\n      if (Array.isArray(data?.titles) && data.titles.length > 0 && (data.titles[0].locked || data.titles[0].votes >= 0)) {\n        // remove dearrow formatting markers https://github.com/ajayyy/DeArrow/blob/0da266485be902fe54259214c3cd7c942f2357c5/src/titles/titleFormatter.ts#L460\n        cacheData.title = data.titles[0].title.replaceAll(/(^|\\s)>(\\S)/g, '$1$2').trim()\n      }\n      if (Array.isArray(data?.thumbnails) && data.thumbnails.length > 0 && (data.thumbnails[0].locked || data.thumbnails[0].votes >= 0)) {\n        cacheData.thumbnailTimestamp = data.thumbnails.at(0).timestamp\n      } else if (data?.videoDuration != null) {\n        cacheData.thumbnailTimestamp = data.videoDuration * data.randomTime\n      }\n      cacheData.videoDuration = data?.videoDuration ? Math.floor(data.videoDuration) : null\n\n      // Save data to cache whether data available or not to prevent duplicate requests\n      this.$store.commit('addVideoToDeArrowCache', cacheData)\n\n      // fetch dearrow thumbnails if enabled\n      if (this.showDeArrowThumbnail && this.deArrowCache?.thumbnail === null) {\n        if (this.debounceGetDeArrowThumbnail == null) {\n          this.debounceGetDeArrowThumbnail = debounce(this.fetchDeArrowThumbnail, 1000)\n        }\n\n        this.debounceGetDeArrowThumbnail()\n      }\n    },\n    toggleDeArrow() {\n      if (!this.deArrowChangedContent) {\n        return\n      }\n\n      this.deArrowTogglePinned = !this.deArrowTogglePinned\n\n      if (this.useDeArrowTitles) {\n        this.showDeArrowTitle = !this.showDeArrowTitle\n      }\n      if (this.useDeArrowThumbnails) {\n        this.showDeArrowThumbnail = !this.showDeArrowThumbnail\n      }\n    },\n\n    handleExternalPlayer: function () {\n      this.$emit('pause-player')\n\n      const payload = {\n        videoId: this.id,\n        playlistId: this.playlistIdFinal,\n        startTime: this.watchProgress,\n        playbackRate: this.defaultPlayback,\n        playlistIndex: this.playlistIndex,\n        playlistReverse: this.playlistReverse,\n        playlistShuffle: this.playlistShuffle,\n        playlistLoop: this.playlistLoop,\n      }\n      // Only play video in non playlist mode when user playlist detected\n      if (this.inUserPlaylist) {\n        Object.assign(payload, {\n          playlistId: null,\n          playlistIndex: null,\n          playlistReverse: null,\n          playlistShuffle: null,\n          playlistLoop: null,\n        })\n      }\n      if (process.env.IS_ELECTRON) {\n        window.ftElectron.openInExternalPlayer(payload)\n      }\n\n      if (this.rememberHistory) {\n        this.markAsWatched()\n      }\n    },\n\n    handleOptionsClick: function (option) {\n      switch (option) {\n        case 'history':\n          if (this.historyEntryExists) {\n            this.removeFromWatched()\n          } else {\n            this.markAsWatched()\n          }\n          break\n        case 'copyYoutube':\n          copyToClipboard(this.youtubeShareUrl, { messageOnSuccess: this.$t('Share.YouTube URL copied to clipboard') })\n          break\n        case 'openYoutube':\n          openExternalLink(this.youtubeUrl)\n          break\n        case 'copyYoutubeEmbed':\n          copyToClipboard(this.youtubeEmbedUrl, { messageOnSuccess: this.$t('Share.YouTube Embed URL copied to clipboard') })\n          break\n        case 'openYoutubeEmbed':\n          openExternalLink(this.youtubeEmbedUrl)\n          break\n        case 'copyInvidious':\n          copyToClipboard(this.invidiousUrl, { messageOnSuccess: this.$t('Share.Invidious URL copied to clipboard') })\n          break\n        case 'openInvidious':\n          openExternalLink(this.invidiousUrl)\n          break\n        case 'copyYoutubeChannel':\n          copyToClipboard(this.youtubeChannelUrl, { messageOnSuccess: this.$t('Share.YouTube Channel URL copied to clipboard') })\n          break\n        case 'openYoutubeChannel':\n          openExternalLink(this.youtubeChannelUrl)\n          break\n        case 'copyInvidiousChannel':\n          copyToClipboard(this.invidiousChannelUrl, { messageOnSuccess: this.$t('Share.Invidious Channel URL copied to clipboard') })\n          break\n        case 'openInvidiousChannel':\n          openExternalLink(this.invidiousChannelUrl)\n          break\n        case 'hideChannel':\n          this.hideChannel(this.channelName, this.channelId)\n          break\n        case 'unhideChannel':\n          this.unhideChannel(this.channelName, this.channelId)\n          break\n      }\n    },\n\n    parseVideoData: function () {\n      this.id = this.data.videoId\n      this.title = this.data.title\n      // this.thumbnail = this.data.videoThumbnails[4].url\n\n      this.channelName = this.data.author ?? null\n      this.channelId = this.data.authorId ?? null\n\n      if ((this.data.lengthSeconds === '' || this.data.lengthSeconds === '0:00') && this.historyEntryExists) {\n        this.lengthSeconds = this.historyEntry.lengthSeconds\n        this.duration = formatDurationAsTimestamp(this.historyEntry.lengthSeconds)\n      } else {\n        this.lengthSeconds = this.data.lengthSeconds\n        this.duration = formatDurationAsTimestamp(this.data.lengthSeconds)\n      }\n\n      this.description = this.data.description\n      this.isLive = this.data.liveNow || this.data.lengthSeconds === 'undefined'\n      this.isUpcoming = this.data.isUpcoming || this.data.premiere\n      this.is4k = this.data.is4k\n      this.is8k = this.data.is8k\n      this.isNew = this.data.isNew\n      this.isVr180 = this.data.isVr180\n      this.isVr360 = this.data.isVr360\n      this.is3D = this.data.is3d\n      this.hasCaptions = this.data.hasCaptions\n      this.isPremium = this.data.premium || false\n      this.viewCount = this.data.viewCount\n\n      if (typeof this.data.premiereDate !== 'undefined') {\n        let premiereDate = this.data.premiereDate\n\n        // premiereDate will be a string when the subscriptions are restored from the cache\n        if (typeof premiereDate === 'string') {\n          premiereDate = new Date(premiereDate)\n        }\n        this.uploadedTime = premiereDate.toLocaleString([this.currentLocale, 'en'])\n        this.published = premiereDate.getTime()\n      } else if (typeof (this.data.premiereTimestamp) !== 'undefined') {\n        this.uploadedTime = new Date(this.data.premiereTimestamp * 1000).toLocaleString([this.currentLocale, 'en'])\n        this.published = this.data.premiereTimestamp * 1000\n      } else if (typeof this.data.published === 'number' && !this.isLive) {\n        this.published = this.data.published\n\n        if (this.inHistory) {\n          this.uploadedTime = new Date(this.data.published).toLocaleDateString([this.currentLocale, 'en'])\n        } else {\n          // Use 30 days per month, just like calculatePublishedDate\n          this.uploadedTime = getRelativeTimeFromDate(this.data.published, false)\n        }\n      }\n\n      if (this.hideVideoViews) {\n        this.hideViews = true\n      } else if (typeof (this.data.viewCount) !== 'undefined' && this.data.viewCount !== null) {\n        this.parsedViewCount = formatNumber(this.data.viewCount)\n      } else if (typeof (this.data.viewCountText) !== 'undefined') {\n        this.parsedViewCount = this.data.viewCountText.replace(' views', '')\n      } else {\n        this.hideViews = true\n      }\n    },\n\n    markAsWatched: function () {\n      const videoData = {\n        videoId: this.id,\n        title: this.title,\n        author: this.channelName,\n        authorId: this.channelId,\n        published: this.published,\n        description: this.description,\n        viewCount: this.viewCount,\n        lengthSeconds: this.data.lengthSeconds,\n        watchProgress: 0,\n        timeWatched: Date.now(),\n        isLive: false,\n        type: 'video'\n      }\n      this.updateHistory(videoData)\n\n      if (!this.historyEntryExists) {\n        showToast(this.$t('Video.Video has been marked as watched'))\n      }\n    },\n\n    removeFromWatched: function () {\n      this.removeFromHistory(this.id)\n\n      showToast(this.$t('Video.Video has been removed from your history'))\n    },\n\n    togglePlaylistPrompt: function () {\n      const videoData = {\n        videoId: this.id,\n        title: this.title,\n        author: this.channelName,\n        authorId: this.channelId,\n        description: this.description,\n        viewCount: this.viewCount,\n        lengthSeconds: this.data.lengthSeconds,\n        published: this.published,\n        premiereDate: this.data.premiereDate,\n        premiereTimestamp: this.data.premiereTimestamp,\n      }\n\n      this.showAddToPlaylistPromptForManyVideos({ videos: [videoData] })\n\n      // Focus when prompt closed\n      this.addToPlaylistPromptCloseCallback = () => {\n        // Run once only\n        this.addToPlaylistPromptCloseCallback = null\n      }\n    },\n\n    hideChannel: function(channelName, channelId) {\n      const hiddenChannels = JSON.parse(this.$store.getters.getChannelsHidden)\n      hiddenChannels.push({ name: channelId, preferredName: channelName })\n      this.updateChannelsHidden(JSON.stringify(hiddenChannels))\n\n      showToast(this.$t('Channel Hidden', { channel: channelName }))\n    },\n\n    unhideChannel: function(channelName, channelId) {\n      const hiddenChannels = JSON.parse(this.$store.getters.getChannelsHidden)\n      this.updateChannelsHidden(JSON.stringify(hiddenChannels.filter(c => c.name !== channelId)))\n\n      showToast(this.$t('Channel Unhidden', { channel: channelName }))\n    },\n\n    toggleQuickBookmarked() {\n      if (!this.isQuickBookmarkEnabled) {\n        // This should be prevented by UI\n        return\n      }\n\n      if (this.isInQuickBookmarkPlaylist) {\n        this.removeFromQuickBookmarkPlaylist()\n      } else {\n        this.addToQuickBookmarkPlaylist()\n      }\n    },\n    addToQuickBookmarkPlaylist() {\n      const videoData = {\n        videoId: this.id,\n        title: this.title,\n        author: this.channelName,\n        authorId: this.channelId,\n        lengthSeconds: this.data.lengthSeconds,\n        published: this.published,\n        premiereDate: this.data.premiereDate,\n        premiereTimestamp: this.data.premiereTimestamp,\n      }\n\n      this.addVideo({\n        _id: this.quickBookmarkPlaylist._id,\n        videoData,\n      })\n\n      // TODO: Maybe show playlist name\n      showToast(this.$t('Video.Video has been saved'))\n    },\n    removeFromQuickBookmarkPlaylist() {\n      this.removeVideo({\n        _id: this.quickBookmarkPlaylist._id,\n        // Remove all playlist items with same videoId\n        videoId: this.id,\n      })\n\n      // TODO: Maybe show playlist name\n      showToast(this.$t('Video.Video has been removed from your saved list'))\n    },\n    moveVideoUp: function() {\n      this.$emit('move-video-up', this.id, this.playlistItemId)\n    },\n\n    moveVideoDown: function() {\n      this.$emit('move-video-down', this.id, this.playlistItemId)\n    },\n\n    removeFromPlaylist: function() {\n      this.$emit('remove-from-playlist', this.id, this.playlistItemId)\n    },\n\n    ...mapActions([\n      'updateHistory',\n      'removeFromHistory',\n      'updateChannelsHidden',\n      'showAddToPlaylistPromptForManyVideos',\n      'addVideo',\n      'removeVideo',\n    ])\n  }\n})\n"
  },
  {
    "path": "src/renderer/components/ft-list-video/ft-list-video.scss",
    "content": "@use '../../scss-partials/ft-list-item';\n\n.thumbnailLink:hover {\n  outline: 3px solid var(--side-nav-hover-color);\n}\n\n.thumbnailImage {\n  // Makes img element sized correctly before image loading starts\n  aspect-ratio: 16/9 auto;\n}\n\n.videoTagLine {\n  margin-block-start: 3px;\n}\n\n.videoTag {\n  padding: 3px;\n  margin-inline: 2px;\n  background-color: var(--secondary-card-bg-color);\n  font-size: 10px;\n  border-radius: 2px;\n  display: inline-block;\n  font-weight: 500;\n  white-space-collapse: collapse;\n}\n\n.videoTagLine .videoTag:first-child {\n  margin-inline-start: 0;\n}\n\n.deArrowToggleButton {\n  border-radius: 50%;\n  cursor: pointer;\n  padding: 10px;\n  font-size: 16px;\n  line-height: 1em;\n  transition: background 0.15s ease-out;\n  background-color: transparent;\n  color: var(--primary-color);\n  border-color: transparent;\n\n  &:not(.disabled) {\n    &:hover,\n    &:focus-visible {\n      background-color: var(--side-nav-hover-color);\n    }\n\n    &:active {\n      background-color: var(--side-nav-active-color);\n    }\n\n    &.alwaysVisible {\n      opacity: 1;\n      filter: grayscale(1);\n    }\n  }\n}\n\n.deArrowToggleIcon {\n  inline-size: 1em;\n}\n"
  },
  {
    "path": "src/renderer/components/ft-list-video/ft-list-video.vue",
    "content": "<template>\n  <div\n    class=\"ft-list-video ft-list-item\"\n    :class=\"{\n      list: effectiveListTypeIsList,\n      grid: !effectiveListTypeIsList,\n      [appearance]: true,\n      watched: addWatchedStyle\n    }\"\n  >\n    <div\n      class=\"videoThumbnail\"\n    >\n      <router-link\n        class=\"thumbnailLink\"\n        tabindex=\"-1\"\n        :to=\"watchVideoRouterLink\"\n        @click=\"handleWatchPageLinkClick\"\n      >\n        <img\n          :src=\"thumbnail\"\n          class=\"thumbnailImage\"\n          alt=\"\"\n          :style=\"{filter: blurThumbnailsStyle}\"\n        >\n      </router-link>\n      <div\n        v-if=\"isLive || isUpcoming || (displayDuration !== '' && displayDuration !== '0:00')\"\n        class=\"videoDuration\"\n        :class=\"{\n          live: isLive,\n          upcoming: isUpcoming\n        }\"\n      >\n        {{ isLive ? $t(\"Video.Live\") : (isUpcoming ? $t(\"Video.Upcoming\") : displayDuration) }}\n      </div>\n      <ft-icon-button\n        v-if=\"externalPlayer !== '' && !externalPlayerIsDefaultViewingMode\"\n        :title=\"$t('Video.External Player.OpenInTemplate', { externalPlayer })\"\n        :icon=\"['fas', 'external-link-alt']\"\n        class=\"externalPlayerIcon\"\n        theme=\"base\"\n        :padding=\"appearance === `watchPlaylistItem` ? 6 : 7\"\n        :size=\"appearance === `watchPlaylistItem` ? 12 : 16\"\n        @click=\"handleExternalPlayer\"\n      />\n      <span class=\"playlistIcons\">\n        <ft-icon-button\n          v-if=\"showPlaylists\"\n          :title=\"$t('User Playlists.Add to Playlist')\"\n          :icon=\"['fas', 'plus']\"\n          class=\"addToPlaylistIcon\"\n          :class=\"alwaysShowAddToPlaylistButton ? 'alwaysVisible' : ''\"\n          :padding=\"appearance === `watchPlaylistItem` ? 5 : 6\"\n          :size=\"appearance === `watchPlaylistItem` ? 14 : 18\"\n          @click=\"togglePlaylistPrompt\"\n        />\n        <ft-icon-button\n          v-if=\"isQuickBookmarkEnabled && quickBookmarkButtonEnabled\"\n          :title=\"quickBookmarkIconText\"\n          :icon=\"isInQuickBookmarkPlaylist ? ['fas', 'check'] : ['fas', 'bookmark']\"\n          class=\"quickBookmarkVideoIcon\"\n          :class=\"{\n            bookmarked: isInQuickBookmarkPlaylist,\n            alwaysVisible: alwaysShowAddToPlaylistButton,\n          }\"\n          :theme=\"quickBookmarkIconTheme\"\n          :padding=\"appearance === `watchPlaylistItem` ? 5 : 6\"\n          :size=\"appearance === `watchPlaylistItem` ? 14 : 18\"\n          @click=\"toggleQuickBookmarked\"\n        />\n        <ft-icon-button\n          v-if=\"inUserPlaylist && canMoveVideoUp\"\n          :title=\"$t('User Playlists.Move Video Up')\"\n          :icon=\"effectiveListTypeIsList ? ['fas', 'arrow-up'] : ['fas', 'arrow-left']\"\n          class=\"upArrowIcon\"\n          :padding=\"appearance === `watchPlaylistItem` ? 5 : 6\"\n          :size=\"appearance === `watchPlaylistItem` ? 14 : 18\"\n          @click=\"moveVideoUp\"\n        />\n        <ft-icon-button\n          v-if=\"inUserPlaylist && canMoveVideoDown\"\n          :title=\"$t('User Playlists.Move Video Down')\"\n          :icon=\"effectiveListTypeIsList ? ['fas', 'arrow-down'] : ['fas', 'arrow-right']\"\n          class=\"downArrowIcon\"\n          :padding=\"appearance === `watchPlaylistItem` ? 5 : 6\"\n          :size=\"appearance === `watchPlaylistItem` ? 14 : 18\"\n          @click=\"moveVideoDown\"\n        />\n        <ft-icon-button\n          v-if=\"inUserPlaylist && canRemoveFromPlaylist\"\n          :title=\"$t('User Playlists.Remove from Playlist')\"\n          :icon=\"['fas', 'trash']\"\n          class=\"trashIcon\"\n          :padding=\"appearance === `watchPlaylistItem` ? 5 : 6\"\n          :size=\"appearance === `watchPlaylistItem` ? 14 : 18\"\n          @click=\"removeFromPlaylist\"\n        />\n      </span>\n      <div\n        v-if=\"addWatchedStyle\"\n        class=\"videoWatched\"\n      >\n        {{ $t(\"Video.Watched\") }}\n      </div>\n      <div\n        v-if=\"historyEntryExists\"\n        class=\"watchedProgressBar\"\n        :style=\"{inlineSize: progressPercentage + '%'}\"\n      />\n    </div>\n    <div class=\"info\">\n      <router-link\n        class=\"title\"\n        :to=\"watchVideoRouterLink\"\n        @click=\"handleWatchPageLinkClick\"\n      >\n        <h3\n          class=\"h3Title\"\n          dir=\"auto\"\n        >\n          {{ displayTitle }}\n        </h3>\n      </router-link>\n      <div class=\"infoLine\">\n        <router-link\n          v-if=\"channelId !== null\"\n          class=\"channelName\"\n          dir=\"auto\"\n          :to=\"`/channel/${channelId}`\"\n        >\n          {{ channelName }}\n        </router-link>\n        <bdi v-else-if=\"channelName !== null\">\n          {{ channelName }}\n        </bdi>\n        <span\n          v-if=\"!isLive && !isUpcoming && !isPremium && !hideViews && viewCount != null\"\n          class=\"viewCount\"\n        >\n          <template v-if=\"channelId !== null || channelName !== null\"> • </template>\n          {{ $t('Global.Counts.View Count', {count: parsedViewCount}, viewCount) }}\n        </span>\n        <span\n          v-if=\"uploadedTime !== '' && !isLive\"\n          class=\"uploadedTime\"\n        > • {{ uploadedTime }}</span>\n        <span\n          v-if=\"isLive && !hideViews\"\n          class=\"viewCount\"\n        > • {{ $t('Global.Counts.Watching Count', {count: parsedViewCount}, viewCount) }}</span>\n      </div>\n      <div\n        v-if=\"is4k || hasCaptions || is8k || isNew || isVr180 || isVr360 || is3D\"\n        class=\"videoTagLine\"\n      >\n        <div\n          v-if=\"isNew\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.New')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.New') }}\n        </div>\n        <div\n          v-if=\"is4k\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.4K')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.4K') }}\n        </div>\n        <div\n          v-if=\"is8k\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.8K')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.8K') }}\n        </div>\n        <div\n          v-if=\"isVr180\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.VR180')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.VR180') }}\n        </div>\n        <div\n          v-if=\"isVr360\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.360 Video')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.360 Video') }}\n        </div>\n        <div\n          v-if=\"is3D\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.3D')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.3D') }}\n        </div>\n        <div\n          v-if=\"hasCaptions\"\n          class=\"videoTag\"\n          :aria-label=\"$t('Search Listing.Label.Closed Captions')\"\n          role=\"img\"\n        >\n          {{ $t('Search Listing.Label.Subtitles') }}\n        </div>\n      </div>\n      <div class=\"buttonStack\">\n        <ft-icon-button\n          class=\"optionsButton\"\n          :icon=\"['fas', 'ellipsis-v']\"\n          :title=\"$t('Video.More Options')\"\n          theme=\"base-no-default\"\n          :size=\"16\"\n          :use-shadow=\"false\"\n          dropdown-position-x=\"left\"\n          :dropdown-options=\"dropdownOptions\"\n          @click=\"handleOptionsClick\"\n        />\n        <button\n          v-if=\"deArrowChangedContent || deArrowTogglePinned\"\n          :title=\"deArrowToggleTitle\"\n          class=\"optionsButton deArrowToggleButton\"\n          :class=\"{ alwaysVisible: deArrowTogglePinned }\"\n          @click=\"toggleDeArrow\"\n        >\n          <font-awesome-icon\n            class=\"deArrowToggleIcon\"\n            :icon=\"['far', 'dot-circle']\"\n          />\n        </button>\n      </div>\n      <p\n        v-if=\"description && effectiveListTypeIsList && appearance === 'result'\"\n        v-safer-html=\"description\"\n        class=\"description\"\n        dir=\"auto\"\n      />\n    </div>\n  </div>\n</template>\n\n<script src=\"./ft-list-video.js\" />\n<style scoped src=\"./ft-list-video.scss\" lang=\"scss\" />\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.css",
    "content": "/* stylelint-disable liberty/use-logical-spec */\n.ftVideoPlayer {\n  display: flex;\n  position: relative;\n\n  /*\n    For vertical videos and full window mode the background is visible,\n    so we want to make it black as it defaults to transparent\n   */\n  background-color: #000;\n\n  /*\n    Fixes the seek bar thumbnails causing a horizontal scroll bar\n    to appear after exiting full screen and full window.\n    But also vertically in case context menu overflows.\n  */\n  overflow: hidden;\n}\n\n.player {\n  width: 100%;\n}\n\n.vrCanvas {\n  position: absolute;\n  inset: 0;\n  margin: 0;\n  padding: 0;\n  width: 100%;\n  height: 100%;\n  pointer-events: none;\n}\n\n:deep(.shaka-bottom-controls) {\n  /*\n    Force left to right, so that the UI doesn't break.\n    With rtl, the progress bar was filling from the left, but the scrubber was moving from the right.\n    video.js forced the direction for their controls too\n  */\n  direction: ltr;\n}\n\n.sixteenByNine {\n  aspect-ratio: 16 / 9;\n}\n\n.stats {\n  position: absolute;\n  left: 5px;\n  top: 5px;\n  padding: 10px;\n  border-radius: 5px;\n  line-height: 1.4em;\n  background-color: rgb(0 0 0 / 70%);\n  color: #fff;\n  z-index: 2;\n\n  /* user-select is intentionally not disabled, so that you can select and copy the stats */\n}\n\n.valueChangePopup {\n  position: absolute;\n  top: 20px;\n  left: 50%;\n  transform: translateX(-50%);\n  padding: 10px;\n  border-radius: 5px;\n  font-size: 1.1em;\n  background-color: rgb(0 0 0 / 70%);\n  color: #fff;\n  width: 85px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 4px;\n  z-index: 2;\n  pointer-events: none;\n}\n\n.valueChangePopup.invert-content-order {\n  flex-direction: row-reverse;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.5s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n  opacity: 0;\n}\n\n.offlineWrapper {\n  position: absolute;\n  top: 20px;\n  inset-inline-end: 20px;\n  margin-inline-start: 20px;\n  display: flex;\n  flex-direction: row;\n  gap: 10px;\n  align-items: center;\n  background-color: #000;\n  color: #fff;\n  padding: 10px;\n  border-radius: 10px;\n}\n\n.offlineIcon {\n  font-size: 30px;\n}\n\n.offlineMessage {\n  margin: 0;\n}\n\n.offlineMessageSubtitle {\n  font-size: 0.8em;\n}\n\n.skippedSegmentsWrapper {\n  position: absolute;\n  right: 2%;\n  bottom: max(15%, calc(46px + 2.5% + 3%)); /* 46px + 2.5% is the height of the controls */\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n  align-items: center;\n  pointer-events: none;\n}\n\n.skippedSegment {\n  margin-block: 0;\n  padding: 10px;\n  border-radius: 20px;\n  background-color: rgb(0 0 0 / 80%);\n  color: #fff;\n}\n\n:deep(.markerContainer) {\n  position: absolute;\n  inset: 0;\n  margin: 0;\n  padding: 0;\n  width: 100%;\n  height: 100%;\n}\n\n:deep(.sponsorBlockMarker) {\n  background-color: var(--primary-color);\n}\n\n:deep(.chapterMarker) {\n  width: 2px;\n  background-color: #000;\n}\n\n:deep(.sponsorBlockMarker),\n:deep(.chapterMarker) {\n  position: absolute;\n  opacity: 0.6;\n  height: 100%;\n}\n\n:deep(.playerFullscreenTitleOverlay) {\n  display: none;\n  opacity: 0;\n  position: absolute;\n  margin: 0;\n  top: 5px;\n  left: 5px;\n  max-width: calc(100% - 10px);\n  font-size: xx-large;\n  color: #fff;\n  font-weight: normal;\n  background-color: rgb(0 0 0 / 50%);\n  border-radius: 5px;\n  user-select: none;\n  text-overflow: ellipsis;\n  text-wrap: nowrap;\n  overflow: hidden;\n\n  /* copied from .shaka-scrim-container */\n  transition: opacity cubic-bezier(0.4, 0, 0.6, 1) 0.6s;\n}\n\n:deep(.playerFullscreenTitleOverlay:dir(rtl)) {\n  left: initial;\n  right: 5px;\n}\n\n.ftVideoPlayer:fullscreen :deep(.playerFullscreenTitleOverlay) {\n  display: block;\n}\n\n:deep(.shaka-controls-container[shown='true'] > .playerFullscreenTitleOverlay) {\n  opacity: 1;\n}\n\n:deep(.shaka-controls-button-panel>.ft-shaka-skip-button .shaka-ui-icon) {\n  font-size: 32px;\n}\n\n.ftVideoPlayer:fullscreen :deep(.theatre-button),\n.ftVideoPlayer:fullscreen :deep(.full-window-button),\n.fullWindow :deep(.theatre-button) {\n  display: none;\n}\n\n.fullWindow {\n  position: absolute !important;\n  max-width: initial !important;\n  inset: 0;\n  z-index: 1000;\n}\n\n.fullWindow > .player {\n  width: 100%;\n  height: 100%;\n}\n\n/* added to the body element */\n:global(.playerFullWindow) {\n  overflow: hidden;\n  margin: 0;\n  padding: 0;\n}\n\n@media only screen and (width <=400px) {\n  :deep(.shaka-text-container) {\n    /* make subtitles take up slightly less space when a mobile phone is in portrait orientation */\n    font-size: 16px !important;\n  }\n}\n\n@media only screen and (width <=1000px) {\n  :deep(.playerFullscreenTitleOverlay) {\n    font-size: large;\n  }\n}\n\n@media only screen and (width <=1350px) {\n  :deep(.theatre-button) {\n    display: none;\n  }\n}\n\n@media (prefers-reduced-transparency) {\n  :deep(.playerFullscreenTitleOverlay),\n  .skippedSegment,\n  .stats {\n    background-color: rgb(0 0 0 / 90%);\n  }\n}\n\n/* stylelint-enable liberty/use-logical-spec */\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js",
    "content": "import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, onUnmounted, reactive, ref, shallowRef, watch } from 'vue'\nimport shaka from 'shaka-player'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport store from '../../store/index'\nimport { KeyboardShortcuts } from '../../../constants'\nimport { AudioTrackSelection } from './player-components/AudioTrackSelection'\nimport { FullWindowButton } from './player-components/FullWindowButton'\nimport { LegacyQualitySelection } from './player-components/LegacyQualitySelection'\nimport { ScreenshotButton } from './player-components/ScreenshotButton'\nimport { StatsButton } from './player-components/StatsButton'\nimport { TheatreModeButton } from './player-components/TheatreModeButton'\nimport { AutoplayToggle } from './player-components/AutoplayToggle'\nimport { SkipButton } from './player-components/SkipButton'\nimport {\n  deduplicateAudioTracks,\n  findMostSimilarAudioBandwidth,\n  getSponsorBlockSegments,\n  logShakaError,\n  repairInvidiousManifest,\n  translateSponsorBlockCategory\n} from '../../helpers/player/utils'\nimport {\n  addKeyboardShortcutToActionTitle,\n  showToast,\n  writeFileWithPicker,\n  throttle,\n  debounce,\n  removeFromArrayIfExists,\n} from '../../helpers/utils'\nimport { MANIFEST_TYPE_SABR } from '../../helpers/player/SabrManifestParser'\nimport { setupSabrScheme } from '../../helpers/player/SabrSchemePlugin'\n\n/** @typedef {import('../../helpers/sponsorblock').SponsorBlockCategory} SponsorBlockCategory */\n\n// The UTF-8 characters \"h\", \"t\", \"t\", and \"p\".\nconst HTTP_IN_HEX = 0x68747470\n\nconst USE_OVERFLOW_MENU_WIDTH_THRESHOLD = 634\n\nconst RequestType = shaka.net.NetworkingEngine.RequestType\nconst AdvancedRequestType = shaka.net.NetworkingEngine.AdvancedRequestType\nconst TrackLabelFormat = shaka.ui.Overlay.TrackLabelFormat\nconst { Severity: ErrorSeverity, Category: ErrorCategory, Code: ErrorCode } = shaka.util.Error\n\n/*\n  Mapping of Shaka localization keys for control labels to FreeTube shortcuts.\n  See: https://github.com/shaka-project/shaka-player/blob/main/ui/locales/en.json\n*/\nconst shakaControlKeysToShortcuts = {\n  MUTE: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.MUTE,\n  UNMUTE: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.MUTE,\n  PLAY: KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.PLAY,\n  PAUSE: KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.PLAY,\n  PICTURE_IN_PICTURE: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE,\n  ENTER_PICTURE_IN_PICTURE: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE,\n  EXIT_PICTURE_IN_PICTURE: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE,\n  CAPTIONS: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.CAPTIONS,\n  FULL_SCREEN: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.FULLSCREEN,\n  EXIT_FULL_SCREEN: KeyboardShortcuts.VIDEO_PLAYER.GENERAL.FULLSCREEN\n}\n\n/** @type {Map<string, string>} */\nconst LOCALE_MAPPINGS = new Map(process.env.SHAKA_LOCALE_MAPPINGS)\n\nexport default defineComponent({\n  name: 'FtShakaVideoPlayer',\n  props: {\n    format: {\n      type: String,\n      required: true\n    },\n    manifestSrc: {\n      type: String,\n      default: null\n    },\n    manifestMimeType: {\n      type: String,\n      required: true\n    },\n    sabrData: {\n      type: Object,\n      default: null\n    },\n    legacyFormats: {\n      type: Array,\n      default: () => ([])\n    },\n    startTime: {\n      type: Number,\n      default: null\n    },\n    captions: {\n      type: Array,\n      default: () => ([])\n    },\n    chapters: {\n      type: Array,\n      default: () => ([])\n    },\n    currentChapterIndex: {\n      type: Number,\n      default: 0\n    },\n    storyboardSrc: {\n      type: String,\n      default: ''\n    },\n    videoId: {\n      type: String,\n      default: ''\n    },\n    title: {\n      type: String,\n      default: ''\n    },\n    thumbnail: {\n      type: String,\n      default: ''\n    },\n    theatrePossible: {\n      type: Boolean,\n      default: false\n    },\n    useTheatreMode: {\n      type: Boolean,\n      default: false\n    },\n    autoplayPossible: {\n      type: Boolean,\n      default: false\n    },\n    autoplayEnabled: {\n      type: Boolean,\n      default: false\n    },\n    watchingPlaylist: {\n      type: Boolean,\n      default: false\n    },\n    vrProjection: {\n      type: String,\n      default: null\n    },\n    startInFullscreen: {\n      type: Boolean,\n      default: false\n    },\n    startInFullwindow: {\n      type: Boolean,\n      default: false\n    },\n    startInPip: {\n      type: Boolean,\n      default: false\n    },\n    currentPlaybackRate: {\n      type: Number,\n      default: 1\n    },\n    delayLoadUntilUnix: {\n      type: Number,\n      default: 0\n    },\n  },\n  emits: [\n    'error',\n    'loaded',\n    'ended',\n    'timeupdate',\n    'toggle-autoplay',\n    'toggle-theatre-mode',\n    'playback-rate-updated',\n    'skip-to-next',\n    'skip-to-prev',\n    'player-reload-requested',\n  ],\n  setup: function (props, { emit, expose }) {\n    const { locale, t } = useI18n()\n\n    /** @type {shaka.Player|null} */\n    let player = null\n\n    /** @type {shaka.ui.Overlay|null} */\n    let ui = null\n\n    const events = new EventTarget()\n\n    /** @type {import('vue').Ref<HTMLDivElement | null>} */\n    const container = ref(null)\n\n    /** @type {import('vue').Ref<HTMLVideoElement | null>} */\n    const video = ref(null)\n\n    /** @type {import('vue').Ref<HTMLCanvasElement | null>} */\n    const vrCanvas = ref(null)\n\n    const hasLoaded = ref(false)\n\n    const hasMultipleAudioTracks = ref(false)\n    const isLive = ref(false)\n\n    const onlyUseOverFlowMenu = ref(false)\n    const forceAspectRatio = ref(false)\n\n    const activeLegacyFormat = shallowRef(null)\n\n    const fullWindowEnabled = ref(false)\n    const startInFullwindow = props.startInFullwindow\n    let startInFullscreen = props.startInFullscreen\n    let startInPip = props.startInPip\n\n    /** @type {number|null} */\n    let restoreCaptionIndex = null\n\n    if (store.getters.getEnableSubtitlesByDefault && props.captions.length > 0) {\n      restoreCaptionIndex = 0\n    }\n\n    const showStats = ref(false)\n    const stats = reactive({\n      resolution: {\n        width: 0,\n        height: 0,\n        frameRate: 0\n      },\n      bitrate: '0',\n      volume: '100',\n      bandwidth: '0',\n      buffered: '0',\n      frames: {\n        totalFrames: 0,\n        droppedFrames: 0\n      },\n      codecs: {\n        audioItag: '',\n        audioCodec: '',\n        videoItag: '',\n        videoCodec: ''\n      }\n    })\n\n    const playerDimensions = computed(() => ({\n      width: playerWidth.value,\n      height: playerHeight.value\n    }))\n\n    // #region settings\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const autoplayVideos = computed(() => {\n      return store.getters.getAutoplayVideos\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const displayVideoPlayButton = computed(() => {\n      return store.getters.getDisplayVideoPlayButton\n    })\n\n    watch(displayVideoPlayButton, (newValue) => {\n      ui.configure({\n        bigButtons: newValue ? ['play_pause'] : []\n      })\n    })\n\n    /** @type {import('vue').ComputedRef<number>} */\n    const defaultSkipInterval = computed(() => {\n      return store.getters.getDefaultSkipInterval\n    })\n\n    watch(defaultSkipInterval, (newValue) => {\n      ui.configure({\n        tapSeekDistance: newValue\n      })\n    })\n\n    /** @type {import('vue').ComputedRef<number | 'auto'>} */\n    const defaultQuality = computed(() => {\n      const value = store.getters.getDefaultQuality\n      if (value === 'auto') { return value }\n\n      return parseInt(value)\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const enterFullscreenOnDisplayRotate = computed(() => {\n      return store.getters.getEnterFullscreenOnDisplayRotate\n    })\n\n    watch(enterFullscreenOnDisplayRotate, (newValue) => {\n      ui.configure({\n        enableFullscreenOnRotation: newValue\n      })\n    })\n\n    /** @type {import('vue').ComputedRef<number>} */\n    const defaultPlaybackRate = computed(() => {\n      return store.getters.getDefaultPlayback\n    })\n\n    watch(defaultPlaybackRate, (newValue) => {\n      if (video.value) {\n        video.value.defaultPlaybackRate = newValue\n      }\n    })\n\n    const maxVideoPlaybackRate = computed(() => {\n      return parseInt(store.getters.getMaxVideoPlaybackRate)\n    })\n\n    const videoPlaybackRateInterval = computed(() => {\n      return parseFloat(store.getters.getVideoPlaybackRateInterval)\n    })\n\n    const playbackRates = computed(() => {\n      const interval = videoPlaybackRateInterval.value\n      const playbackRates = []\n      let i = interval\n\n      while (i <= maxVideoPlaybackRate.value) {\n        playbackRates.unshift(i)\n        i += interval\n        i = parseFloat(i.toFixed(2))\n      }\n\n      return playbackRates\n    })\n\n    watch(playbackRates, (newValue) => {\n      ui.configure({\n        playbackRates: newValue\n      })\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const enableScreenshot = computed(() => {\n      return store.getters.getEnableScreenshot\n    })\n\n    /** @type {import('vue').ComputedRef<string>} */\n    const screenshotFormat = computed(() => {\n      return store.getters.getScreenshotFormat\n    })\n\n    /** @type {import('vue').ComputedRef<number>} */\n    const screenshotQuality = computed(() => {\n      return store.getters.getScreenshotQuality\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const screenshotAskPath = computed(() => {\n      return store.getters.getScreenshotAskPath\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const videoVolumeMouseScroll = computed(() => {\n      return store.getters.getVideoVolumeMouseScroll\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const videoPlaybackRateMouseScroll = computed(() => {\n      return store.getters.getVideoPlaybackRateMouseScroll\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const videoSkipMouseScroll = computed(() => {\n      return store.getters.getVideoSkipMouseScroll\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const useSponsorBlock = computed(() => {\n      return store.getters.getUseSponsorBlock\n    })\n\n    /** @type {import('vue').ComputedRef<boolean>} */\n    const sponsorBlockShowSkippedToast = computed(() => {\n      return store.getters.getSponsorBlockShowSkippedToast\n    })\n\n    const sponsorSkips = computed(() => {\n      // save some work when sponsorblock is disabled\n      if (!useSponsorBlock.value) {\n        return {}\n      }\n\n      /** @type {SponsorBlockCategory[]} */\n      const sponsorCategories = ['sponsor',\n        'selfpromo',\n        'interaction',\n        'intro',\n        'outro',\n        'preview',\n        'music_offtopic',\n        'filler'\n      ]\n\n      /** @type {Set<SponsorBlockCategory>} */\n      const autoSkip = new Set()\n\n      /** @type {SponsorBlockCategory[]} */\n      const seekBar = []\n\n      /** @type {Set<SponsorBlockCategory>} */\n      const promptSkip = new Set()\n\n      /**\n       * @type {{\n       *   [key in SponsorBlockCategory]: {\n       *     color: string,\n       *     skip: 'autoSkip' | 'promptToSkip' | 'showInSeekBar' | 'doNothing'\n       *   }\n        }} */\n      const categoryData = {}\n\n      sponsorCategories.forEach(x => {\n        let sponsorVal = {}\n        switch (x) {\n          case 'sponsor':\n            sponsorVal = store.getters.getSponsorBlockSponsor\n            break\n          case 'selfpromo':\n            sponsorVal = store.getters.getSponsorBlockSelfPromo\n            break\n          case 'interaction':\n            sponsorVal = store.getters.getSponsorBlockInteraction\n            break\n          case 'intro':\n            sponsorVal = store.getters.getSponsorBlockIntro\n            break\n          case 'outro':\n            sponsorVal = store.getters.getSponsorBlockOutro\n            break\n          case 'preview':\n            sponsorVal = store.getters.getSponsorBlockRecap\n            break\n          case 'music_offtopic':\n            sponsorVal = store.getters.getSponsorBlockMusicOffTopic\n            break\n          case 'filler':\n            sponsorVal = store.getters.getSponsorBlockFiller\n            break\n        }\n\n        if (sponsorVal.skip !== 'doNothing') {\n          seekBar.push(x)\n        }\n\n        if (sponsorVal.skip === 'autoSkip') {\n          autoSkip.add(x)\n        }\n\n        if (sponsorVal.skip === 'promptToSkip') {\n          promptSkip.add(x)\n        }\n\n        categoryData[x] = sponsorVal\n      })\n      return { autoSkip, seekBar, promptSkip, categoryData }\n    })\n\n    // #endregion settings\n\n    // #region SponsorBlock\n\n    /**\n     * @type {{\n     *   uuid: string\n     *   category: SponsorBlockCategory\n     *   startTime: number,\n     *   endTime: number\n     * }[]}\n     */\n    let sponsorBlockSegments = []\n    let sponsorBlockAverageVideoDuration = 0\n\n    /**\n     * Yes a map would be much more suitable for this (unlike objects they retain the order that items were inserted),\n     * but Vue 2 doesn't support reactivity on Maps, so we have to use an array instead\n     * @type {import('vue').Ref<{uuid: string, translatedCategory: string, timeoutId: number}[]>}\n     */\n    const skippedSponsorBlockSegments = ref([])\n\n    async function setupSponsorBlock() {\n      let segments, averageDuration\n\n      try {\n        ({ segments, averageDuration } = await getSponsorBlockSegments(props.videoId, sponsorSkips.value.seekBar))\n      } catch (e) {\n        console.error(e)\n        segments = []\n      }\n\n      // check if the component is already getting destroyed\n      // which is possible because this function runs asynchronously\n      if (!ui || !player) {\n        return\n      }\n\n      if (segments.length > 0) {\n        sponsorBlockSegments = segments\n        sponsorBlockAverageVideoDuration = averageDuration\n\n        createSponsorBlockMarkers(averageDuration)\n      }\n    }\n\n    /**\n     * @param {number} currentTime\n     */\n    function skipSponsorBlockSegments(currentTime) {\n      const { autoSkip } = sponsorSkips.value\n\n      if (autoSkip.size === 0) {\n        return\n      }\n\n      const video_ = video.value\n\n      let newTime = 0\n      const skippedSegments = []\n\n      sponsorBlockSegments.forEach(segment => {\n        if (autoSkip.has(segment.category) && currentTime < segment.endTime &&\n          (segment.startTime <= currentTime ||\n            // if we already have a segment to skip, check if there are any that are less than 150ms later,\n            // so that we can skip them all in one go (especially useful on slow connections)\n            (newTime > 0 && (segment.startTime < newTime || segment.startTime - newTime <= 0.150) && segment.endTime > newTime))) {\n          newTime = segment.endTime\n          skippedSegments.push(segment)\n        }\n      })\n\n      if (newTime === 0 || video_.ended) {\n        return\n      }\n\n      const videoEnd = player.seekRange().end\n\n      if (Math.abs(videoEnd - currentTime) < 1 || video_.ended) {\n        return\n      }\n\n      if (newTime > videoEnd || Math.abs(videoEnd - newTime) < 1) {\n        newTime = videoEnd\n      }\n\n      video_.currentTime = newTime\n\n      if (sponsorBlockShowSkippedToast.value) {\n        skippedSegments.forEach(({ uuid, category }) => {\n          // if the element already exists, just update the timeout, instead of creating a duplicate\n          // can happen at the end of the video sometimes\n          const existingSkip = skippedSponsorBlockSegments.value.find(skipped => skipped.uuid === uuid)\n          if (existingSkip) {\n            clearTimeout(existingSkip.timeoutId)\n\n            existingSkip.timeoutId = setTimeout(() => {\n              const index = skippedSponsorBlockSegments.value.findIndex(skipped => skipped.uuid === uuid)\n              skippedSponsorBlockSegments.value.splice(index, 1)\n            }, 2000)\n          } else {\n            skippedSponsorBlockSegments.value.push({\n              uuid,\n              translatedCategory: translateSponsorBlockCategory(category),\n              timeoutId: setTimeout(() => {\n                const index = skippedSponsorBlockSegments.value.findIndex(skipped => skipped.uuid === uuid)\n                skippedSponsorBlockSegments.value.splice(index, 1)\n              }, 2000)\n            })\n          }\n        })\n      }\n    }\n\n    // #endregion SponsorBlock\n\n    // #region player config\n\n    const seekingIsPossible = computed(() => {\n      if (props.manifestMimeType !== 'application/x-mpegurl') {\n        return true\n      }\n\n      const match = props.manifestSrc.match(/\\/(?:manifest|playlist)_duration\\/(\\d+)\\//)\n\n      // Check how many seconds we are allowed to seek, 30 is too short, 3600 is an hour which is great\n      return match != null && parseInt(match[1] || '0') > 30\n    })\n\n    /**\n     * @param {'dash'|'audio'|'legacy'} format\n     * @param {boolean} useAutoQuality\n     * @returns {shaka.extern.PlayerConfiguration}\n     */\n    function getPlayerConfig(format, useAutoQuality = false) {\n      return {\n        // YouTube uses these values and they seem to work well in FreeTube too,\n        // so we might as well use them\n        streaming: {\n          bufferingGoal: 180,\n          rebufferingGoal: 0.02,\n          bufferBehind: 300\n        },\n        manifest: {\n          disableVideo: format === 'audio',\n\n          // makes captions work for live streams and doesn't seem to have any negative affect on VOD videos\n          segmentRelativeVttTiming: true,\n          dash: {\n            manifestPreprocessorTXml: manifestPreprocessorTXml\n          },\n        },\n        abr: {\n          enabled: useAutoQuality,\n\n          // This only affects the \"auto\" quality, users can still manually select whatever quality they want.\n          restrictToElementSize: true\n        },\n\n        // Prioritise variants that are predicted to play:\n        // - `smooth`: without dropping frames\n        // - `powerEfficient` the spec is quite vague but in Chromium it should prioritise hardware decoding when available\n        // https://developer.mozilla.org/en-US/docs/Web/API/MediaCapabilities/decodingInfo\n        preferredDecodingAttributes: format === 'dash' ? ['smooth', 'powerEfficient'] : [],\n\n        // Electron doesn't like YouTube's vp9 VR video streams and throws:\n        // \"CHUNK_DEMUXER_ERROR_APPEND_FAILED: Projection element is incomplete; ProjectionPoseYaw required.\"\n        // So use the AV1 and h264 codecs instead which it doesn't reject\n        preferredVideoCodecs: typeof props.vrProjection === 'string' ? ['av01', 'avc1'] : []\n      }\n    }\n\n    /**\n     * @param {shaka.extern.xml.Node} mpdNode\n     */\n    function manifestPreprocessorTXml(mpdNode) {\n      /** @type {shaka.extern.xml.Node[]} */\n      const periods = mpdNode.children?.filter(child => typeof child !== 'string' && child.tagName === 'Period') ?? []\n\n      sortAdapationSetsByCodec(periods)\n      sortAudioAdaptationSetsByBitrate(periods)\n\n      if (mpdNode.attributes.type === 'dynamic') {\n        // fix live stream loading issues\n        // YouTube uses a 12 second delay on the official website for normal streams\n        // and a shorter one for low latency streams\n        // If we don't add a little bit of a delay, we get presented with a loading symbol every 5 seconds,\n        // while shaka-player processes the new manifest and segments\n        const minimumUpdatePeriod = parseFloat(mpdNode.attributes.minimumUpdatePeriod.match(/^PT(\\d+(?:\\.\\d+)?)S$/)[1])\n        mpdNode.attributes.suggestedPresentationDelay = `PT${(minimumUpdatePeriod * 2).toFixed(3)}S`\n\n        // fix live streams with subtitles having duplicate Representation ids\n        // shaka-player throws DASH_DUPLICATE_REPRESENTATION_ID if we don't fix it\n\n        for (const period of periods) {\n          /** @type {shaka.extern.xml.Node[]} */\n          const representations = []\n\n          for (const periodChild of period.children) {\n            if (typeof periodChild !== 'string' && periodChild.tagName === 'AdaptationSet') {\n              for (const adaptationSetChild of periodChild.children) {\n                if (typeof adaptationSetChild !== 'string' && adaptationSetChild.tagName === 'Representation') {\n                  representations.push(adaptationSetChild)\n                }\n              }\n            }\n          }\n\n          const knownIds = new Set()\n          let counter = 0\n          for (const representation of representations) {\n            const id = representation.attributes.id\n\n            if (knownIds.has(id)) {\n              const newId = `${id}-ft-fix-${counter}`\n\n              representation.attributes.id = newId\n              knownIds.add(newId)\n              counter++\n            } else {\n              knownIds.add(id)\n            }\n          }\n        }\n      } else if (!process.env.SUPPORTS_LOCAL_API) {\n        repairInvidiousManifest(periods)\n      }\n    }\n\n    /**\n     * @param {shaka.extern.xml.Node[]} periods\n     */\n    function sortAdapationSetsByCodec(periods) {\n      /** @param {shaka.extern.xml.Node} adaptationSet */\n      const getCodecsPrefix = (adaptationSet) => {\n        const codecs = adaptationSet.attributes.codecs ??\n          adaptationSet.children\n            .find(child => typeof child !== 'string' && child.tagName === 'Representation').attributes.codecs\n\n        return codecs.split('.')[0]\n      }\n\n      const codecPriorities = [\n        // audio\n        'opus',\n        'mp4a',\n        'ec-3',\n        'ac-3',\n\n        // video\n        'av01',\n        'vp09',\n        'vp9',\n        'avc1'\n      ]\n\n      for (const period of periods) {\n        period.children\n          ?.sort((\n            /** @type {shaka.extern.xml.Node | string} */ a,\n            /** @type {shaka.extern.xml.Node | string} */ b\n          ) => {\n            if (typeof a === 'string' || a.tagName !== 'AdaptationSet' ||\n              typeof b === 'string' || b.tagName !== 'AdaptationSet') {\n              return 0\n            }\n\n            const typeA = a.attributes.contentType || a.attributes.mimeType.split('/')[0]\n            const typeB = b.attributes.contentType || b.attributes.mimeType.split('/')[0]\n\n            // always place image and text tracks AdaptionSets last in the manifest\n\n            if (typeA !== 'video' && typeA !== 'audio') {\n              return 1\n            }\n            if (typeB !== 'video' && typeB !== 'audio') {\n              return -1\n            }\n\n            const codecsPrefixA = getCodecsPrefix(a)\n            const codecsPrefixB = getCodecsPrefix(b)\n\n            return codecPriorities.indexOf(codecsPrefixA) - codecPriorities.indexOf(codecsPrefixB)\n          })\n      }\n    }\n\n    /**\n     * Sort audio AdaptationSets so that streams with higher bitrates come first.\n     * Workaround that makes the player select high-quality audio.\n     * @param {shaka.extern.xml.Node[]} periods\n     */\n    function sortAudioAdaptationSetsByBitrate(periods) {\n      for (const period of periods) {\n        period.children\n          ?.filter(child => typeof child !== 'string' && child.tagName === 'AdaptationSet' &&\n            (child.attributes.contentType === 'audio' || child.attributes.mimeType.startsWith('audio/')))\n          .forEach(adaptationSet => {\n            adaptationSet.children.sort((a, b) => {\n              if (a.tagName === 'AudioChannelConfiguration' && b.tagName !== 'AudioChannelConfiguration') {\n                // Push AudioChannelConfiguration to the front (where it seems to already be) so that it doesn't\n                // block sorting Representations if it's in the middle instead\n                return -1\n              } else if (b.tagName === 'AudioChannelConfiguration' && a.tagName !== 'AudioChannelConfiguration') {\n                return 1\n              } else if (a.tagName === 'Representation' && b.tagName === 'Representation') {\n                return b.attributes.bandwidth - a.attributes.bandwidth\n              } else {\n                return 0\n              }\n            })\n          })\n      }\n    }\n\n    // #endregion player config\n\n    // #region UI config\n\n    const useVrMode = computed(() => {\n      return props.format === 'dash' && props.vrProjection === 'EQUIRECTANGULAR'\n    })\n\n    const uiConfig = computed(() => {\n      const controlPanelElements = [\n        'play_pause',\n        'mute',\n        'volume',\n        'time_and_duration',\n        'spacer'\n      ]\n      const controlPanelElementsWithSkipButtons = [\n        ...controlPanelElements.slice(0, 1),\n        'ft_skip_previous',\n        'ft_skip_next',\n        ...controlPanelElements.slice(1)\n      ]\n\n      /** @type {shaka.extern.UIConfiguration} */\n      const uiConfig = {\n        controlPanelElements: props.watchingPlaylist ? controlPanelElementsWithSkipButtons : controlPanelElements,\n        overflowMenuButtons: [],\n\n        // only set this to label when we actually have labels, so that the warning doesn't show up\n        // about it being set to labels, but that the audio tracks don't have labels\n        trackLabelFormat: hasMultipleAudioTracks.value ? TrackLabelFormat.LABEL : TrackLabelFormat.LANGUAGE_ROLE,\n        // Only set it to label if we added the captions ourselves,\n        // some live streams come with subtitles in the DASH manifest, but without labels\n        textTrackLabelFormat: props.captions.length > 0 ? TrackLabelFormat.LABEL : TrackLabelFormat.LANGUAGE,\n        displayInVrMode: useVrMode.value\n      }\n\n      /** @type {string[]} */\n      let elementList\n\n      if (onlyUseOverFlowMenu.value) {\n        uiConfig.overflowMenuButtons = [\n          'ft_autoplay_toggle',\n          props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',\n          'playback_rate',\n          'captions',\n          'ft_audio_tracks',\n          'loop',\n          'ft_screenshot',\n          'picture_in_picture',\n          'ft_full_window',\n          'recenter_vr',\n          'toggle_stereoscopic',\n        ]\n\n        elementList = uiConfig.overflowMenuButtons\n\n        uiConfig.controlPanelElements.push('overflow_menu', 'fullscreen')\n      } else {\n        uiConfig.controlPanelElements.push(\n          'ft_screenshot',\n          'ft_autoplay_toggle',\n          'overflow_menu',\n          'picture_in_picture',\n          'ft_theatre_mode',\n          'ft_full_window',\n          'fullscreen'\n        )\n\n        uiConfig.overflowMenuButtons.push(\n          'ft_audio_tracks',\n          'captions',\n          'playback_rate',\n          props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',\n          'loop',\n          'recenter_vr',\n          'toggle_stereoscopic',\n        )\n\n        elementList = uiConfig.controlPanelElements\n      }\n\n      if (!enableScreenshot.value || props.format === 'audio') {\n        removeFromArrayIfExists(elementList, 'ft_screenshot')\n      }\n\n      if (!props.theatrePossible) {\n        removeFromArrayIfExists(uiConfig.controlPanelElements, 'ft_theatre_mode')\n      }\n\n      if (!props.autoplayPossible) {\n        removeFromArrayIfExists(elementList, 'ft_autoplay_toggle')\n      }\n\n      if (props.format === 'audio') {\n        removeFromArrayIfExists(elementList, 'picture_in_picture')\n      }\n\n      if (isLive.value) {\n        removeFromArrayIfExists(uiConfig.overflowMenuButtons, 'loop')\n      }\n\n      if (!useVrMode.value) {\n        removeFromArrayIfExists(uiConfig.overflowMenuButtons, 'recenter_vr')\n        removeFromArrayIfExists(uiConfig.overflowMenuButtons, 'toggle_stereoscopic')\n      }\n\n      return uiConfig\n    })\n\n    /**\n     * For the first call we want to set initial values for options that may change later,\n     * as well as setting the options that we won't change again.\n     *\n     * For all subsequent calls we only want to reconfigure the options that have changed.\n     * e.g. due to the active format changing or the user changing settings\n     * @param {boolean} firstTime\n     */\n    function configureUI(firstTime = false) {\n      if (firstTime) {\n        /** @type {shaka.extern.UIConfiguration} */\n        const firstTimeConfig = {\n          addSeekBar: seekingIsPossible.value,\n          customContextMenu: true,\n          contextMenuElements: ['ft_stats'],\n          enableTooltips: true,\n          seekBarColors: {\n            played: 'var(--primary-color)'\n          },\n          showAudioCodec: false,\n          showVideoCodec: false,\n          volumeBarColors: {\n            level: 'var(--primary-color)'\n          },\n          mediaSession: {\n            // The WatchVideoInfo component handles that\n            handleMetadata: false,\n            // Need to override the default list so it doesn't override the next and previous video handlers in the WatchVideoPlaylist component.\n            supportedActions: [\n              'pause',\n              'play',\n              'seekbackward',\n              'seekforward',\n              'seekto'\n            ]\n          },\n\n          // these have their own watchers\n          bigButtons: displayVideoPlayButton.value ? ['play_pause'] : [],\n          enableFullscreenOnRotation: enterFullscreenOnDisplayRotate.value,\n          playbackRates: playbackRates.value,\n          tapSeekDistance: defaultSkipInterval.value,\n\n          // we have our own ones (shaka-player's ones are quite limited)\n          enableKeyboardPlaybackControls: false,\n\n          // TODO: enable this when electron gets document PiP support\n          // https://github.com/electron/electron/issues/39633\n          documentPictureInPicture: {\n            enabled: false\n          }\n        }\n\n        if (document.pictureInPictureEnabled) {\n          firstTimeConfig.mediaSession.supportedActions.push('enterpictureinpicture')\n        }\n\n        // Combine the config objects so we only need to do one configure call\n        // as shaka-player recreates the UI when you call configure\n        Object.assign(firstTimeConfig, uiConfig.value)\n\n        ui.configure(firstTimeConfig)\n      } else {\n        ui.configure(uiConfig.value)\n      }\n    }\n\n    /**\n     * @param {WheelEvent} event\n     */\n    function handleControlsContainerWheel(event) {\n      /** @type {DOMTokenList} */\n      const classList = event.target.classList\n\n      if (classList.contains('shaka-scrim-container') ||\n        classList.contains('shaka-fast-foward-container') ||\n        classList.contains('shaka-rewind-container') ||\n        classList.contains('shaka-play-button-container') ||\n        classList.contains('shaka-play-button') ||\n        classList.contains('shaka-controls-container')) {\n        //\n\n        if (event.ctrlKey || event.metaKey) {\n          if (videoPlaybackRateMouseScroll.value) {\n            mouseScrollPlaybackRateHandler(event)\n          }\n        } else {\n          if (videoVolumeMouseScroll.value) {\n            mouseScrollVolumeHandler(event)\n          } else if (videoSkipMouseScroll.value) {\n            mouseScrollSkipHandler(event)\n          }\n        }\n      }\n    }\n\n    /**\n     * @param {MouseEvent} event\n     */\n    function handleControlsContainerClick(event) {\n      if (event.ctrlKey || event.metaKey) {\n        // stop shaka-player's click handler firing\n        event.stopPropagation()\n\n        player.cancelTrickPlay()\n\n        showValueChange(`${defaultPlaybackRate.value}x`)\n      }\n    }\n\n    function addUICustomizations() {\n      /** @type {HTMLDivElement} */\n      const controlsContainer = ui.getControls().getControlsContainer()\n\n      controlsContainer.removeEventListener('wheel', handleControlsContainerWheel)\n      controlsContainer.removeEventListener('click', handleControlsContainerClick, true)\n\n      if (!useVrMode.value) {\n        if (videoVolumeMouseScroll.value || videoSkipMouseScroll.value || videoPlaybackRateMouseScroll.value) {\n          controlsContainer.addEventListener('wheel', handleControlsContainerWheel)\n        }\n\n        if (videoPlaybackRateMouseScroll.value) {\n          controlsContainer.addEventListener('click', handleControlsContainerClick, true)\n        }\n      }\n\n      // make scrolling over volume slider change the volume\n      container.value.querySelector('.shaka-volume-bar').addEventListener('wheel', mouseScrollVolumeHandler)\n\n      // title overlay when the video is fullscreened\n      // placing this inside the controls container so that we can fade it in and out at the same time as the controls\n      const fullscreenTitleOverlay = document.createElement('h1')\n      fullscreenTitleOverlay.textContent = props.title\n      fullscreenTitleOverlay.className = 'playerFullscreenTitleOverlay'\n      fullscreenTitleOverlay.dir = 'auto'\n      controlsContainer.appendChild(fullscreenTitleOverlay)\n\n      if (hasLoaded.value && props.chapters.length > 0) {\n        createChapterMarkers()\n      }\n\n      if (useSponsorBlock.value && sponsorBlockSegments.length > 0) {\n        let duration\n        if (hasLoaded.value) {\n          const seekRange = player.seekRange()\n\n          duration = seekRange.end - seekRange.start\n        } else {\n          duration = sponsorBlockAverageVideoDuration\n        }\n\n        createSponsorBlockMarkers(duration)\n      }\n    }\n\n    watch(uiConfig, (newValue, oldValue) => {\n      if (newValue !== oldValue && ui) {\n        configureUI()\n      }\n    })\n\n    watch(videoVolumeMouseScroll, (newValue, oldValue) => {\n      if (newValue !== oldValue && ui) {\n        configureUI()\n      }\n    })\n\n    watch(videoPlaybackRateMouseScroll, (newValue, oldValue) => {\n      if (newValue !== oldValue && ui) {\n        configureUI()\n      }\n    })\n\n    watch(videoSkipMouseScroll, (newValue, oldValue) => {\n      if (newValue !== oldValue && ui) {\n        configureUI()\n      }\n    })\n\n    watch(() => props.autoplayEnabled, (newValue, oldValue) => {\n      if (newValue !== oldValue) {\n        events.dispatchEvent(new CustomEvent('setAutoplay', {\n          detail: newValue\n        }))\n      }\n    })\n\n    /** @type {ResizeObserver|null} */\n    let containerResizeObserver = null\n\n    /** @type {ResizeObserverCallback} */\n    function resized(entries) {\n      onlyUseOverFlowMenu.value = entries[0].contentBoxSize[0].inlineSize <= USE_OVERFLOW_MENU_WIDTH_THRESHOLD\n    }\n\n    // #endregion UI config\n\n    // #region player locales\n\n    // shaka-player ships with some locales prebundled and already loaded\n    const loadedLocales = new Set(process.env.SHAKA_LOCALES_PREBUNDLED)\n\n    /**\n     * @param {string} locale\n     */\n    async function setLocale(locale) {\n      // For most of FreeTube's locales, there is an equivalent one in shaka-player,\n      // however if there isn't one we should fall back to US English.\n      // At the time of writing \"et\", \"eu\", \"gl\", \"is\" don't have any translations\n      const shakaLocale = LOCALE_MAPPINGS.get(locale) ?? 'en'\n\n      const localization = ui.getControls().getLocalization()\n\n      const cachedLocales = store.state.player.cachedPlayerLocales\n\n      if (!loadedLocales.has(shakaLocale)) {\n        if (!Object.hasOwn(cachedLocales, shakaLocale)) {\n          await store.dispatch('cachePlayerLocale', shakaLocale)\n        }\n\n        localization.insert(shakaLocale, new Map(Object.entries(cachedLocales[shakaLocale])))\n\n        loadedLocales.add(shakaLocale)\n      }\n\n      localization.changeLocale([shakaLocale])\n\n      // Add the keyboard shortcut to the label for the default Shaka controls\n\n      const shakaControlKeysToShortcutLocalizations = new Map()\n      Object.entries(shakaControlKeysToShortcuts).forEach(([shakaControlKey, shortcut]) => {\n        const originalLocalization = localization.resolve(shakaControlKey)\n        if (originalLocalization === '') {\n          // e.g., A Shaka localization key in shakaControlKeysToShortcuts has fallen out of date and need to be updated\n          console.error('Mising Shaka localization key \"%s\"', shakaControlKey)\n          return\n        }\n\n        const localizationWithShortcut = addKeyboardShortcutToActionTitle(\n          originalLocalization,\n          shortcut\n        )\n\n        shakaControlKeysToShortcutLocalizations.set(shakaControlKey, localizationWithShortcut)\n      })\n\n      localization.insert(shakaLocale, shakaControlKeysToShortcutLocalizations)\n\n      events.dispatchEvent(new CustomEvent('localeChanged'))\n    }\n\n    watch(locale, setLocale)\n\n    // #endregion player locales\n\n    // #region power save blocker\n\n    function startPowerSaveBlocker() {\n      if (process.env.IS_ELECTRON) {\n        window.ftElectron.startPowerSaveBlocker()\n      }\n    }\n\n    function stopPowerSaveBlocker() {\n      if (process.env.IS_ELECTRON) {\n        window.ftElectron.stopPowerSaveBlocker()\n      }\n    }\n\n    // #endregion power save blocker\n\n    // #region video event handlers\n\n    function handlePlay() {\n      startPowerSaveBlocker()\n\n      if ('mediaSession' in navigator) {\n        navigator.mediaSession.playbackState = 'playing'\n      }\n    }\n\n    function handlePause() {\n      stopPowerSaveBlocker()\n\n      if ('mediaSession' in navigator) {\n        navigator.mediaSession.playbackState = 'paused'\n      }\n    }\n\n    function handleEnded() {\n      stopPowerSaveBlocker()\n\n      if ('mediaSession' in navigator) {\n        navigator.mediaSession.playbackState = 'none'\n      }\n\n      emit('ended')\n    }\n\n    function handleCanPlay() {\n      // PiP can only be activated once the video's readState and video track are populated\n      if (startInPip && props.format !== 'audio' && ui.getControls().isPiPAllowed() && process.env.IS_ELECTRON) {\n        startInPip = false\n        window.ftElectron.requestPiP()\n      }\n    }\n\n    function updateVolume() {\n      const video_ = video.value\n      // https://docs.videojs.com/html5#volume\n      if (sessionStorage.getItem('muted') === 'false' && video_.volume === 0) {\n        // If video is muted by dragging volume slider, it doesn't change 'muted' in sessionStorage to true\n        // hence compare it with 'false' and set volume to defaultVolume.\n        const volume = parseFloat(sessionStorage.getItem('defaultVolume'))\n        const muted = true\n        sessionStorage.setItem('volume', volume.toString())\n        sessionStorage.setItem('muted', String(muted))\n      } else {\n        // If volume isn't muted by dragging the slider, muted and volume values are carried over to next video.\n        const volume = video_.volume\n        const muted = video_.muted\n        sessionStorage.setItem('volume', volume.toString())\n        sessionStorage.setItem('muted', String(muted))\n      }\n\n      if (showStats.value) {\n        stats.volume = (video_.volume * 100).toFixed(1)\n      }\n    }\n\n    function handleTimeupdate() {\n      if (video.value) {\n        const currentTime = video.value.currentTime\n\n        emit('timeupdate', currentTime)\n\n        if (showStats.value && hasLoaded.value) {\n          updateStats()\n        }\n\n        if (useSponsorBlock.value && sponsorBlockSegments.length > 0 && canSeek()) {\n          skipSponsorBlockSegments(currentTime)\n        }\n      }\n    }\n\n    const videoElementWidth = ref(0)\n    const videoElementHeight = ref(0)\n\n    /** @type {ResizeObserver} */\n    const videoResizeObserver = new ResizeObserver(() => {\n      if (video.value) {\n        const devicePixelRatio = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1\n        const video_ = video.value\n\n        videoElementWidth.value = video_.clientWidth * devicePixelRatio\n        videoElementHeight.value = video_.clientHeight * devicePixelRatio\n      }\n    })\n\n    /** @type {PictureInPictureWindow | null} */\n    let pipWindow = null\n    const pipWindowWidth = ref(null)\n    const pipWindowHeight = ref(null)\n\n    /**\n     * @param {PictureInPictureEvent} event\n     */\n    function handleEnterPictureInPicture(event) {\n      pipWindow = event.pictureInPictureWindow\n      handlePictureInPictureResize()\n      pipWindow.addEventListener('resize', handlePictureInPictureResize)\n    }\n\n    function handleLeavePictureInPicture() {\n      pipWindow.removeEventListener('resize', handlePictureInPictureResize)\n\n      pipWindow = null\n      pipWindowWidth.value = null\n      pipWindowHeight.value = null\n    }\n\n    function handlePictureInPictureResize() {\n      const devicePixelRatio = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1\n\n      pipWindowWidth.value = pipWindow.width * devicePixelRatio\n      pipWindowHeight.value = pipWindow.height * devicePixelRatio\n    }\n\n    const playerWidth = computed(() => Math.round(pipWindowWidth.value ?? videoElementWidth.value))\n    const playerHeight = computed(() => Math.round(pipWindowHeight.value ?? videoElementHeight.value))\n\n    // #endregion video event handlers\n\n    // #region SABR\n\n    /** @type {shaka.extern.Manifest | undefined} */\n    let sabrManifest\n\n    /** @type {import('../../helpers/player/SabrSchemePlugin').SabrStream | undefined} */\n    let sabrStream\n    /** @type {AbortController | undefined} */\n    let sabrAbortController\n\n    if (process.env.SUPPORTS_LOCAL_API && props.sabrData) {\n      sabrStream = /** @__NOINLINE__ */ setupSabrScheme(props.sabrData, () => player, () => sabrManifest, playerWidth, playerHeight)\n      sabrAbortController = new AbortController()\n      // Since there can be 2 requests at the same time (video + audio), we debounce the listener to only show the message once\n      sabrStream.onBackoffRequested(debounce(({ backoffMs }) => {\n        showToast(\n          ({ remainingMs }) => {\n            // `+value` converts string back to float\n            return t('Video.Watch.Remaining SABR backoff time: {remindingTimeSeconds}s', { remindingTimeSeconds: +(remainingMs / 1000).toFixed(1) })\n          },\n          // So that we don't see last countdown text like 0/N\n          backoffMs,\n          null,\n          sabrAbortController.signal,\n        )\n      }, 1000))\n      sabrStream.onReloadOnce(() => {\n        sabrAbortController.abort()\n        emit('player-reload-requested')\n      })\n    }\n\n    // #endregion SABR\n\n    // #region request/response filters\n\n    /** @type {shaka.extern.RequestFilter} */\n    function requestFilter(type, request, _context) {\n      if (type === RequestType.SEGMENT) {\n        const url = new URL(request.uris[0])\n\n        // only when we aren't proxying through Invidious,\n        // it doesn't like the range param and makes get requests to youtube anyway\n        if (url.protocol !== 'sabr:' && url.hostname.endsWith('.googlevideo.com') && url.pathname === '/videoplayback') {\n          request.method = 'POST'\n          request.body = new Uint8Array([0x78, 0]) // protobuf: { 15: 0 } (no idea what it means but this is what YouTube uses)\n\n          if (request.headers.Range) {\n            request.uris[0] += `&range=${request.headers.Range.split('=')[1]}`\n            delete request.headers.Range\n          }\n\n          request.uris[0] += '&alr=yes'\n        }\n      }\n    }\n\n    /** @type {shaka.extern.ResponseFilter} */\n    async function responseFilter(type, response, context) {\n      if (type === RequestType.SEGMENT) {\n        const url = new URL(response.uri)\n\n        if (url.protocol === 'sabr:') {\n          return\n        }\n\n        if (response.data && response.data.byteLength > 4 &&\n          new DataView(response.data).getUint32(0) === HTTP_IN_HEX) {\n          // Interpret the response data as a URL string.\n          const responseAsString = shaka.util.StringUtils.fromUTF8(response.data)\n\n          const retryParameters = player.getConfiguration().streaming.retryParameters\n\n          // Make another request for the redirect URL.\n          const uris = [responseAsString]\n          const redirectRequest = shaka.net.NetworkingEngine.makeRequest(uris, retryParameters)\n          const requestOperation = player.getNetworkingEngine().request(type, redirectRequest, context)\n          const redirectResponse = await requestOperation.promise\n\n          // Modify the original response to contain the results of the redirect\n          // response.\n          response.data = redirectResponse.data\n          response.headers = redirectResponse.headers\n          response.uri = redirectResponse.uri\n        } else {\n          // Fix positioning for auto-generated subtitles\n          if (url.hostname.endsWith('.youtube.com') && url.pathname === '/api/timedtext' &&\n            url.searchParams.get('caps') === 'asr' && url.searchParams.get('kind') === 'asr' && url.searchParams.get('fmt') === 'vtt') {\n            const stringBody = new TextDecoder().decode(response.data)\n            // position:0% for LTR text and position:100% for RTL text\n            const cleaned = stringBody.replaceAll(/ align:start position:(?:10)?0%$/gm, '')\n\n            response.data = new TextEncoder().encode(cleaned).buffer\n          }\n        }\n      } else if (type === RequestType.MANIFEST && context.type === AdvancedRequestType.MEDIA_PLAYLIST) {\n        const url = new URL(response.uri)\n\n        let modifiedText\n\n        // Fixes proxied HLS manifests, as Invidious replaces the path parameters with query parameters,\n        // so shaka-player isn't able to infer the mime type from the `/file/seg.ts` part like it does for non-proxied HLS manifests.\n        // Shaka-player does attempt to detect it with HEAD request but the `Content-Type` header is `application/octet-stream`,\n        // which still doesn't tell shaka-player how to handle the stream because that's the equivalent of saying \"binary data\".\n        if (url.searchParams.has('local')) {\n          const stringBody = new TextDecoder().decode(response.data)\n\n          modifiedText = stringBody.replaceAll(/https?:\\/\\/.+$/gm, hlsProxiedUrlReplacer)\n        }\n\n        // The audio-only streams are actually raw AAC, so correct the file extension from `.ts` to `.aac`\n        if (/\\/itag\\/23[34]\\//.test(url.pathname) || url.searchParams.get('itag') === '233' || url.searchParams.get('itag') === '234') {\n          if (!modifiedText) {\n            modifiedText = new TextDecoder().decode(response.data)\n          }\n\n          modifiedText = modifiedText.replaceAll('/file/seg.ts', '/file/seg.aac')\n        }\n\n        if (modifiedText) {\n          response.data = new TextEncoder().encode(modifiedText).buffer\n        }\n      }\n    }\n\n    /**\n     * @param {string} match\n     */\n    function hlsProxiedUrlReplacer(match) {\n      const url = new URL(match)\n\n      let fileValue\n      for (const [key, value] of url.searchParams) {\n        if (key === 'file') {\n          fileValue = value\n          continue\n        } else if (key === 'hls_chunk_host') {\n          // Add the host parameter so some Invidious instances stop complaining about the missing host parameter\n          // Replace .c.youtube.com with .googlevideo.com as the built-in Invidious video proxy only accepts host parameters with googlevideo.com\n          url.pathname += `/host/${encodeURIComponent(value.replace('.c.youtube.com', '.googlevideo.com'))}`\n        }\n\n        url.pathname += `/${key}/${encodeURIComponent(value)}`\n      }\n\n      // This has to be right at the end so that shaka-player can read the file extension\n      url.pathname += `/file/${encodeURIComponent(fileValue)}`\n\n      url.search = ''\n      return url.toString()\n    }\n\n    // #endregion request/response filters\n\n    // #region set quality\n\n    /**\n     * @param {number} quality\n     * @param {number | undefined} audioBandwidth\n     * @param {string | undefined} label\n     */\n    function setDashQuality(quality, audioBandwidth, label) {\n      let variants = player.getVariantTracks()\n\n      if (label) {\n        variants = variants.filter(variant => variant.label === label)\n      } else if (hasMultipleAudioTracks.value) {\n        // default audio track\n        const filteredVariants = variants.filter(variant => variant.audioRoles.includes('main'))\n        // Sometimes there is nothing marked as main, don't filter in this case\n        if (filteredVariants.length > 0) {\n          variants = filteredVariants\n        }\n      }\n\n      const isPortrait = variants[0].height > variants[0].width\n\n      let matches = variants.filter(variant => {\n        return quality === (isPortrait ? variant.width : variant.height)\n      })\n\n      if (matches.length === 0) {\n        matches = variants.filter(variant => {\n          return quality > (isPortrait ? variant.width : variant.height)\n        })\n      }\n\n      matches.sort((a, b) => isPortrait ? b.width - a.width : b.height - a.height)\n\n      let chosenVariant\n\n      if (typeof audioBandwidth === 'number') {\n        const width = matches[0].width\n        const height = matches[0].height\n\n        matches = matches.filter(variant => variant.width === width && variant.height === height)\n\n        chosenVariant = findMostSimilarAudioBandwidth(matches, audioBandwidth)\n      } else {\n        chosenVariant = matches[0]\n      }\n\n      player.selectVariantTrack(chosenVariant)\n    }\n\n    /**\n     * @param {number|null} playbackPosition\n     * @param {number|undefined} previousQuality\n     */\n    async function setLegacyQuality(playbackPosition = null, previousQuality = undefined) {\n      if (typeof previousQuality === 'undefined') {\n        if (defaultQuality.value === 'auto') {\n          previousQuality = Infinity\n        } else {\n          previousQuality = defaultQuality.value\n        }\n      }\n\n      /** @type {object[]} */\n      const legacyFormats = props.legacyFormats\n\n      const isPortrait = legacyFormats[0].height > legacyFormats[0].width\n\n      let matches = legacyFormats.filter(variant => {\n        return previousQuality === isPortrait ? variant.width : variant.height\n      })\n\n      if (matches.length === 0) {\n        matches = legacyFormats.filter(variant => {\n          return previousQuality > isPortrait ? variant.width : variant.height\n        })\n\n        if (matches.length > 0) {\n          matches.sort((a, b) => b.bitrate - a.bitrate)\n        } else {\n          matches = legacyFormats.sort((a, b) => a.bitrate - b.bitrate)\n        }\n      }\n\n      hasMultipleAudioTracks.value = false\n\n      events.dispatchEvent(new CustomEvent('setLegacyFormat', {\n        detail: {\n          format: matches[0],\n          playbackPosition\n        }\n      }))\n    }\n\n    // #endregion set quality\n\n    // #region stats\n\n    function gatherInitialStatsValues() {\n      /** @type {HTMLVideoElement} */\n      const video_ = video.value\n\n      stats.volume = (video_.volume * 100).toFixed(1)\n\n      if (props.format === 'legacy') {\n        updateLegacyQualityStats(activeLegacyFormat.value)\n      }\n\n      if (!hasLoaded.value) {\n        player.addEventListener('loaded', () => {\n          if (showStats.value) {\n            if (props.format !== 'legacy') {\n              updateQualityStats({\n                newTrack: player.getVariantTracks().find(track => track.active)\n              })\n            }\n\n            updateStats()\n          }\n        }, {\n          once: true\n        })\n\n        return\n      }\n\n      if (props.format !== 'legacy') {\n        updateQualityStats({\n          newTrack: player.getVariantTracks().find(track => track.active)\n        })\n      }\n\n      updateStats()\n    }\n\n    /**\n     * @param {{\n     *   type: ('adaptation'|'variantchanged'),\n     *   newTrack: shaka.extern.Track,\n     *   oldTrack: shaka.extern.Track\n     * }} track\n     */\n    function updateQualityStats({ newTrack }) {\n      if (!showStats.value || props.format === 'legacy') {\n        return\n      }\n\n      stats.bitrate = (newTrack.bandwidth / 1000).toFixed(2)\n\n      // Combined audio and video HLS streams\n      if (newTrack.videoCodec?.includes(',')) {\n        stats.codecs.audioItag = ''\n        stats.codecs.videoItag = ''\n\n        const [audioCodec, videoCodec] = newTrack.videoCodec.split(',')\n\n        stats.codecs.audioCodec = audioCodec\n        stats.codecs.videoCodec = videoCodec\n\n        stats.resolution.frameRate = newTrack.frameRate\n        stats.resolution.width = newTrack.width\n        stats.resolution.height = newTrack.height\n      } else {\n        stats.codecs.audioItag = newTrack.originalAudioId.split('-', 1)[0]\n        stats.codecs.audioCodec = newTrack.audioCodec\n\n        if (props.format === 'dash') {\n          stats.resolution.frameRate = newTrack.frameRate\n\n          stats.codecs.videoItag = newTrack.originalVideoId.split('-', 1)[0]\n          stats.codecs.videoCodec = newTrack.videoCodec\n\n          stats.resolution.width = newTrack.width\n          stats.resolution.height = newTrack.height\n        }\n      }\n    }\n\n    function updateLegacyQualityStats(newFormat) {\n      if (!showStats.value || props.format !== 'legacy') {\n        return\n      }\n\n      const { fps, bitrate, mimeType, itag, width, height } = newFormat\n\n      const codecsMatch = mimeType.match(/codecs=\"(?<videoCodec>.+), ?(?<audioCodec>.+)\"/)\n\n      stats.codecs.audioItag = itag\n      stats.codecs.audioCodec = codecsMatch.groups.audioCodec\n\n      stats.codecs.videoItag = itag\n      stats.codecs.videoCodec = codecsMatch.groups.videoCodec\n\n      stats.resolution.frameRate = fps\n\n      stats.bitrate = (bitrate / 1000).toFixed(2)\n\n      stats.resolution.width = width\n      stats.resolution.height = height\n    }\n\n    function updateStats() {\n      const playerStats = player.getStats()\n\n      if (props.format !== 'audio') {\n        stats.frames = {\n          droppedFrames: playerStats.droppedFrames,\n          totalFrames: playerStats.decodedFrames\n        }\n      }\n\n      if (props.format !== 'legacy') {\n        // estimated bandwidth is NaN for legacy, as none of the requests go through shaka,\n        // so it has no way to estimate the bandwidth\n        stats.bandwidth = (playerStats.estimatedBandwidth / 1000).toFixed(2)\n      }\n\n      let bufferedSeconds = 0\n\n      const buffered = player.getBufferedInfo().total\n\n      for (const { start, end } of buffered) {\n        bufferedSeconds += end - start\n      }\n\n      const seekRange = player.seekRange()\n      const duration = seekRange.end - seekRange.start\n\n      stats.buffered = ((bufferedSeconds / duration) * 100).toFixed(2)\n    }\n\n    watch(showStats, (newValue) => {\n      if (newValue) {\n        // for abr changes/auto quality\n        player.addEventListener('adaptation', updateQualityStats)\n\n        // for manual changes e.g. in quality selector\n        player.addEventListener('variantchanged', updateQualityStats)\n      } else {\n        // for abr changes/auto quality\n        player.removeEventListener('adaptation', updateQualityStats)\n\n        // for manual changes e.g. in quality selector\n        player.removeEventListener('variantchanged', updateQualityStats)\n      }\n    })\n\n    watch(activeLegacyFormat, updateLegacyQualityStats)\n\n    // #endregion stats\n\n    // #region screenshots\n\n    async function takeScreenshot() {\n      const video_ = video.value\n\n      const width = video_.videoWidth\n      const height = video_.videoHeight\n\n      if (width <= 0) {\n        return\n      }\n\n      // Need to set crossorigin=\"anonymous\" for LegacyFormat on Invidious\n      // https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image\n      const canvas = document.createElement('canvas')\n      canvas.width = width\n      canvas.height = height\n      canvas.getContext('2d').drawImage(video_, 0, 0)\n\n      const format = screenshotFormat.value\n      const mimeType = `image/${format === 'jpg' ? 'jpeg' : format}`\n      // imageQuality is ignored for pngs, so it is still okay to pass the quality value\n      const imageQuality = screenshotQuality.value / 100\n\n      let filename\n      try {\n        filename = await store.dispatch('parseScreenshotCustomFileName', {\n          date: new Date(),\n          playerTime: video_.currentTime,\n          videoId: props.videoId\n        })\n      } catch (err) {\n        console.error(`Parse failed: ${err.message}`)\n        showToast(t('Screenshot Error', { error: err.message }))\n        canvas.remove()\n        return\n      }\n\n      const filenameWithExtension = `${filename}.${format}`\n\n      const wasPlaying = !video_.paused\n      if ((!process.env.IS_ELECTRON || screenshotAskPath.value) && wasPlaying) {\n        video_.pause()\n      }\n\n      try {\n        /** @type {Blob} */\n        const blob = await new Promise((resolve) => canvas.toBlob(resolve, mimeType, imageQuality))\n\n        if (!process.env.IS_ELECTRON || screenshotAskPath.value) {\n          const saved = await writeFileWithPicker(\n            filenameWithExtension,\n            blob,\n            format.toUpperCase(),\n            mimeType,\n            `.${format}`,\n            'player-screenshots',\n            'pictures'\n          )\n\n          if (saved) {\n            showToast(t('Screenshot Success'))\n          }\n        } else {\n          const arrayBuffer = await blob.arrayBuffer()\n\n          if (await window.ftElectron.writeToDefaultFolder(filenameWithExtension, arrayBuffer)) {\n            showToast(t('Screenshot Success'))\n          }\n        }\n      } catch (error) {\n        console.error(error)\n        showToast(t('Screenshot Error', { error }))\n      } finally {\n        canvas.remove()\n\n        if ((!process.env.IS_ELECTRON || screenshotAskPath.value) && wasPlaying) {\n          video_.play()\n        }\n      }\n    }\n\n    // #endregion screenshots\n\n    // #region custom player controls\n\n    const { ContextMenu: shakaContextMenu, Controls: shakaControls, OverflowMenu: shakaOverflowMenu } = shaka.ui\n\n    function registerAudioTrackSelection() {\n      /** @implements {shaka.extern.IUIElement.Factory} */\n      class AudioTrackSelectionFactory {\n        create(rootElement, controls) {\n          return new AudioTrackSelection(events, rootElement, controls)\n        }\n      }\n\n      shakaControls.registerElement('ft_audio_tracks', new AudioTrackSelectionFactory())\n      shakaOverflowMenu.registerElement('ft_audio_tracks', new AudioTrackSelectionFactory())\n    }\n\n    function registerAutoplayToggle() {\n      events.addEventListener('toggleAutoplay', () => {\n        emit('toggle-autoplay')\n      })\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class AutoplayToggleFactory {\n        create(rootElement, controls) {\n          return new AutoplayToggle(props.autoplayEnabled, events, rootElement, controls)\n        }\n      }\n\n      shakaControls.registerElement('ft_autoplay_toggle', new AutoplayToggleFactory())\n      shakaOverflowMenu.registerElement('ft_autoplay_toggle', new AutoplayToggleFactory())\n    }\n\n    function registerTheatreModeButton() {\n      events.addEventListener('toggleTheatreMode', () => {\n        emit('toggle-theatre-mode')\n      })\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class TheatreModeButtonFactory {\n        create(rootElement, controls) {\n          return new TheatreModeButton(props.useTheatreMode, events, rootElement, controls)\n        }\n      }\n\n      shakaControls.registerElement('ft_theatre_mode', new TheatreModeButtonFactory())\n      shakaOverflowMenu.registerElement('ft_theatre_mode', new TheatreModeButtonFactory())\n    }\n\n    function registerFullWindowButton() {\n      events.addEventListener('setFullWindow', (/** @type {CustomEvent} */ event) => {\n        if (event.detail) {\n          window.scrollTo({ top: 0, left: 0, behavior: 'instant' })\n        }\n\n        fullWindowEnabled.value = event.detail\n\n        if (fullWindowEnabled.value) {\n          document.body.classList.add('playerFullWindow')\n        } else {\n          document.body.classList.remove('playerFullWindow')\n        }\n      })\n\n      if (startInFullwindow) {\n        events.dispatchEvent(new CustomEvent('setFullWindow', {\n          detail: true\n        }))\n      }\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class FullWindowButtonFactory {\n        create(rootElement, controls) {\n          return new FullWindowButton(fullWindowEnabled.value, events, rootElement, controls)\n        }\n      }\n\n      shakaControls.registerElement('ft_full_window', new FullWindowButtonFactory())\n      shakaOverflowMenu.registerElement('ft_full_window', new FullWindowButtonFactory())\n    }\n\n    function registerLegacyQualitySelection() {\n      events.addEventListener('setLegacyFormat', async (/** @type {CustomEvent} */ event) => {\n        const { format, playbackPosition, restoreCaptionIndex: restoreCaptionIndex_ = null } = event.detail\n\n        if (restoreCaptionIndex_ !== null) {\n          restoreCaptionIndex = restoreCaptionIndex_\n        }\n\n        activeLegacyFormat.value = event.detail.format\n        try {\n          await player.load(format.url, playbackPosition, format.mimeType)\n        } catch (error) {\n          handleError(error, 'setLegacyFormat', event.detail)\n        }\n      })\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class LegacyQualitySelectionFactory {\n        create(rootElement, controls) {\n          return new LegacyQualitySelection(\n            activeLegacyFormat.value,\n            props.legacyFormats,\n            events,\n            rootElement,\n            controls\n          )\n        }\n      }\n\n      shakaControls.registerElement('ft_legacy_quality', new LegacyQualitySelectionFactory())\n      shakaOverflowMenu.registerElement('ft_legacy_quality', new LegacyQualitySelectionFactory())\n    }\n\n    function registerStatsButton() {\n      events.addEventListener('setStatsVisibility', (/** @type {CustomEvent} */ event) => {\n        showStats.value = event.detail\n\n        if (showStats.value) {\n          gatherInitialStatsValues()\n        }\n      })\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class StatsButtonFactory {\n        create(rootElement, controls) {\n          return new StatsButton(showStats.value, events, rootElement, controls)\n        }\n      }\n\n      shakaContextMenu.registerElement('ft_stats', new StatsButtonFactory())\n    }\n\n    function registerScreenshotButton() {\n      events.addEventListener('takeScreenshot', () => {\n        takeScreenshot()\n      })\n\n      /**\n       * @implements {shaka.extern.IUIElement.Factory}\n       */\n      class ScreenshotButtonFactory {\n        create(rootElement, controls) {\n          return new ScreenshotButton(events, rootElement, controls)\n        }\n      }\n\n      shakaControls.registerElement('ft_screenshot', new ScreenshotButtonFactory())\n      shakaOverflowMenu.registerElement('ft_screenshot', new ScreenshotButtonFactory())\n    }\n\n    function registerSkipButtons() {\n      // skip to next video button\n      events.addEventListener('nextVideo', () => {\n        emit('skip-to-next')\n      })\n\n      class SkipNextButtonFactory {\n        create(rootElement, controls) {\n          return new SkipButton(events, rootElement, controls, 'next')\n        }\n      }\n\n      shakaControls.registerElement('ft_skip_next', new SkipNextButtonFactory())\n      shakaOverflowMenu.registerElement('ft_skip_next', new SkipNextButtonFactory())\n\n      // skip to previous video button\n      events.addEventListener('previousVideo', () => {\n        emit('skip-to-prev')\n      })\n\n      class SkipPreviousButtonFactory {\n        create(rootElement, controls) {\n          return new SkipButton(events, rootElement, controls, 'previous')\n        }\n      }\n\n      shakaControls.registerElement('ft_skip_previous', new SkipPreviousButtonFactory())\n      shakaOverflowMenu.registerElement('ft_skip_previous', new SkipPreviousButtonFactory())\n    }\n\n    /**\n     * As shaka-player doesn't let you unregister custom control factories,\n     * overwrite them with `null` instead so the referenced objects\n     * (e.g. {@linkcode events}, {@linkcode fullWindowEnabled}) can get garbage collected\n     */\n    function cleanUpCustomPlayerControls() {\n      shakaControls.registerElement('ft_audio_tracks', null)\n      shakaOverflowMenu.registerElement('ft_audio_tracks', null)\n\n      shakaControls.registerElement('ft_autoplay_toggle', null)\n      shakaOverflowMenu.registerElement('ft_autoplay_toggle', null)\n\n      shakaControls.registerElement('ft_theatre_mode', null)\n      shakaOverflowMenu.registerElement('ft_theatre_mode', null)\n\n      shakaControls.registerElement('ft_full_window', null)\n      shakaOverflowMenu.registerElement('ft_full_window', null)\n\n      shakaControls.registerElement('ft_legacy_quality', null)\n      shakaOverflowMenu.registerElement('ft_legacy_quality', null)\n\n      shakaContextMenu.registerElement('ft_stats', null)\n\n      shakaControls.registerElement('ft_screenshot', null)\n      shakaOverflowMenu.registerElement('ft_screenshot', null)\n\n      shakaControls.registerElement('ft_next_previous', null)\n      shakaOverflowMenu.registerElement('ft_next_previous', null)\n\n      shakaControls.registerElement('ft_skip_previous', null)\n      shakaOverflowMenu.registerElement('ft_skip_previous', null)\n    }\n\n    // #endregion custom player controls\n\n    // #region mouse and keyboard helpers\n\n    /**\n     * @param {number} step\n     */\n    function changeVolume(step) {\n      const volumeBar = container.value.querySelector('.shaka-volume-bar')\n\n      const oldValue = parseFloat(volumeBar.value)\n      const newValue = oldValue + (step * 100)\n\n      if (newValue < 0) {\n        volumeBar.value = 0\n      } else if (newValue > 100) {\n        volumeBar.value = 100\n      } else {\n        volumeBar.value = newValue\n      }\n\n      volumeBar.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }))\n\n      let messageIcon\n      if (newValue <= 0) {\n        messageIcon = 'volume-mute'\n      } else if (newValue > 0 && newValue < oldValue) {\n        messageIcon = 'volume-low'\n      } else if (newValue > 0 && newValue > oldValue) {\n        messageIcon = 'volume-high'\n      }\n      showValueChange(`${Math.round(video.value.volume * 100)}%`, messageIcon)\n    }\n\n    /**\n     * @param {number} step\n     */\n    function changePlayBackRate(step) {\n      const newPlaybackRateString = (player.getPlaybackRate() + step).toFixed(2)\n      const newPlaybackRate = parseFloat(newPlaybackRateString)\n\n      // The following error is thrown if you go below 0.07:\n      // The provided playback rate (0.05) is not in the supported playback range.\n      if (newPlaybackRate > 0.07 && newPlaybackRate <= maxVideoPlaybackRate.value) {\n        if (newPlaybackRate === defaultPlaybackRate.value) {\n          player.cancelTrickPlay()\n        } else {\n          player.trickPlay(newPlaybackRate, false)\n        }\n\n        showValueChange(`${newPlaybackRateString}x`)\n      }\n    }\n\n    function canSeek() {\n      if (!player || !hasLoaded.value) {\n        return false\n      }\n\n      const seekRange = player.seekRange()\n\n      // Seeking not possible e.g. with HLS\n      if (seekRange.start === seekRange.end || !seekingIsPossible.value) {\n        return false\n      }\n\n      return true\n    }\n\n    /**\n     * @param {number} seconds The number of seconds to seek by, positive values seek forwards, negative ones seek backwards\n     * @param {boolean} canSeekResult Allow functions that have already checked whether seeking is possible, to skip the extra check (e.g. frameByFrame)\n     * @param {boolean} showPopUp Whether to show a pop-up with the seconds seeked\n     */\n    function seekBySeconds(seconds, canSeekResult = false, showPopUp = false) {\n      if (!(canSeekResult || canSeek())) {\n        return\n      }\n\n      const seekRange = player.seekRange()\n\n      const video_ = video.value\n\n      const currentTime = video_.currentTime\n      const newTime = currentTime + seconds\n\n      if (newTime < seekRange.start) {\n        video_.currentTime = seekRange.start\n      } else if (newTime > seekRange.end) {\n        if (isLive.value) {\n          player.goToLive()\n        } else {\n          video_.currentTime = seekRange.end\n        }\n      } else {\n        video_.currentTime = newTime\n      }\n      if (showPopUp) {\n        const popUpLayout = seconds > 0\n          ? { icon: 'arrow-right', invertContentOrder: true }\n          : { icon: 'arrow-left', invertContentOrder: false }\n        // `+value` converts string back to float\n        const formattedSeconds = +Math.abs(seconds).toFixed(2)\n        showValueChange(`${formattedSeconds}s`, popUpLayout.icon, popUpLayout.invertContentOrder)\n      }\n\n      showOverlayControls()\n    }\n\n    // #endregion mouse and keyboard helpers\n\n    // #region mouse scroll handlers\n\n    const mouseScrollThrottleWaitMs = 200\n\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollPlaybackRate(event) {\n      if ((event.deltaY < 0 || event.deltaX > 0)) {\n        changePlayBackRate(0.05)\n      } else if ((event.deltaY > 0 || event.deltaX < 0)) {\n        changePlayBackRate(-0.05)\n      }\n    }\n    const mouseScrollPlaybackRateThrottle = throttle(mouseScrollPlaybackRate, mouseScrollThrottleWaitMs)\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollPlaybackRateHandler(event) {\n      event.preventDefault()\n\n      // Touchpad scroll = small deltaX/deltaY\n      if (Math.abs(event.deltaX) <= 5 && Math.abs(event.deltaY) <= 5) {\n        mouseScrollPlaybackRateThrottle(event)\n      } else {\n        mouseScrollPlaybackRate(event)\n      }\n    }\n\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollSkip(event) {\n      if ((event.deltaY < 0 || event.deltaX > 0)) {\n        seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), true)\n      } else if ((event.deltaY > 0 || event.deltaX < 0)) {\n        seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), true)\n      }\n    }\n    const mouseScrollSkipThrottle = throttle(mouseScrollSkip, mouseScrollThrottleWaitMs)\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollSkipHandler(event) {\n      if (canSeek()) {\n        event.preventDefault()\n\n        // Touchpad scroll = small deltaX/deltaY\n        if (Math.abs(event.deltaX) <= 5 && Math.abs(event.deltaY) <= 5) {\n          mouseScrollSkipThrottle(event)\n        } else {\n          mouseScrollSkip(event)\n        }\n      }\n    }\n\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollVolume(event) {\n      const video_ = video.value\n\n      if (video_.muted && (event.deltaY < 0 || event.deltaX > 0)) {\n        video_.muted = false\n        video_.volume = 0\n      }\n\n      if (!video_.muted) {\n        if ((event.deltaY < 0 || event.deltaX > 0)) {\n          changeVolume(0.05)\n        } else if ((event.deltaY > 0 || event.deltaX < 0)) {\n          changeVolume(-0.05)\n        }\n      }\n    }\n    const mouseScrollVolumeThrottle = throttle(mouseScrollVolume, mouseScrollThrottleWaitMs)\n    /**\n     * @param {WheelEvent} event\n     */\n    function mouseScrollVolumeHandler(event) {\n      if (!event.ctrlKey && !event.metaKey) {\n        event.preventDefault()\n        event.stopPropagation()\n\n        // Touchpad scroll = small deltaX/deltaY\n        if (Math.abs(event.deltaX) <= 5 && Math.abs(event.deltaY) <= 5) {\n          mouseScrollVolumeThrottle(event)\n        } else {\n          mouseScrollVolume(event)\n        }\n      }\n    }\n\n    // #endregion mouse scroll handlers\n\n    // #region keyboard shortcuts\n\n    /**\n     * determines whether the jump to the previous or next chapter\n     * with the the keyboard shortcuts, should be done\n     * first it checks whether there are any chapters (the array is also empty if chapters are hidden)\n     * it also checks that the approprate combination was used ALT/OPTION on macOS and CTRL everywhere else\n     * @param {KeyboardEvent} event the keyboard event\n     * @param {string} direction the direction of the jump either previous or next\n     */\n    function canChapterJump(event, direction) {\n      const currentChapter = props.currentChapterIndex\n      return props.chapters.length > 0 &&\n        (direction === 'previous' ? currentChapter > 0 : props.chapters.length - 1 !== currentChapter) &&\n        ((process.platform !== 'darwin' && event.ctrlKey) ||\n          (process.platform === 'darwin' && event.metaKey))\n    }\n\n    /**\n     * @param {number} step\n     */\n    function frameByFrame(step) {\n      if (props.format === 'audio' || !canSeek()) {\n        return\n      }\n\n      video.value.pause()\n\n      /** @type {number} */\n      let fps\n      if (props.format === 'legacy') {\n        fps = activeLegacyFormat.value.fps\n      } else {\n        fps = player.getVariantTracks().find(track => track.active).frameRate\n      }\n\n      const frameTime = 1 / fps\n      const dist = frameTime * step\n      seekBySeconds(dist, true)\n    }\n\n    /**\n     * @param {KeyboardEvent} event\n     */\n    function keyboardShortcutHandler(event) {\n      if (!player || !hasLoaded.value) {\n        return\n      }\n\n      if (document.activeElement.classList.contains('ft-input') || event.altKey) {\n        return\n      }\n\n      // exit fullscreen and/or fullwindow if keyboard shortcut modal is opened\n      if (event.shiftKey && event.key === '?') {\n        event.preventDefault()\n\n        if (ui.getControls().isFullScreenEnabled()) {\n          ui.getControls().toggleFullScreen()\n        }\n\n        if (fullWindowEnabled.value) {\n          events.dispatchEvent(new CustomEvent('setFullWindow', {\n            detail: !fullWindowEnabled.value\n          }))\n        }\n\n        return\n      }\n\n      // allow chapter jump keyboard shortcuts\n      if (event.ctrlKey && (process.platform === 'darwin' || (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight'))) {\n        return\n      }\n\n      // allow copying text\n      if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'c') {\n        return\n      }\n\n      const video_ = video.value\n\n      // Skip to next video in playlist or recommended\n      if (event.shiftKey && event.key.toLowerCase() === 'n') {\n        emit('skip-to-next')\n        return\n      }\n\n      // Skip to previous video in playlist\n      if (event.shiftKey && event.key.toLowerCase() === 'p') {\n        emit('skip-to-prev')\n        return\n      }\n\n      switch (event.key.toLowerCase()) {\n        case ' ':\n        case 'spacebar': // older browsers might return spacebar instead of a space character\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.PLAY:\n          // Toggle Play/Pause\n          event.preventDefault()\n          video_.paused ? video_.play() : video_.pause()\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.LARGE_REWIND:\n          // Rewind by 2x the time-skip interval (in seconds)\n          event.preventDefault()\n          seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate() * 2, false, true)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.LARGE_FAST_FORWARD:\n          // Fast-Forward by 2x the time-skip interval (in seconds)\n          event.preventDefault()\n          seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate() * 2, false, true)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.DECREASE_VIDEO_SPEED:\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.DECREASE_VIDEO_SPEED_ALT:\n          // Decrease playback rate by user configured interval\n          event.preventDefault()\n          changePlayBackRate(-videoPlaybackRateInterval.value)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.INCREASE_VIDEO_SPEED:\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.INCREASE_VIDEO_SPEED_ALT:\n          // Increase playback rate by user configured interval\n          event.preventDefault()\n          changePlayBackRate(videoPlaybackRateInterval.value)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.FULLSCREEN:\n          // Toggle full screen\n          event.preventDefault()\n          ui.getControls().toggleFullScreen()\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.MUTE:\n          // Toggle mute only if metakey is not pressed\n          if (!event.metaKey) {\n            event.preventDefault()\n            const isMuted = !video_.muted\n            video_.muted = isMuted\n\n            const messageIcon = isMuted ? 'volume-mute' : 'volume-high'\n            const message = isMuted ? '0%' : `${Math.round(video_.volume * 100)}%`\n            showValueChange(message, messageIcon)\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.CAPTIONS: {\n          // Toggle caption/subtitles\n\n          const textTracks = player.getTextTracks()\n          if (textTracks.length > 0) {\n            event.preventDefault()\n\n            if (textTracks.some(track => track.active)) {\n              player.selectTextTrack(null)\n            } else {\n              player.selectTextTrack(textTracks[0])\n            }\n\n            showOverlayControls()\n          }\n          break\n        }\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.VOLUME_UP:\n          // Increase volume\n          event.preventDefault()\n          changeVolume(0.05)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.VOLUME_DOWN:\n          // Decrease Volume\n          event.preventDefault()\n          changeVolume(-0.05)\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_REWIND:\n          if (event.shiftKey) {\n            break\n          }\n          event.preventDefault()\n          if (canChapterJump(event, 'previous')) {\n            // Jump to the previous chapter\n            video_.currentTime = props.chapters[props.currentChapterIndex - 1].startSeconds\n            showOverlayControls()\n          } else {\n            // Rewind by the time-skip interval (in seconds)\n            seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), false, true)\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_FAST_FORWARD:\n          if (event.shiftKey) {\n            break\n          }\n          event.preventDefault()\n          if (canChapterJump(event, 'next')) {\n            // Jump to the next chapter\n            video_.currentTime = (props.chapters[props.currentChapterIndex + 1].startSeconds)\n            showOverlayControls()\n          } else {\n            // Fast-Forward by the time-skip interval (in seconds)\n            seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), false, true)\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE:\n          // Toggle picture in picture\n          if (props.format !== 'audio') {\n            const controls = ui.getControls()\n            if (controls.isPiPAllowed()) {\n              controls.togglePiP()\n            }\n          }\n          break\n        case '0':\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n        case '8':\n        case '9': {\n          // Jump to percentage in the video\n          if (canSeek()) {\n            event.preventDefault()\n\n            // use seek range instead of duration so that it works for live streams too\n            const seekRange = player.seekRange()\n\n            const length = seekRange.end - seekRange.start\n            const percentage = parseInt(event.key) / 10\n\n            video_.currentTime = seekRange.start + (length * percentage)\n            showOverlayControls()\n          }\n          break\n        }\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.LAST_FRAME:\n          // `⌘+,` is for settings in MacOS\n          if (!event.metaKey && video_.paused) {\n            event.preventDefault()\n            // Return to previous frame\n            frameByFrame(-1)\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.NEXT_FRAME:\n          if (video_.paused) {\n            event.preventDefault()\n            // Advance to next frame\n            frameByFrame(1)\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.STATS:\n          // Toggle stats display\n          event.preventDefault()\n\n          events.dispatchEvent(new CustomEvent('setStatsVisibility', {\n            detail: !showStats.value\n          }))\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.HOME:\n          // Jump to beginning of video\n          if (canSeek()) {\n            event.preventDefault()\n            // use seek range instead of duration so that it works for live streams too\n            const seekRange = player.seekRange()\n            video_.currentTime = seekRange.start\n            showOverlayControls()\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.END:\n          // Jump to end of video\n          if (canSeek()) {\n            event.preventDefault()\n            // use seek range instead of duration so that it works for live streams too\n            const seekRange = player.seekRange()\n            video_.currentTime = seekRange.end\n            showOverlayControls()\n          }\n          break\n        case 'escape':\n          // Exit full window\n          if (fullWindowEnabled.value) {\n            event.preventDefault()\n\n            events.dispatchEvent(new CustomEvent('setFullWindow', {\n              detail: false\n            }))\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.FULLWINDOW:\n          // Toggle full window mode\n          event.preventDefault()\n          events.dispatchEvent(new CustomEvent('setFullWindow', {\n            detail: !fullWindowEnabled.value\n          }))\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.THEATRE_MODE:\n          // Toggle theatre mode\n          if (props.theatrePossible) {\n            event.preventDefault()\n\n            events.dispatchEvent(new CustomEvent('toggleTheatreMode', {\n              detail: !props.useTheatreMode\n            }))\n          }\n          break\n        case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.TAKE_SCREENSHOT:\n          if (enableScreenshot.value && props.format !== 'audio') {\n            event.preventDefault()\n            // Take screenshot\n            takeScreenshot()\n          }\n          break\n      }\n    }\n\n    // #endregion keyboard shortcuts\n\n    let ignoreErrors = false\n\n    /**\n     * @param {shaka.util.Error} error\n     * @param {string} context\n     * @param {object?} details\n     */\n    function handleError(error, context, details) {\n      // These two errors are just wrappers around another error, so use the original error instead\n      // As they can be nested (e.g. multiple googlevideo redirects because the Invidious server was far away from the user) we should pick the inner most one\n      while (error.code === ErrorCode.REQUEST_FILTER_ERROR || error.code === ErrorCode.RESPONSE_FILTER_ERROR) {\n        error = error.data[0]\n      }\n\n      // Allow shaka-player to retry on potentially recoverable network errors\n      if (error.severity === ErrorSeverity.RECOVERABLE && error.category === ErrorCategory.NETWORK) {\n        /** @type {keyof ErrorCategory} */\n        const categoryText = Object.keys(ErrorCategory).find((/** @type {keyof ErrorCategory} */ key) => ErrorCategory[key] === error.category)\n\n        /** @type {keyof ErrorCode} */\n        const codeText = Object.keys(ErrorCode).find((/** @type {keyof ErrorCode} */ key) => ErrorCode[key] === error.code)\n\n        console.warn(\n          'Recoverable network error retrying...\\n' +\n          `Category: ${categoryText} (${error.category})\\n` +\n          `Code: ${codeText} (${error.code})\\n` +\n          'Data', error.data\n        )\n        return\n      }\n\n      logShakaError(error, context, props.videoId, details)\n\n      // text related errors aren't serious (captions and seek bar thumbnails), so we should just log them\n      // TODO: consider only emitting when the severity is crititcal?\n      if (\n        !ignoreErrors &&\n        error.category !== shaka.util.Error.Category.TEXT &&\n        !(error.code === shaka.util.Error.Code.BAD_HTTP_STATUS && error.data[0].startsWith('https://www.youtube.com/api/timedtext'))\n      ) {\n        // don't react to multiple consecutive errors, otherwise we don't give the format fallback from the previous error a chance to work\n        ignoreErrors = true\n\n        emit('error', error)\n\n        stopPowerSaveBlocker()\n\n        if ('mediaSession' in navigator) {\n          navigator.mediaSession.playbackState = 'none'\n        }\n      }\n    }\n\n    // #region seek bar markers\n\n    /**\n     * @param {number} duration As the sponsorblock segments can sometimes load before the video does, we need to pass in the duration here\n     */\n    function createSponsorBlockMarkers(duration) {\n      addMarkers(\n        sponsorBlockSegments.map(segment => {\n          const markerDiv = document.createElement('div')\n\n          markerDiv.title = translateSponsorBlockCategory(segment.category)\n          markerDiv.className = `sponsorBlockMarker main${sponsorSkips.value.categoryData[segment.category].color}`\n          markerDiv.style.width = `${((segment.endTime - segment.startTime) / duration) * 100}%`\n          markerDiv.style.left = `${(segment.startTime / duration) * 100}%`\n\n          return markerDiv\n        })\n      )\n    }\n\n    function createChapterMarkers() {\n      const { start, end } = player.seekRange()\n      const duration = end - start\n\n      /**\n       * @type {{\n       *   title: string,\n       *   timestamp: string,\n       *   startSeconds: number,\n       *   endSeconds: number,\n       *   thumbnail?: string\n       * }[]}\n       */\n      const chapters = props.chapters\n\n      addMarkers(\n        chapters.map(chapter => {\n          const markerDiv = document.createElement('div')\n\n          markerDiv.title = chapter.title\n          markerDiv.className = 'chapterMarker'\n          markerDiv.style.left = `calc(${(chapter.startSeconds / duration) * 100}% - 1px)`\n\n          return markerDiv\n        })\n      )\n    }\n\n    /**\n     * @param {HTMLDivElement[]} markers\n     */\n    function addMarkers(markers) {\n      const seekBarContainer = container.value.querySelector('.shaka-seek-bar-container')\n\n      if (seekBarContainer.firstElementChild?.classList.contains('markerContainer')) {\n        /** @type {HTMLDivElement} */\n        const markerBar = seekBarContainer.firstElementChild\n\n        markers.forEach(marker => markerBar.appendChild(marker))\n      } else {\n        const markerBar = document.createElement('div')\n        markerBar.className = 'markerContainer'\n\n        markers.forEach(marker => markerBar.appendChild(marker))\n\n        seekBarContainer.insertBefore(markerBar, seekBarContainer.firstElementChild)\n      }\n    }\n\n    // #endregion seek bar markers\n\n    // #region offline message\n\n    const isOffline = ref(!navigator.onLine)\n    const isBuffering = ref(false)\n\n    function onlineHandler() {\n      isOffline.value = false\n    }\n\n    function offlineHandler() {\n      isOffline.value = true\n    }\n\n    function fullscreenChangeHandler() {\n      nextTick(showOverlayControls)\n    }\n\n    window.addEventListener('online', onlineHandler)\n    window.addEventListener('offline', offlineHandler)\n\n    // Only display the offline message while buffering/the loading symbol is visible.\n    // If we briefly lose the connection but it comes back before the buffer is empty,\n    // the user won't notice anything so we don't need to display the message.\n    const showOfflineMessage = computed(() => {\n      return isOffline.value && isBuffering.value\n    })\n\n    // #endregion offline message\n\n    // #region setup\n    const initLoadWaitTimeToastAC = new AbortController()\n\n    onMounted(async () => {\n      const videoElement = video.value\n\n      const volume = sessionStorage.getItem('volume')\n      if (volume !== null) {\n        videoElement.volume = parseFloat(volume)\n      }\n\n      const muted = sessionStorage.getItem('muted')\n      if (muted !== null) {\n        // as sessionStorage stores string values which are truthy by default so we must check with 'true'\n        // otherwise 'false' will be returned as true as well\n        videoElement.muted = (muted === 'true')\n      }\n\n      const localPlayer = new shaka.Player()\n\n      ui = new shaka.ui.Overlay(\n        localPlayer,\n        container.value,\n        videoElement,\n        vrCanvas.value\n      )\n\n      // This has to be called after creating the UI, so that the player uses the UI's UITextDisplayer\n      // otherwise it uses the browsers native captions which get displayed underneath the UI controls\n      await localPlayer.attach(videoElement)\n\n      videoElement.playbackRate = props.currentPlaybackRate\n      videoElement.defaultPlaybackRate = defaultPlaybackRate.value\n\n      // check if the component is already getting destroyed\n      // which is possible because this function runs asynchronously\n      if (!ui) {\n        return\n      }\n\n      const controls = ui.getControls()\n      player = controls.getPlayer()\n\n      player.addEventListener('buffering', event => {\n        isBuffering.value = event.buffering\n      })\n\n      player.addEventListener('error', event => handleError(event.detail, 'shaka error handler'))\n\n      player.configure(getPlayerConfig(props.format, defaultQuality.value === 'auto'))\n\n      if (process.env.SUPPORTS_LOCAL_API) {\n        player.getNetworkingEngine().registerRequestFilter(requestFilter)\n        player.getNetworkingEngine().registerResponseFilter(responseFilter)\n      }\n\n      await setLocale(locale.value)\n\n      // check if the component is already getting destroyed\n      // which is possible because this function runs asynchronously\n      if (!ui || !player) {\n        return\n      }\n\n      videoResizeObserver.observe(videoElement)\n\n      registerScreenshotButton()\n      registerAudioTrackSelection()\n      registerAutoplayToggle()\n\n      registerTheatreModeButton()\n      registerFullWindowButton()\n      registerLegacyQualitySelection()\n      registerStatsButton()\n      registerSkipButtons()\n\n      if (ui.isMobile()) {\n        onlyUseOverFlowMenu.value = true\n      } else {\n        onlyUseOverFlowMenu.value = container.value.getBoundingClientRect().width <= USE_OVERFLOW_MENU_WIDTH_THRESHOLD\n\n        containerResizeObserver = new ResizeObserver(resized)\n        containerResizeObserver.observe(container.value)\n      }\n\n      controls.addEventListener('uiupdated', addUICustomizations)\n      configureUI(true)\n\n      document.removeEventListener('keydown', keyboardShortcutHandler)\n      document.addEventListener('keydown', keyboardShortcutHandler)\n      document.addEventListener('fullscreenchange', fullscreenChangeHandler)\n\n      player.addEventListener('loading', () => {\n        hasLoaded.value = false\n      })\n\n      player.addEventListener('loaded', handleLoaded)\n\n      if (props.format !== 'legacy') {\n        player.addEventListener('streaming', () => {\n          if (props.format === 'dash') {\n            const firstVariant = player.getVariantTracks()[0]\n\n            // force the player aspect ratio to 16:9 to avoid overflowing the layout\n            forceAspectRatio.value = firstVariant.width / firstVariant.height < 1.5\n          }\n        })\n      } else {\n        // force the player aspect ratio to 16:9 to avoid overflowing the layout, when the video is too tall\n\n        const firstFormat = props.legacyFormats[0]\n        forceAspectRatio.value = firstFormat.width / firstFormat.height < 1.5\n      }\n\n      if (useSponsorBlock.value && sponsorSkips.value.seekBar.length > 0) {\n        setupSponsorBlock()\n      }\n\n      window.addEventListener('beforeunload', stopPowerSaveBlocker)\n\n      // shaka-player doesn't start with the cursor hidden, so hide it here for instances in which the\n      // cursor is in the video player area when the video first loads\n      container.value.classList.add('no-cursor')\n\n      await performFirstLoad()\n      // Whatever runs after `performFirstLoad` might be after switching to another page due to SABR backoff\n\n      player?.addEventListener('ratechange', () => {\n        emit('playback-rate-updated', player.getPlaybackRate())\n      })\n    })\n    onUnmounted(() => {\n      initLoadWaitTimeToastAC.abort()\n    })\n\n    async function performFirstLoad() {\n      if (process.env.SUPPORTS_LOCAL_API && sabrStream) {\n        // Longer timeout for receiving larger responses\n        player.configure({\n          streaming: {\n            retryParameters: {\n              timeout: 30 * 1000 * 2,\n            }\n          }\n        })\n      } else {\n        // Reset to default value\n        player.configure({\n          streaming: {\n            retryParameters: {\n              timeout: 30 * 1000,\n            }\n          }\n        })\n      }\n\n      const initialLoadDelayMs = props.delayLoadUntilUnix - Date.now()\n      if (initialLoadDelayMs > 0 && (props.format === 'legacy' || props.manifestMimeType !== MANIFEST_TYPE_SABR)) {\n        showToast(\n          ({ remainingMs }) => {\n            // `+value` converts string back to float\n            return t('Video.Watch.Remaining preroll-ad time: {remindingTimeSeconds}s', { remindingTimeSeconds: +(remainingMs / 1000).toFixed(1) })\n          },\n          // So that we don't see last countdown text like 0/N\n          initialLoadDelayMs,\n          null,\n          initLoadWaitTimeToastAC.signal,\n        )\n        await new Promise((resolve) => setTimeout(resolve, initialLoadDelayMs))\n      }\n\n      if (props.format === 'dash' || props.format === 'audio') {\n        try {\n          await player.load(props.manifestSrc, props.startTime, props.manifestMimeType)\n\n          if (defaultQuality.value !== 'auto') {\n            if (props.format === 'dash') {\n              setDashQuality(defaultQuality.value)\n            } else {\n              let variants = player.getVariantTracks()\n\n              if (hasMultipleAudioTracks.value) {\n                // default audio track\n                variants = variants.filter(variant => variant.audioRoles.includes('main'))\n              }\n\n              const highestBandwidth = Math.max(...variants.map(variant => variant.audioBandwidth))\n              variants = variants.filter(variant => variant.audioBandwidth === highestBandwidth)\n\n              player.selectVariantTrack(variants[0])\n            }\n          }\n        } catch (error) {\n          handleError(error, 'loading dash/audio manifest and setting default quality in mounted')\n        }\n      } else {\n        await setLegacyQuality(props.startTime)\n      }\n    }\n\n    /**\n     * Adds the captions and thumbnail tracks, also restores the previously selected captions track,\n     * if this was triggered by a format change and the user had the captions enabled.\n     */\n    async function handleLoaded() {\n      hasLoaded.value = true\n      emit('loaded')\n\n      // ideally we would set this in the `streaming` event handler, but for HLS this is only set to true after the loaded event fires.\n      isLive.value = player.isLive()\n      // getAudioTracks() returns an empty array when no variant is active, so we can't do this in the `streaming` event\n      hasMultipleAudioTracks.value = deduplicateAudioTracks(player.getAudioTracks()).size > 1\n\n      if (process.env.SUPPORTS_LOCAL_API && props.format !== 'legacy' && props.manifestMimeType === MANIFEST_TYPE_SABR) {\n        sabrManifest = player.getManifest()\n      }\n\n      // For SABR we include the thumbnails and subtitles in the manifest\n      if (!process.env.SUPPORTS_LOCAL_API || props.format === 'legacy' || props.manifestMimeType !== MANIFEST_TYPE_SABR) {\n        const promises = []\n\n        for (const caption of props.captions) {\n          if (props.format === 'legacy') {\n            const url = new URL(caption.url)\n\n            if (url.hostname.endsWith('.youtube.com') && url.pathname === '/api/timedtext' &&\n              url.searchParams.get('caps') === 'asr' && url.searchParams.get('kind') === 'asr' && url.searchParams.get('fmt') === 'vtt') {\n              promises.push((async () => {\n                try {\n                  const response = await fetch(caption.url)\n                  let text = await response.text()\n\n                  // position:0% for LTR text and position:100% for RTL text\n                  text = text.replaceAll(/ align:start position:(?:10)?0%$/gm, '')\n\n                  const url = `data:${caption.mimeType};charset=utf-8,${encodeURIComponent(text)}`\n\n                  await player.addTextTrackAsync(\n                    url,\n                    caption.language,\n                    'captions',\n                    caption.mimeType,\n                    undefined, // codec, only needed if the captions are inside a container (e.g. mp4)\n                    caption.label\n                  )\n                } catch (error) {\n                  if (error instanceof shaka.util.Error) {\n                    handleError(error, 'addTextTrackAsync', caption)\n                  } else {\n                    console.error(error)\n                  }\n                }\n              })())\n            } else {\n              promises.push(\n                player.addTextTrackAsync(\n                  caption.url,\n                  caption.language,\n                  'captions',\n                  caption.mimeType,\n                  undefined, // codec, only needed if the captions are inside a container (e.g. mp4)\n                  caption.label\n                )\n                  .catch(error => handleError(error, 'addTextTrackAsync', caption))\n              )\n            }\n          } else {\n            promises.push(\n              player.addTextTrackAsync(\n                caption.url,\n                caption.language,\n                'captions',\n                caption.mimeType,\n                undefined, // codec, only needed if the captions are inside a container (e.g. mp4)\n                caption.label\n              )\n                .catch(error => handleError(error, 'addTextTrackAsync', caption))\n            )\n          }\n        }\n\n        if (!isLive.value && props.storyboardSrc) {\n          promises.push(\n            // Only log the error, as the thumbnails are a nice to have\n            // If an error occurs with them, it's not critical\n            player.addThumbnailsTrack(props.storyboardSrc, 'text/vtt')\n              .catch(error => logShakaError(error, 'addThumbnailsTrack', props.videoId, props.storyboardSrc))\n          )\n        }\n\n        await Promise.all(promises)\n      }\n\n      if (restoreCaptionIndex !== null) {\n        const index = restoreCaptionIndex\n        restoreCaptionIndex = null\n\n        const textTrack = player.getTextTracks()[index]\n\n        if (textTrack) {\n          player.selectTextTrack(textTrack)\n        }\n      }\n\n      if (props.chapters.length > 0) {\n        createChapterMarkers()\n      }\n\n      if (startInFullscreen && process.env.IS_ELECTRON) {\n        startInFullscreen = false\n        window.ftElectron.requestFullscreen()\n      }\n    }\n\n    watch(\n      () => props.format,\n      /**\n       * Handles changing between formats. It tries its best to backup and restore the settings:\n       * - playback position\n       * - paused state\n       * - audio track\n       * - captions track\n       * - video quality\n       * @param {'dash'|'audio'|'legacy'} newFormat\n       * @param {'dash'|'audio'|'legacy'} oldFormat\n       */\n      async (newFormat, oldFormat) => {\n        ignoreErrors = true\n\n        // format switch happened before the player loaded, probably because of an error\n        // as there are no previous player settings to restore, we should treat it like this was the original format\n        if (!hasLoaded.value) {\n          try {\n            await player.unload()\n          } catch { }\n\n          ignoreErrors = false\n\n          player.configure(getPlayerConfig(newFormat, defaultQuality.value === 'auto'))\n\n          await performFirstLoad()\n          return\n        }\n\n        const video_ = video.value\n\n        const wasPaused = video_.paused\n\n        let useAutoQuality = oldFormat === 'legacy' ? defaultQuality.value === 'auto' : player.getConfiguration().abr.enabled\n\n        if (!wasPaused) {\n          video_.pause()\n        }\n\n        const playbackPosition = video_.currentTime\n\n        const activeCaptionIndex = player.getTextTracks().findIndex(caption => caption.active)\n\n        if (activeCaptionIndex >= 0) {\n          restoreCaptionIndex = activeCaptionIndex\n\n          // hide captions before switching as shaka/the browser doesn't clean up the displayed captions\n          // when switching away from the legacy formats\n          player.selectTextTrack(null)\n        } else {\n          restoreCaptionIndex = null\n        }\n\n        if (newFormat === 'audio' || newFormat === 'dash') {\n          let label\n          let audioBandwidth\n          let dimension\n\n          if (oldFormat === 'legacy' && newFormat === 'dash') {\n            const legacyFormat = activeLegacyFormat.value\n\n            if (!useAutoQuality) {\n              dimension = legacyFormat.height > legacyFormat.width ? legacyFormat.width : legacyFormat.height\n            }\n          } else if (oldFormat !== 'legacy') {\n            const track = player.getVariantTracks().find(track => track.active)\n\n            if (typeof track.audioBandwidth === 'number') {\n              audioBandwidth = track.audioBandwidth\n            }\n\n            if (track.label) {\n              label = track.label\n            }\n          }\n\n          if (oldFormat === 'audio' && newFormat === 'dash' && !useAutoQuality) {\n            if (defaultQuality.value !== 'auto') {\n              dimension = defaultQuality.value\n            } else {\n              // Use auto as we don't know what resolution to pick\n              useAutoQuality = true\n            }\n          }\n\n          try {\n            await player.unload()\n          } catch { }\n\n          ignoreErrors = false\n\n          player.configure(getPlayerConfig(newFormat, useAutoQuality))\n\n          try {\n            await player.load(props.manifestSrc, playbackPosition, props.manifestMimeType)\n\n            if (useAutoQuality) {\n              if (label) {\n                const audioTracks = deduplicateAudioTracks(player.getAudioTracks()).values()\n\n                for (const track of audioTracks) {\n                  if (label === track.label) {\n                    player.selectAudioTrack(track)\n                    break\n                  }\n                }\n              }\n            } else {\n              if (dimension) {\n                setDashQuality(dimension, audioBandwidth, label)\n              } else {\n                let variants = player.getVariantTracks()\n\n                if (label) {\n                  variants = variants.filter(variant => variant.label === label)\n                } else if (variants.length > 1) {\n                  // default audio track\n                  const filteredVariants = variants.filter(variant => variant.audioRoles.includes('main'))\n                  // Sometimes there is nothing marked as main, don't filter in this case\n                  if (filteredVariants.length > 0) {\n                    variants = filteredVariants\n                  }\n                }\n\n                let chosenVariant\n\n                if (typeof audioBandwidth === 'number') {\n                  chosenVariant = findMostSimilarAudioBandwidth(variants, audioBandwidth)\n                } else {\n                  chosenVariant = variants.reduce((previous, current) => {\n                    return previous === null || current.bandwidth > previous.bandwidth ? current : previous\n                  }, null)\n                }\n\n                player.selectVariantTrack(chosenVariant)\n              }\n            }\n          } catch (error) {\n            handleError(error, 'loading dash/audio manifest for format switch', `${oldFormat} -> ${newFormat}`)\n          }\n          activeLegacyFormat.value = null\n        } else {\n          let previousQuality\n\n          if (oldFormat === 'dash') {\n            const previousTrack = player.getVariantTracks().find(track => track.active)\n\n            previousQuality = previousTrack.height > previousTrack.width ? previousTrack.width : previousTrack.height\n          }\n\n          try {\n            await player.unload()\n          } catch { }\n\n          ignoreErrors = false\n\n          await setLegacyQuality(playbackPosition, previousQuality)\n        }\n\n        if (wasPaused) {\n          video_.pause()\n        }\n      }\n    )\n\n    // #endregion setup\n\n    // #region tear down\n\n    onBeforeUnmount(() => {\n      hasLoaded.value = false\n      document.body.classList.remove('playerFullWindow')\n\n      document.removeEventListener('keydown', keyboardShortcutHandler)\n      document.removeEventListener('fullscreenchange', fullscreenChangeHandler)\n\n      if (containerResizeObserver) {\n        containerResizeObserver.disconnect()\n        containerResizeObserver = null\n      }\n\n      if (videoResizeObserver) {\n        videoResizeObserver.disconnect()\n      }\n\n      cleanUpCustomPlayerControls()\n\n      stopPowerSaveBlocker()\n      window.removeEventListener('beforeunload', stopPowerSaveBlocker)\n\n      if ('mediaSession' in navigator) {\n        navigator.mediaSession.playbackState = 'none'\n      }\n\n      skippedSponsorBlockSegments.value.forEach(segment => clearTimeout(segment.timeoutId))\n\n      window.removeEventListener('online', onlineHandler)\n      window.removeEventListener('offline', offlineHandler)\n    })\n\n    // #endregion tear down\n\n    // #region functions used by the watch page\n\n    function isPaused() {\n      return video.value.paused\n    }\n\n    function pause() {\n      video.value.pause()\n    }\n\n    function getCurrentTime() {\n      return video.value.currentTime\n    }\n\n    /**\n     * @param {number} time\n     */\n    function setCurrentTime(time) {\n      video.value.currentTime = time\n    }\n\n    /**\n     * Vue's lifecycle hooks are synchonous, so if we destroy the player in {@linkcode onBeforeUnmount},\n     * it won't be finished in time, as the player destruction is asynchronous.\n     * To workaround that we destroy the player first and wait for it to finish before we unmount this component.\n     *\n     * @returns {Promise<{ startNextVideoInFullscreen: boolean, startNextVideoInFullwindow: boolean, startNextVideoInPip: boolean }>}\n     */\n    async function destroyPlayer() {\n      ignoreErrors = true\n\n      let uiState = { startNextVideoInFullscreen: false, startNextVideoInFullwindow: false, startNextVideoInPip: false }\n\n      if (ui) {\n        if (ui.getControls()) {\n          // save the state of player settings to reinitialize them upon next creation\n          const controls = ui.getControls()\n          uiState = {\n            startNextVideoInFullscreen: controls.isFullScreenEnabled(),\n            startNextVideoInFullwindow: fullWindowEnabled.value,\n            startNextVideoInPip: controls.isPiPEnabled()\n          }\n        }\n\n        // destroying the ui also destroys the player\n        await ui.destroy()\n        ui = null\n        player = null\n      } else if (player) {\n        await player.destroy()\n        player = null\n      }\n\n      if (process.env.SUPPORTS_LOCAL_API && sabrStream) {\n        sabrStream.cleanup()\n        sabrAbortController?.abort()\n      }\n\n      // shaka-player doesn't clear these itself, which prevents shaka.ui.Overlay from being garbage collected\n      // Should really be fixed in shaka-player but it's easier just to do it ourselves\n      if (container.value) {\n        container.value.ui = null\n      }\n\n      if (video.value) {\n        video.value.ui = null\n      }\n\n      return uiState\n    }\n\n    expose({\n      hasLoaded,\n\n      isPaused,\n      pause,\n      getCurrentTime,\n      setCurrentTime,\n      destroyPlayer\n    })\n\n    // #endregion functions used by the watch page\n\n    const showValueChangePopup = ref(false)\n    const valueChangeMessage = ref('')\n    const valueChangeIcon = ref(null)\n    const invertValueChangeContentOrder = ref(false)\n    let valueChangeTimeout = null\n\n    function showOverlayControls() {\n      ui.getControls().showUI()\n    }\n\n    /**\n     * Shows a popup with a message and an icon on top of the video player.\n     * @param {string} message - The message to display.\n     * @param {string} icon - The icon to display.\n     * @param {boolean} invertContentOrder - Whether to invert the order of the icon and message.\n     */\n    function showValueChange(message, icon = null, invertContentOrder = false) {\n      valueChangeMessage.value = message\n      valueChangeIcon.value = icon\n      showValueChangePopup.value = true\n      invertValueChangeContentOrder.value = invertContentOrder\n\n      if (valueChangeTimeout) {\n        clearTimeout(valueChangeTimeout)\n      }\n\n      valueChangeTimeout = setTimeout(() => {\n        showValueChangePopup.value = false\n      }, 2000)\n\n      showOverlayControls()\n    }\n\n    return {\n      container,\n      video,\n      vrCanvas,\n\n      fullWindowEnabled,\n      forceAspectRatio,\n\n      showStats,\n      stats,\n      playerDimensions,\n\n      autoplayVideos,\n      sponsorBlockShowSkippedToast,\n\n      skippedSponsorBlockSegments,\n\n      showOfflineMessage,\n\n      handlePlay,\n      handlePause,\n      handleCanPlay,\n      handleEnded,\n      updateVolume,\n      handleTimeupdate,\n      handleEnterPictureInPicture,\n      handleLeavePictureInPicture,\n\n      valueChangeMessage,\n      valueChangeIcon,\n      showValueChangePopup,\n      invertValueChangeContentOrder,\n    }\n  }\n})\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.vue",
    "content": "<template>\n  <div\n    ref=\"container\"\n    class=\"ftVideoPlayer shaka-video-container\"\n    :class=\"{\n      fullWindow: fullWindowEnabled,\n      sixteenByNine: forceAspectRatio && !fullWindowEnabled\n    }\"\n  >\n    <!-- eslint-disable-next-line vuejs-accessibility/media-has-caption -->\n    <video\n      ref=\"video\"\n      class=\"player\"\n      preload=\"auto\"\n      crossorigin=\"anonymous\"\n      playsinline\n      :autoplay=\"autoplayVideos ? true : null\"\n      :poster=\"thumbnail\"\n      @play=\"handlePlay\"\n      @pause=\"handlePause\"\n      @ended=\"handleEnded\"\n      @canplay=\"handleCanPlay\"\n      @volumechange=\"updateVolume\"\n      @timeupdate=\"handleTimeupdate\"\n      @enterpictureinpicture=\"handleEnterPictureInPicture\"\n      @leavepictureinpicture=\"handleLeavePictureInPicture\"\n    />\n    <!--\n      VR playback is only possible for VR videos with \"EQUIRECTANGULAR\" projection\n      This intentionally doesn't use the \"useVrMode\" computed prop,\n      as that changes depending on the active format,\n      but as we initialize the shaka-player UI once per watch page,\n      the canvas has to exist even in audio-only mode, because the user may switch to DASH later.\n    -->\n    <canvas\n      v-if=\"vrProjection === 'EQUIRECTANGULAR'\"\n      ref=\"vrCanvas\"\n      class=\"vrCanvas\"\n    />\n    <div\n      v-if=\"showStats\"\n      class=\"stats\"\n    >\n      <span>{{ $t('Video.Player.Stats.Video ID', { videoId }) }}</span>\n      <br>\n      <span>{{ $t('Video.Player.Stats.Media Formats', { formats: format }) }}</span>\n      <br>\n      <span>{{ $t('Video.Player.Stats.Bitrate', { bitrate: stats.bitrate }) }}</span>\n      <br>\n      <span>{{ $t('Video.Player.Stats.Volume', { volumePercentage: stats.volume }) }}</span>\n      <br>\n      <template\n        v-if=\"format !== 'legacy'\"\n      >\n        <span>{{ $t('Video.Player.Stats.Bandwidth', { bandwidth: stats.bandwidth }) }}</span>\n        <br>\n      </template>\n      <span>{{ $t('Video.Player.Stats.Buffered', { bufferedPercentage: stats.buffered }) }}</span>\n      <br>\n      <span\n        v-if=\"format === 'audio'\"\n      >{{ $t('Video.Player.Stats.CodecAudio', stats.codecs) }}</span>\n      <span\n        v-else-if=\"stats.codecs.audioItag && stats.codecs.videoItag\"\n      >{{ $t('Video.Player.Stats.CodecsVideoAudio', stats.codecs) }}</span>\n      <span\n        v-else\n      >{{ $t('Video.Player.Stats.CodecsVideoAudioNoItags', stats.codecs) }}</span>\n      <br>\n      <span>{{ $t('Video.Player.Stats.Player Dimensions', playerDimensions) }}</span>\n      <br>\n      <template\n        v-if=\"format !== 'audio'\"\n      >\n        <span>{{ $t('Video.Player.Stats.Resolution', stats.resolution) }}</span>\n        <br>\n        <span>{{ $t('Video.Player.Stats.Dropped Frames / Total Frames', stats.frames) }}</span>\n      </template>\n    </div>\n    <Transition name=\"fade\">\n      <div\n        v-if=\"showValueChangePopup\"\n        class=\"valueChangePopup\"\n        :class=\"{ 'invert-content-order': invertValueChangeContentOrder }\"\n      >\n        <font-awesome-icon\n          v-if=\"valueChangeIcon\"\n          :icon=\"['fas', valueChangeIcon]\"\n        />\n        <span>{{ valueChangeMessage }}</span>\n      </div>\n    </Transition>\n    <div\n      v-if=\"showOfflineMessage\"\n      class=\"offlineWrapper\"\n    >\n      <font-awesome-layers\n        class=\"offlineIcon\"\n        aria-hidden=\"true\"\n      >\n        <font-awesome-icon :icon=\"['fas', 'wifi']\" />\n        <font-awesome-icon :icon=\"['fas', 'slash']\" />\n      </font-awesome-layers>\n      <p class=\"offlineMessage\">\n        <span>\n          {{ $t('Video.Player.You appear to be offline') }}\n        </span>\n        <br>\n        <span class=\"offlineMessageSubtitle\">\n          {{ $t('Video.Player.Playback will resume automatically when your connection comes back') }}\n        </span>\n      </p>\n    </div>\n    <div\n      v-if=\"sponsorBlockShowSkippedToast && skippedSponsorBlockSegments.length > 0\"\n      class=\"skippedSegmentsWrapper\"\n    >\n      <p\n        v-for=\"{ uuid, translatedCategory } in skippedSponsorBlockSegments\"\n        :key=\"uuid\"\n        class=\"skippedSegment\"\n      >\n        {{ $t('Video.Player.Skipped segment', { segmentCategory: translatedCategory }) }}\n      </p>\n    </div>\n  </div>\n</template>\n\n<script src=\"./ft-shaka-video-player.js\" />\n\n<style src=\"shaka-player/dist/controls.css\" />\n<style scoped src=\"./ft-shaka-video-player.css\" />\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/AudioTrackSelection.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { deduplicateAudioTracks } from '../../../helpers/player/utils'\nimport { PlayerIcons } from '../../../../constants'\n\nexport class AudioTrackSelection extends shaka.ui.SettingsMenu {\n  /**\n   * @param {EventTarget} events\n   * @param {!HTMLElement} parent\n   * @param {!shaka.ui.Controls} controls\n   */\n  constructor(events, parent, controls) {\n    super(parent, controls, PlayerIcons.RECORD_VOICE_OVER_FILLED)\n\n    this.button.classList.add('audio-track-button', 'shaka-tooltip-status')\n    this.menu.classList.add('audio-tracks')\n\n    /** @type {SVGElement} */\n    const checkmarkIcon = new shaka.ui.Icon(null, PlayerIcons.DONE_FILLED).getSvgElement()\n    checkmarkIcon.classList.add('shaka-chosen-item')\n    checkmarkIcon.ariaHidden = 'true'\n\n    /** @private */\n    this._checkmarkIcon = checkmarkIcon\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.eventManager.listen(this.player, 'loading', () => {\n      this.updateAudioTracks_()\n    })\n\n    this.eventManager.listen(this.player, 'trackschanged', () => {\n      this.updateAudioTracks_()\n    })\n\n    this.eventManager.listen(this.player, 'variantchanged', () => {\n      this.updateAudioTracks_()\n    })\n\n    this.eventManager.listen(this.player, 'adaptation', () => {\n      this.updateAudioTracks_()\n    })\n\n    if (this.isSubMenu) {\n      this.eventManager.listen(this.controls, 'submenuopen', () => {\n        this.updateAudioTracks_()\n      })\n\n      this.eventManager.listen(this.controls, 'submenuclose', () => {\n        this.updateAudioTracks_()\n      })\n    }\n\n    this.updateLocalisedStrings_()\n\n    this.updateAudioTracks_()\n  }\n\n  /**\n   * @private\n   */\n  updateAudioTracks_() {\n    const tracks = deduplicateAudioTracks(this.player.getAudioTracks()).values()\n\n    const menu = this.menu\n\n    const backButton = menu.querySelector('.shaka-back-to-overflow-button')\n\n    while (menu.firstChild) {\n      menu.removeChild(menu.firstChild)\n    }\n\n    menu.appendChild(backButton)\n\n    let count = 0\n\n    for (const track of tracks) {\n      const button = document.createElement('button')\n      button.addEventListener('click', () => {\n        this.onAudioTrackSelected_(track)\n      })\n\n      const span = document.createElement('span')\n      button.appendChild(span)\n\n      span.textContent = track.label || new Intl.DisplayNames('en', { type: 'language', languageDisplay: 'standard' }).of(track.language)\n\n      if (track.active) {\n        button.appendChild(this._checkmarkIcon)\n\n        span.classList.add('shaka-chosen-item')\n        button.ariaSelected = 'true'\n        this.currentSelection.textContent = span.textContent\n      }\n\n      menu.appendChild(button)\n      count++\n    }\n\n    menu.querySelector('shaka-chosen-item')?.parentElement.focus()\n\n    this.button.setAttribute('shaka-status', this.currentSelection.innerText)\n\n    if (count > 1 && !this.isSubMenuOpened) {\n      this.button.classList.remove('shaka-hidden')\n    } else {\n      this.button.classList.add('shaka-hidden')\n    }\n  }\n\n  /**\n   * @param {shaka.extern.AudioTrack} track\n   * @private\n   */\n  onAudioTrackSelected_(track) {\n    track.codecs = null\n\n    this.player.selectAudioTrack(track)\n\n    const config = {\n      preferSpatialAudio: track.spatialAudio\n    }\n\n    if (track.language !== 'und') {\n      config.preferredAudioLanguage = track.language\n    }\n\n    if (track.label) {\n      config.preferredAudioLabel = track.label\n    }\n\n    if (track.channelsCount) {\n      config.preferredAudioChannelCount = track.channelsCount\n    }\n\n    this.player.configure(config)\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    this.backButton.ariaLabel = this.localization.resolve('BACK')\n\n    const audioTracksText = i18n.global.t('Video.Player.Audio Tracks')\n\n    this.button.ariaLabel = audioTracksText\n    this.nameSpan.textContent = audioTracksText\n    this.backSpan.textContent = audioTracksText\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/AutoplayToggle.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { PlayerIcons } from '../../../../constants'\n\nexport class AutoplayToggle extends shaka.ui.Element {\n  /**\n   * @param {boolean} autoplayEnabled\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   */\n  constructor(autoplayEnabled, events, parent, controls) {\n    super(parent, controls)\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add('autoplay-toggle', 'shaka-tooltip')\n\n    /** @private */\n    this.icon_ = new shaka.ui.Icon(this.button_, PlayerIcons.PAUSE_CIRCLE_FILLED)\n\n    const label = document.createElement('label')\n    label.classList.add(\n      'shaka-overflow-button-label',\n      'shaka-overflow-menu-only',\n      'shaka-simple-overflow-button-label-inline'\n    )\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n\n    /** @private */\n    this.currentState_ = document.createElement('span')\n    this.currentState_.classList.add('shaka-current-selection-span')\n    label.appendChild(this.currentState_)\n\n    this.button_.appendChild(label)\n\n    this.parent.appendChild(this.button_)\n\n    /** @private */\n    this.autoplayEnabled_ = autoplayEnabled\n\n    // listeners\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      events.dispatchEvent(new CustomEvent('toggleAutoplay', {\n        detail: !this.autoplayEnabled_\n      }))\n    })\n\n    const handleAutoplayValueChange = (/** @type {CustomEvent} */ event) => {\n      this.autoplayEnabled_ = event.detail\n      this.updateLocalisedStrings_()\n    }\n\n    this.eventManager.listen(events, 'setAutoplay', handleAutoplayValueChange)\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    this.nameSpan_.textContent = i18n.global.t('Video.Autoplay')\n\n    this.icon_.use(this.autoplayEnabled_ ? PlayerIcons.PLAY_CIRCLE_FILLED : PlayerIcons.PAUSE_CIRCLE_FILLED)\n\n    this.currentState_.textContent = this.localization.resolve(this.autoplayEnabled_ ? 'ON' : 'OFF')\n\n    this.button_.ariaLabel = this.autoplayEnabled_ ? i18n.global.t('Video.Player.Autoplay is on') : i18n.global.t('Video.Player.Autoplay is off')\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/FullWindowButton.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { KeyboardShortcuts, PlayerIcons } from '../../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../../helpers/utils'\n\nexport class FullWindowButton extends shaka.ui.Element {\n  /**\n   * @param {boolean} fullWindowEnabled\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   */\n  constructor(fullWindowEnabled, events, parent, controls) {\n    super(parent, controls)\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add('full-window-button', 'shaka-tooltip')\n\n    /** @private */\n    this.icon_ = new shaka.ui.Icon(this.button_, PlayerIcons.OPEN_IN_FULL_FILLED)\n\n    const label = document.createElement('label')\n    label.classList.add(\n      'shaka-overflow-button-label',\n      'shaka-overflow-menu-only',\n      'shaka-simple-overflow-button-label-inline'\n    )\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n\n    /** @private */\n    this.currentState_ = document.createElement('span')\n    this.currentState_.classList.add('shaka-current-selection-span')\n    label.appendChild(this.currentState_)\n\n    this.button_.appendChild(label)\n\n    this.parent.appendChild(this.button_)\n\n    /** @private */\n    this.fullWindowEnabled_ = fullWindowEnabled\n\n    // listeners\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      events.dispatchEvent(new CustomEvent('setFullWindow', {\n        detail: !this.fullWindowEnabled_\n      }))\n    })\n\n    this.eventManager.listen(events, 'setFullWindow', (/** @type {CustomEvent} */ event) => {\n      this.fullWindowEnabled_ = event.detail\n\n      this.updateLocalisedStrings_()\n    })\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    this.icon_.use(this.fullWindowEnabled_ ? PlayerIcons.CLOSE_FULLSCREEN_FILLED : PlayerIcons.OPEN_IN_FULL_FILLED)\n    this.currentState_.textContent = this.localization.resolve(this.fullWindowEnabled_ ? 'ON' : 'OFF')\n\n    const baseAriaLabel = this.fullWindowEnabled_ ? i18n.global.t('Video.Player.Exit Full Window') : i18n.global.t('Video.Player.Full Window')\n    const newLabel = addKeyboardShortcutToActionTitle(\n      baseAriaLabel,\n      KeyboardShortcuts.VIDEO_PLAYER.GENERAL.FULLWINDOW\n    )\n    this.nameSpan_.textContent = this.button_.ariaLabel = newLabel\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/LegacyQualitySelection.js",
    "content": "import shaka from 'shaka-player'\n\nimport { PlayerIcons } from '../../../../constants'\n\nexport class LegacyQualitySelection extends shaka.ui.SettingsMenu {\n  /**\n   * @param {object} activeLegacyFormat\n   * @param {object[]} legacyFormats\n   * @param {EventTarget} events\n   * @param {!HTMLElement} parent\n   * @param {!shaka.ui.Controls} controls\n   */\n  constructor(activeLegacyFormat, legacyFormats, events, parent, controls) {\n    super(parent, controls, PlayerIcons.TUNE_FILLED)\n\n    this.button.classList.add('legacy-quality-button', 'shaka-tooltip-status')\n    this.menu.classList.add('legacy-qualities')\n\n    /** @type {SVGElement} */\n    const checkmarkIcon = new shaka.ui.Icon(null, PlayerIcons.DONE_FILLED).getSvgElement()\n    checkmarkIcon.classList.add('shaka-chosen-item')\n    checkmarkIcon.ariaHidden = 'true'\n\n    /** @private */\n    this._checkmarkIcon = checkmarkIcon\n\n    /** @private */\n    this.events_ = events\n    /** @private */\n    this.activeLegacyFormat_ = activeLegacyFormat\n\n    const sortedLegacyFormats = [...legacyFormats]\n\n    const isPortrait = legacyFormats[0].height > legacyFormats[0].width\n    sortedLegacyFormats.sort((a, b) => isPortrait ? b.width - a.width : b.height - a.height)\n\n    /** @private */\n    this.legacyFormats_ = sortedLegacyFormats\n\n    for (const format of sortedLegacyFormats) {\n      const button = document.createElement('button')\n      button.classList.add('legacy-resolution')\n\n      this.eventManager.listen(button, 'click', () => {\n        this.onFormatSelected_(format)\n      })\n\n      const span = document.createElement('span')\n      span.textContent = format.qualityLabel\n      button.appendChild(span)\n\n      this.menu.appendChild(button)\n    }\n\n    // listeners\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.eventManager.listen(events, 'setLegacyFormat', (/** @type {CustomEvent} */ event) => {\n      this.activeLegacyFormat_ = event.detail.format\n      this.updateResolutionSelection_()\n    })\n\n    if (this.isSubMenu) {\n      this.eventManager.listen(this.controls, 'submenuopen', () => {\n        this.button.classList.add('shaka-hidden')\n      })\n\n      this.eventManager.listen(this.controls, 'submenuclose', () => {\n        this.button.classList.remove('shaka-hidden')\n      })\n    }\n\n    this.updateResolutionSelection_()\n  }\n\n  /** @private */\n  updateResolutionSelection_() {\n    if (!this.activeLegacyFormat_) {\n      return\n    }\n\n    // remove previous selection\n\n    const previousSpan = this.menu.querySelector('.shaka-chosen-item')\n    if (previousSpan) {\n      previousSpan.classList.remove('shaka-chosen-item')\n\n      const button = previousSpan.parentElement\n      button.ariaSelected = 'false'\n      this._checkmarkIcon.remove()\n    }\n\n    // current selection\n\n    const index = this.legacyFormats_.indexOf(this.activeLegacyFormat_)\n\n    const button = this.menu.querySelectorAll('.legacy-resolution')[index]\n    const span = button.querySelector('span')\n\n    button.ariaSelected = 'true'\n\n    span.classList.add('shaka-chosen-item')\n\n    button.appendChild(this._checkmarkIcon)\n\n    this.currentSelection.textContent = span.textContent\n\n    this.button.setAttribute('shaka-status', span.textContent)\n\n    button.focus()\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  async onFormatSelected_(format) {\n    if (format === this.activeLegacyFormat_) {\n      return\n    }\n\n    const playbackPosition = this.player.getMediaElement().currentTime\n\n    const activeCaptionIndex = this.player.getTextTracks().findIndex(caption => caption.active)\n    let restoreCaptionIndex = null\n\n    if (activeCaptionIndex >= 0) {\n      restoreCaptionIndex = activeCaptionIndex\n\n      // hide captions before switching as shaka/the browser doesn't clean up the displayed captions\n      // when switching away from the legacy formats\n      this.player.selectTextTrack(null)\n    }\n\n    this.events_.dispatchEvent(new CustomEvent('setLegacyFormat', {\n      detail: {\n        format,\n        playbackPosition,\n        restoreCaptionIndex\n      }\n    }))\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    const resolutionText = this.localization.resolve('RESOLUTION')\n\n    this.button.ariaLabel = resolutionText\n    this.backButton.ariaLabel = resolutionText\n    this.backSpan.textContent = resolutionText\n    this.nameSpan.textContent = resolutionText\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/ScreenshotButton.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { KeyboardShortcuts, PlayerIcons } from '../../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../../helpers/utils'\n\nexport class ScreenshotButton extends shaka.ui.Element {\n  /**\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   */\n  constructor(events, parent, controls) {\n    super(parent, controls)\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add('screenshot-button', 'shaka-tooltip')\n\n    // eslint-disable-next-line no-new\n    new shaka.ui.Icon(this.button_, PlayerIcons.PHOTO_CAMERA_FILLED)\n\n    const label = document.createElement('label')\n    label.classList.add(\n      'shaka-overflow-button-label',\n      'shaka-overflow-menu-only',\n      'shaka-simple-overflow-button-label-inline'\n    )\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n\n    this.button_.appendChild(label)\n\n    this.parent.appendChild(this.button_)\n\n    // listeners\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      events.dispatchEvent(new CustomEvent('takeScreenshot'))\n    })\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    const label = addKeyboardShortcutToActionTitle(\n      i18n.global.t('Video.Player.Take Screenshot'),\n      KeyboardShortcuts.VIDEO_PLAYER.GENERAL.TAKE_SCREENSHOT\n    )\n    this.nameSpan_.textContent = this.button_.ariaLabel = label\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/SkipButton.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { KeyboardShortcuts, PlayerIcons } from '../../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../../helpers/utils'\n\nexport class SkipButton extends shaka.ui.Element {\n  /**\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   * @param {'next'|'previous'} type\n   */\n  constructor(events, parent, controls, type = 'next') {\n    super(parent, controls)\n\n    this.type_ = type\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add(`skip-${type}-button`, 'shaka-tooltip', 'ft-shaka-skip-button')\n\n    const icon = type === 'next' ? PlayerIcons.SKIP_NEXT_FILLED : PlayerIcons.SKIP_PREVIOUS_FILLED\n    // eslint-disable-next-line no-new\n    new shaka.ui.Icon(this.button_, icon)\n\n    const label = document.createElement('label')\n    label.classList.add(\n      'shaka-overflow-button-label',\n      'shaka-overflow-menu-only',\n      'shaka-simple-overflow-button-label-inline'\n    )\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n    this.button_.appendChild(label)\n    this.parent.appendChild(this.button_)\n\n    // listener\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      const eventName = type === 'next' ? 'nextVideo' : 'previousVideo'\n      events.dispatchEvent(new CustomEvent(eventName))\n    })\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    const labelText =\n      this.type_ === 'next'\n        ? i18n.global.t('Video.Next')\n        : i18n.global.t('Video.Previous')\n\n    const shortcut =\n      this.type_ === 'next'\n        ? KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SKIP_TO_NEXT\n        : KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SKIP_TO_PREV\n\n    const label = addKeyboardShortcutToActionTitle(labelText, shortcut)\n    this.nameSpan_.textContent = this.button_.ariaLabel = label\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/StatsButton.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { KeyboardShortcuts, PlayerIcons } from '../../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../../helpers/utils'\n\nexport class StatsButton extends shaka.ui.Element {\n  /**\n   * @param {boolean} showStats\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   */\n  constructor(showStats, events, parent, controls) {\n    super(parent, controls)\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add('stats-button')\n\n    /** @private */\n    this.icon_ = new shaka.ui.Icon(this.button_, PlayerIcons.INSERT_CHART_DEFAULT)\n\n    const label = document.createElement('label')\n    label.classList.add('shaka-overflow-button-label', 'shaka-simple-overflow-button-label-inline')\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n\n    /** @private */\n    this.currentState_ = document.createElement('span')\n    this.currentState_.classList.add('shaka-current-selection-span')\n    label.appendChild(this.currentState_)\n\n    this.button_.appendChild(label)\n\n    this.parent.appendChild(this.button_)\n\n    /** @private */\n    this.showStats_ = showStats\n\n    // listeners\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      events.dispatchEvent(new CustomEvent('setStatsVisibility', {\n        detail: !this.showStats_\n      }))\n    })\n\n    this.eventManager.listen(events, 'setStatsVisibility', (/** @type {CustomEvent} */ event) => {\n      this.showStats_ = event.detail\n\n      this.updateLocalisedStrings_()\n    })\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    this.icon_.use(this.showStats_ ? PlayerIcons.INSERT_CHART_FILLED : PlayerIcons.INSERT_CHART_DEFAULT)\n\n    const baseLabel = this.showStats_ ? i18n.global.t('Video.Player.Hide Stats') : i18n.global.t('Video.Player.Show Stats')\n    const label = addKeyboardShortcutToActionTitle(\n      baseLabel,\n      KeyboardShortcuts.VIDEO_PLAYER.GENERAL.STATS\n    )\n\n    this.nameSpan_.textContent = label\n    this.button_.ariaLabel = label\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/ft-shaka-video-player/player-components/TheatreModeButton.js",
    "content": "import shaka from 'shaka-player'\n\nimport i18n from '../../../i18n/index'\nimport { KeyboardShortcuts, PlayerIcons } from '../../../../constants'\nimport { addKeyboardShortcutToActionTitle } from '../../../helpers/utils'\n\nexport class TheatreModeButton extends shaka.ui.Element {\n  /**\n   * @param {boolean} theatreModeEnabled\n   * @param {EventTarget} events\n   * @param {HTMLElement} parent\n   * @param {shaka.ui.Controls} controls\n   */\n  constructor(theatreModeEnabled, events, parent, controls) {\n    super(parent, controls)\n\n    /** @private */\n    this.button_ = document.createElement('button')\n    this.button_.classList.add('theatre-button', 'shaka-tooltip')\n\n    /** @private */\n    this.icon_ = new shaka.ui.Icon(this.button_, PlayerIcons.RECTANGLE_DEFAULT)\n\n    const label = document.createElement('label')\n    label.classList.add(\n      'shaka-overflow-button-label',\n      'shaka-overflow-menu-only',\n      'shaka-simple-overflow-button-label-inline'\n    )\n\n    /** @private */\n    this.nameSpan_ = document.createElement('span')\n    label.appendChild(this.nameSpan_)\n\n    /** @private */\n    this.currentState_ = document.createElement('span')\n    this.currentState_.classList.add('shaka-current-selection-span')\n    label.appendChild(this.currentState_)\n\n    this.button_.appendChild(label)\n\n    this.parent.appendChild(this.button_)\n\n    /** @private */\n    this.theatreModeEnabled_ = theatreModeEnabled\n\n    // listeners\n\n    this.eventManager.listen(this.button_, 'click', () => {\n      events.dispatchEvent(new CustomEvent('toggleTheatreMode', {\n        detail: !this.theatreModeEnabled_\n      }))\n    })\n\n    this.eventManager.listen(events, 'toggleTheatreMode', (/** @type {CustomEvent} */event) => {\n      this.theatreModeEnabled_ = event.detail\n\n      this.updateLocalisedStrings_()\n    })\n\n    this.eventManager.listen(events, 'localeChanged', () => {\n      this.updateLocalisedStrings_()\n    })\n\n    this.updateLocalisedStrings_()\n  }\n\n  /** @private */\n  updateLocalisedStrings_() {\n    this.icon_.use(this.theatreModeEnabled_ ? PlayerIcons.VARIABLES_DEFAULT : PlayerIcons.RECTANGLE_DEFAULT)\n\n    this.currentState_.textContent = this.localization.resolve(this.theatreModeEnabled_ ? 'ON' : 'OFF')\n\n    const baseAriaLabel = this.theatreModeEnabled_ ? i18n.global.t('Video.Player.Exit Theatre Mode') : i18n.global.t('Video.Player.Theatre Mode')\n\n    this.nameSpan_.textContent = this.button_.ariaLabel = addKeyboardShortcutToActionTitle(\n      baseAriaLabel,\n      KeyboardShortcuts.VIDEO_PLAYER.GENERAL.THEATRE_MODE\n    )\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/watch-video-playlist/watch-video-playlist.css",
    "content": ".playlistTitle {\n  text-overflow: ellipsis;\n  overflow: hidden;\n  white-space: nowrap;\n}\n\n.playlistTitleLink,\n.channelName {\n  text-decoration: none;\n  color: inherit;\n}\n\n.channelName {\n  font-size: 15px;\n  position: relative;\n  inset-block-end: 15px;\n}\n\n.playlistIndex {\n  position: relative;\n  inset-block-end: 15px;\n  color: var(--tertiary-text-color);\n}\n\n.playlistProgressBarContainer {\n  margin-inline-start: 10px;\n  position: relative;\n  padding-block: 8px;\n}\n\n.playlistProgressBar {\n  cursor: pointer;\n  background-color: var(--secondary-text-color);\n  block-size: 6px;\n  border-radius: 3px;\n  overflow: visible;\n  position: relative;\n  transition: block-size 0.2s ease, margin-block 0.2s ease;\n}\n\n.playlistProgressBar.expanded {\n  block-size: 12px;\n  margin-block: -3px;\n}\n\n.playlistProgressBarFill {\n  block-size: 100%;\n  background-color: var(--accent-color);\n  border-radius: inherit;\n  transition: inline-size 0.2s ease;\n}\n\n.progressBarPreview {\n  position: absolute;\n  inset-block-start: -65px;\n  transform: translateX(-50%);\n  z-index: 10;\n  pointer-events: none;\n}\n\n.previewTooltip {\n  background-color: var(--card-bg-color);\n  border: 1px solid var(--primary-border-color);\n  border-radius: 8px;\n  padding-block: 8px;\n  padding-inline: 12px;\n  font-size: 12px;\n  color: var(--primary-text-color);\n  white-space: nowrap;\n  box-shadow: 0 4px 12px rgb(0 0 0 / 50%);\n  margin-block-end: 4px;\n  display: grid;\n  grid-template:\n    'thumb index title' auto /\n    max-content max-content max-content;\n  align-items: center;\n  gap: 8px;\n}\n\n.previewThumbnail {\n  grid-area: thumb;\n  block-size: 36px;\n  inline-size: 48px;\n  object-fit: cover;\n  border-radius: 4px;\n}\n\n.previewText {\n  grid-area: index;\n}\n\n.previewVideoTitle {\n  grid-area: title;\n  font-weight: 400;\n  color: var(--secondary-text-color);\n  inline-size: 240px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  font-size: 11px;\n}\n\n.progressBarTick.current {\n  background-color: var(--accent-color);\n  opacity: 0.8;\n  inline-size: 3px;\n}\n\n.playlistProgressBar.expanded .progressBarTick {\n  opacity: 0.5;\n}\n\n.playlistProgressBar.expanded .progressBarTick.current {\n  opacity: 1;\n}\n\n.playlistButtons {\n  margin-block: 8px;\n}\n\n.playlistButton {\n  background-color: transparent;\n  font-size: 20px;\n  line-height: 1em;\n  padding: 10px;\n  margin-block-start: -25px;\n  cursor: pointer;\n  border-radius: 50%;\n  border-style: none;\n  color: var(--tertiary-text-color);\n  transition: background 0.2s ease-out;\n  stroke-width: 20;\n  stroke: var(--bg-color);\n}\n\n.playlistButton:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  stroke-width: 20;\n  stroke: var(--side-nav-hover-color);\n  transition: background 0.2s ease-in;\n}\n\n.playlistButtonActive {\n  color: var(--accent-color);\n  stroke-width: 10;\n  stroke: var(--accent-color);\n}\n\n.playlistButtonActive:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--accent-color-hover);\n  stroke-width: 10;\n  stroke: var(--accent-color-hover);\n  transition: background 0.2s ease-in;\n}\n\n.playlistIcon {\n  inline-size: 1em;\n}\n\n.playlistItemsWrapper {\n  overflow-y: auto;\n  block-size: 360px;\n}\n\n.playlistItem {\n  display: grid;\n  grid-template-columns: 30px 1fr;\n  align-items: center;\n  transition: background 0.2s ease-out;\n}\n\n.playlistItem:not(:last-child) {\n  margin-block-end: 8px;\n}\n\n.playlistItem:hover {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.videoInfo {\n  margin-inline-start: 30px;\n  position: relative;\n  inset-block-end: 7px;\n}\n\n@media only screen and (width <= 768px) {\n  .previewTooltip {\n    inline-size: auto;\n    padding: 6px;\n    grid-template:\n      'thumb index' auto\n      'title title' auto /\n      auto auto;\n    column-gap: 0;\n  }\n\n  .previewThumbnail {\n    inline-size: 32px;\n    block-size: 24px;\n  }\n\n  .previewText {\n    justify-self: start;\n  }\n\n  .previewVideoTitle {\n    inline-size: 200px;\n    text-align: center;\n  }\n}\n\n@media only screen and (width <= 500px) {\n  .previewVideoTitle {\n    inline-size: 150px;\n  }\n}\n\n/* The primary input mechanism does not include a pointing device or includes a pointing device of limited accuracy, such as a finger on a touchscreen. */\n@media (pointer: none), (pointer: coarse) {\n  .progressBarPreview {\n    display: none;\n  }\n\n  /* Show progress bar as always expanded */\n  .playlistProgressBar {\n    block-size: 12px;\n    margin-block: -3px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/components/watch-video-playlist/watch-video-playlist.js",
    "content": "import { defineComponent, nextTick } from 'vue'\nimport { mapMutations } from 'vuex'\nimport FtLoader from '../FtLoader/FtLoader.vue'\nimport FtCard from '../ft-card/ft-card.vue'\nimport FtListVideoNumbered from '../FtListVideoNumbered/FtListVideoNumbered.vue'\nimport { copyToClipboard, showToast } from '../../helpers/utils'\nimport {\n  getLocalCachedFeedContinuation,\n  getLocalPlaylist,\n  parseLocalPlaylistVideo,\n  untilEndOfLocalPlayList,\n} from '../../helpers/api/local'\nimport { invidiousGetPlaylistInfo } from '../../helpers/api/invidious'\nimport { getSortedPlaylistItems, SORT_BY_VALUES } from '../../helpers/playlists'\n\nexport default defineComponent({\n  name: 'WatchVideoPlaylist',\n  components: {\n    'ft-loader': FtLoader,\n    'ft-card': FtCard,\n    'ft-list-video-numbered': FtListVideoNumbered\n  },\n  props: {\n    playlistId: {\n      type: String,\n      required: true,\n    },\n    playlistType: {\n      type: String,\n      default: null\n    },\n    videoId: {\n      type: String,\n      required: true,\n    },\n    playlistItemId: {\n      type: String,\n      default: null,\n    },\n    watchViewLoading: {\n      type: Boolean,\n      required: true,\n    },\n  },\n  emits: ['pause-player'],\n  data: function () {\n    return {\n      isLoading: true,\n      shuffleEnabled: false,\n      loopEnabled: false,\n      reversePlaylist: false,\n      prevVideoBeforeDeletion: null,\n      channelName: '',\n      channelId: '',\n      playlistTitle: '',\n      playlistItems: [],\n      randomizedPlaylistItems: [],\n\n      getPlaylistInfoRun: false,\n      showProgressBarPreview: false,\n      previewPosition: 0,\n      previewVideoIndex: 1,\n      windowWidth: window.innerWidth,\n    }\n  },\n  computed: {\n    backendPreference: function () {\n      return this.$store.getters.getBackendPreference\n    },\n    backendFallback: function () {\n      return this.$store.getters.getBackendFallback\n    },\n    currentInvidiousInstanceUrl: function () {\n      return this.$store.getters.getCurrentInvidiousInstanceUrl\n    },\n\n    currentLocale: function () {\n      return this.$i18n.locale\n    },\n    isUserPlaylist: function () {\n      return this.playlistType === 'user'\n    },\n    userPlaylistsReady: function () {\n      return this.$store.getters.getPlaylistsReady\n    },\n    selectedUserPlaylist: function () {\n      if (this.playlistId == null || this.playlistId === '') { return null }\n\n      return this.$store.getters.getPlaylist(this.playlistId)\n    },\n    selectedUserPlaylistVideoCount () {\n      return this.selectedUserPlaylist?.videos?.length\n    },\n    selectedUserPlaylistLastUpdatedAt () {\n      return this.selectedUserPlaylist?.lastUpdatedAt\n    },\n\n    currentVideoIndexZeroBased: function () {\n      return this.findIndexOfCurrentVideoInPlaylist(this.playlistItems)\n    },\n    currentVideoIndexOneBased: function () {\n      return this.currentVideoIndexZeroBased + 1\n    },\n    currentVideo: function () {\n      return this.playlistItems[this.currentVideoIndexZeroBased]\n    },\n\n    playlistVideoCount: function () {\n      return this.playlistItems.length\n    },\n\n    shouldStopDueToPlaylistEnd: function () {\n      if (!this.videoIsLastInInPlaylistItems) { return false }\n\n      // Loop enabled = should not stop\n      return !this.loopEnabled\n    },\n\n    videoIsLastInInPlaylistItems: function () {\n      if (this.shuffleEnabled) {\n        return this.videoIndexInPlaylistItems === this.randomizedPlaylistItems.length - 1\n      } else {\n        return this.videoIndexInPlaylistItems === this.playlistItems.length - 1\n      }\n    },\n\n    videoIndexInPlaylistItems: function () {\n      const playlistItems = this.shuffleEnabled ? this.randomizedPlaylistItems : this.playlistItems\n      return this.findIndexOfCurrentVideoInPlaylist(playlistItems)\n    },\n    videoIsLastPlaylistItem: function () {\n      return this.videoIndexInPlaylistItems === (this.playlistItems.length - 1)\n    },\n    videoIsNotPlaylistItem: function () {\n      return this.videoIndexInPlaylistItems === -1\n    },\n\n    playlistPageLinkTo() {\n      // For `router-link` attribute `to`\n      return {\n        path: `/playlist/${this.playlistId}`,\n        query: {\n          playlistType: this.isUserPlaylist ? 'user' : '',\n        },\n      }\n    },\n    userPlaylistSortOrder: function () {\n      return this.$store.getters.getUserPlaylistSortOrder\n    },\n    sortOrder: function () {\n      return this.isUserPlaylist ? this.userPlaylistSortOrder : SORT_BY_VALUES.Custom\n    },\n\n    previewTransformXPercentage() {\n      // Breakpoint for single-column-template\n      if (this.windowWidth > 1050) {\n        // Align left when preview is on the right half to avoid going out of right side of the window\n        return this.previewPosition <= 50 ? -50 : -100\n      }\n\n      // Align left/right to avoid going out of either side of the window\n      return this.previewPosition <= 50 ? 0 : -100\n    },\n    previewVideoTitle: function () {\n      const index = this.previewVideoIndex - 1\n      if (index >= 0 && index < this.playlistItems.length) {\n        return this.playlistItems[index].title || 'Unknown Title'\n      }\n      return ''\n    },\n    previewVideoThumbnail: function () {\n      const index = this.previewVideoIndex - 1\n      if (index >= 0 && index < this.playlistItems.length) {\n        const videoId = this.playlistItems[index].videoId\n        if (videoId) {\n          let baseUrl = 'https://i.ytimg.com'\n          if (this.backendPreference === 'invidious') {\n            baseUrl = this.currentInvidiousInstanceUrl\n          }\n          return `${baseUrl}/vi/${videoId}/default.jpg`\n        }\n      }\n      return null\n    },\n    shouldShowTicks: function () {\n      // Only show ticks if <= 50 videos in playlist to avoid clutter\n      return this.playlistVideoCount <= 50\n    }\n  },\n  watch: {\n    userPlaylistsReady: function() {\n      this.getPlaylistInfoWithDelay()\n    },\n    selectedUserPlaylistVideoCount () {\n      // Re-fetch from local store when current user playlist updated\n      this.parseUserPlaylist(this.selectedUserPlaylist)\n      this.shufflePlaylistItems()\n    },\n    selectedUserPlaylistLastUpdatedAt () {\n      // Re-fetch from local store when current user playlist updated\n      this.parseUserPlaylist(this.selectedUserPlaylist)\n    },\n    videoId: function (newId, oldId) {\n      // Check if next video is from the shuffled list or if the user clicked a different video\n      if (this.shuffleEnabled) {\n        const newVideoIndex = this.randomizedPlaylistItems.findIndex((item) => {\n          return item.videoId === newId\n        })\n\n        const oldVideoIndex = this.randomizedPlaylistItems.findIndex((item) => {\n          return item.videoId === oldId\n        })\n\n        if ((newVideoIndex - 1) !== oldVideoIndex) {\n          // User clicked a different video than expected. Re-shuffle the list\n          this.shufflePlaylistItems()\n        }\n      }\n    },\n    playlistItemId: function () {\n      this.prevVideoBeforeDeletion = null\n    },\n    watchViewLoading: function (newVal, oldVal) {\n      // If watch view is loaded after this component loaded\n      if (oldVal && !newVal) {\n        // Scroll after watch view loaded, otherwise doesn't work\n        // Mainly for Local API\n        // `nextTick` is required (tested via reloading)\n        nextTick(() => this.scrollToCurrentVideo())\n      }\n    },\n    isLoading: function (newVal, oldVal) {\n      // This component is loaded/rendered before watch view loaded\n      if (oldVal && !newVal) {\n        // Scroll after this component loaded, otherwise doesn't work\n        // Mainly for Invidious API\n        // `nextTick` is required (tested via reloading)\n        nextTick(() => this.scrollToCurrentVideo())\n      }\n    },\n    playlistId: function (newVal, oldVal) {\n      if (oldVal !== newVal) {\n        if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') {\n          this.getPlaylistInformationInvidious()\n        } else {\n          this.getPlaylistInformationLocal()\n        }\n      }\n    },\n  },\n  mounted: function () {\n    const cachedPlaylist = this.$store.getters.getCachedPlaylist\n    if (cachedPlaylist?.id === this.playlistId) {\n      this.loadCachedPlaylistInformation(cachedPlaylist)\n    } else {\n      this.getPlaylistInfoWithDelay()\n    }\n\n    if ('mediaSession' in navigator) {\n      navigator.mediaSession.setActionHandler('previoustrack', this.playPreviousVideo)\n      navigator.mediaSession.setActionHandler('nexttrack', this.playNextVideo)\n    }\n\n    window.addEventListener('resize', this.calculateWindowWidth)\n  },\n  beforeUnmount: function () {\n    if ('mediaSession' in navigator) {\n      navigator.mediaSession.setActionHandler('previoustrack', null)\n      navigator.mediaSession.setActionHandler('nexttrack', null)\n    }\n\n    window.removeEventListener('resize', this.calculateWindowWidth)\n  },\n  methods: {\n    findIndexOfCurrentVideoInPlaylist: function (playlist) {\n      const playlistItemId = this.playlistItemId\n      const prevVideoBeforeDeletion = this.prevVideoBeforeDeletion\n      const videoId = this.videoId\n      return playlist.findIndex((item) => {\n        if (item.playlistItemId && (playlistItemId || prevVideoBeforeDeletion?.playlistItemId)) {\n          return item.playlistItemId === playlistItemId || item.playlistItemId === prevVideoBeforeDeletion?.playlistItemId\n        } else if (item.videoId) {\n          return item.videoId === videoId || item.videoId === prevVideoBeforeDeletion?.videoId\n        } else if (item.id) {\n          return item.id === videoId || item.id === prevVideoBeforeDeletion?.videoId\n        }\n\n        return false\n      })\n    },\n\n    getPlaylistInfoWithDelay: function () {\n      if (this.getPlaylistInfoRun) { return }\n\n      this.isLoading = true\n      // `selectedUserPlaylist` result accuracy relies on data being ready\n      if (this.isUserPlaylist && !this.userPlaylistsReady) { return }\n\n      this.getPlaylistInfoRun = true\n\n      if (this.selectedUserPlaylist != null) {\n        this.parseUserPlaylist(this.selectedUserPlaylist)\n      } else if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') {\n        this.getPlaylistInformationInvidious()\n      } else {\n        this.getPlaylistInformationLocal()\n      }\n    },\n\n    toggleLoop: function () {\n      if (this.loopEnabled) {\n        this.loopEnabled = false\n        showToast(this.$t('Loop is now disabled'))\n      } else {\n        this.loopEnabled = true\n        showToast(this.$t('Loop is now enabled'))\n      }\n    },\n\n    toggleShuffle: function () {\n      if (this.shuffleEnabled) {\n        this.shuffleEnabled = false\n        showToast(this.$t('Shuffle is now disabled'))\n      } else {\n        this.shuffleEnabled = true\n        showToast(this.$t('Shuffle is now enabled'))\n        this.shufflePlaylistItems()\n      }\n    },\n\n    toggleReversePlaylist: function () {\n      this.isLoading = true\n      showToast(this.$t('The playlist has been reversed'))\n\n      this.reversePlaylist = !this.reversePlaylist\n      // Create a new array to avoid changing array in data store state\n      // it could be user playlist or cache playlist\n      this.playlistItems = this.playlistItems.toReversed()\n      nextTick(() => {\n        this.isLoading = false\n      })\n    },\n\n    playNextVideo: function () {\n      const playlistInfo = {\n        playlistId: this.playlistId,\n        playlistType: this.playlistType,\n      }\n\n      const videoIndex = this.videoIndexInPlaylistItems\n      const targetVideoIndex = (this.videoIsNotPlaylistItem || this.videoIsLastPlaylistItem) ? 0 : videoIndex + 1\n      if (this.shuffleEnabled) {\n        let doShufflePlaylistItems = false\n        if (this.videoIsLastPlaylistItem && !this.loopEnabled) {\n          showToast(this.$t('The playlist has ended. Enable loop to continue playing'))\n          return\n        }\n        // loopEnabled = true\n        if (this.videoIsLastPlaylistItem || this.videoIsNotPlaylistItem) { doShufflePlaylistItems = true }\n\n        const targetPlaylistItem = this.randomizedPlaylistItems[targetVideoIndex]\n\n        this.$router.push(\n          {\n            path: `/watch/${targetPlaylistItem.videoId}`,\n            query: Object.assign(playlistInfo, { playlistItemId: targetPlaylistItem.playlistItemId }),\n          }\n        )\n        showToast(this.$t('Playing Next Video'))\n        if (doShufflePlaylistItems) { this.shufflePlaylistItems() }\n      } else {\n        const targetPlaylistItem = this.playlistItems[targetVideoIndex]\n\n        const stopDueToLoopDisabled = this.videoIsLastPlaylistItem && !this.loopEnabled\n        if (stopDueToLoopDisabled) {\n          showToast(this.$t('The playlist has ended. Enable loop to continue playing'))\n          return\n        }\n\n        this.$router.push(\n          {\n            path: `/watch/${targetPlaylistItem.videoId}`,\n            query: Object.assign(playlistInfo, { playlistItemId: targetPlaylistItem.playlistItemId }),\n          }\n        )\n        showToast(this.$t('Playing Next Video'))\n      }\n    },\n\n    playPreviousVideo: function () {\n      showToast(this.$t('Playing Previous Video'))\n\n      const playlistInfo = {\n        playlistId: this.playlistId,\n        playlistType: this.playlistType,\n      }\n\n      let videoIndex = this.videoIndexInPlaylistItems\n\n      /*\n      * When the current video being watched in the playlist is deleted,\n      * the previous video is shown as the \"current\" one.\n      * So if we want to play the previous video, in this case,\n      * we actually want to actually play the \"current\" video.\n      * The only exception is when shuffle is enabled, as we don't actually\n      * want to play the last sequential video with shuffle.\n      */\n      if (this.prevVideoBeforeDeletion && !this.shuffleEnabled) {\n        videoIndex++\n      }\n\n      // Wrap around to the end of the playlist only if there are no remaining earlier videos\n      const targetVideoIndex = (videoIndex === 0 || this.videoIsNotPlaylistItem) ? this.playlistItems.length - 1 : videoIndex - 1\n\n      if (this.shuffleEnabled) {\n        const targetPlaylistItem = this.randomizedPlaylistItems[targetVideoIndex]\n\n        this.$router.push(\n          {\n            path: `/watch/${targetPlaylistItem.videoId}`,\n            query: Object.assign(playlistInfo, { playlistItemId: targetPlaylistItem.playlistItemId }),\n          }\n        )\n      } else {\n        const targetPlaylistItem = this.playlistItems[targetVideoIndex]\n\n        this.$router.push(\n          {\n            path: `/watch/${targetPlaylistItem.videoId}`,\n            query: Object.assign(playlistInfo, { playlistItemId: targetPlaylistItem.playlistItemId }),\n          }\n        )\n      }\n    },\n\n    loadCachedPlaylistInformation: async function (cachedPlaylist) {\n      this.isLoading = true\n      this.getPlaylistInfoRun = true\n      this.setCachedPlaylist(null)\n\n      this.playlistTitle = cachedPlaylist.title\n      this.channelName = cachedPlaylist.channelName\n      this.channelId = cachedPlaylist.channelId\n\n      if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious' || cachedPlaylist.continuationData === null) {\n        this.playlistItems = cachedPlaylist.items\n      } else {\n        const videos = cachedPlaylist.items\n\n        const continuationData = await getLocalCachedFeedContinuation('playlist', cachedPlaylist.continuationData)\n        videos.push(...continuationData.items.map(parseLocalPlaylistVideo))\n\n        await untilEndOfLocalPlayList(continuationData, (p) => {\n          videos.push(...p.items.map(parseLocalPlaylistVideo))\n        }, { runCallbackOnceFirst: false })\n\n        this.playlistItems = videos\n      }\n\n      this.isLoading = false\n    },\n\n    getPlaylistInformationLocal: async function () {\n      this.isLoading = true\n\n      try {\n        const playlist = await getLocalPlaylist(this.playlistId)\n\n        let channelName\n\n        if (playlist.info.author) {\n          channelName = playlist.info.author.name\n        } else {\n          const subtitle = playlist.info.subtitle.toString()\n\n          const index = subtitle.lastIndexOf('•')\n          channelName = subtitle.substring(0, index).trim()\n        }\n\n        this.playlistTitle = playlist.info.title\n        this.channelName = channelName\n        this.channelId = playlist.info.author?.id\n\n        const videos = []\n        await untilEndOfLocalPlayList(playlist, (p) => {\n          videos.push(...p.items.map(parseLocalPlaylistVideo))\n        })\n\n        this.playlistItems = videos\n\n        this.isLoading = false\n      } catch (err) {\n        console.error(err)\n        const errorMessage = this.$t('Local API Error (Click to copy)')\n        showToast(`${errorMessage}: ${err}`, 10000, () => {\n          copyToClipboard(err)\n        })\n        if (this.backendPreference === 'local' && this.backendFallback) {\n          showToast(this.$t('Falling back to Invidious API'))\n          this.getPlaylistInformationInvidious()\n        } else {\n          this.isLoading = false\n        }\n      }\n    },\n\n    getPlaylistInformationInvidious: function () {\n      this.isLoading = true\n\n      invidiousGetPlaylistInfo(this.playlistId).then((result) => {\n        this.playlistTitle = result.title\n        this.channelName = result.author\n        this.channelId = result.authorId\n\n        this.playlistItems = this.playlistItems.concat(result.videos)\n\n        this.isLoading = false\n      }).catch((err) => {\n        console.error(err)\n        const errorMessage = this.$t('Invidious API Error (Click to copy)')\n        showToast(`${errorMessage}: ${err}`, 10000, () => {\n          copyToClipboard(err)\n        })\n        if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) {\n          showToast(this.$t('Falling back to Local API'))\n          this.getPlaylistInformationLocal()\n        } else {\n          this.isLoading = false\n          // TODO: Show toast with error message\n        }\n      })\n    },\n\n    parseUserPlaylist: function (playlist) {\n      this.playlistTitle = playlist.playlistName\n      this.channelName = ''\n      this.channelId = ''\n\n      const isCurrentVideoInParsedPlaylist = this.findIndexOfCurrentVideoInPlaylist(playlist.videos) !== -1\n      if (!isCurrentVideoInParsedPlaylist) {\n        // grab 2nd video if the 1st one is current & deleted\n        // or the prior video in the list before the current video's deletion\n        const targetVideoIndex = this.currentVideoIndexZeroBased - 1\n        this.prevVideoBeforeDeletion = targetVideoIndex >= 0 ? this.playlistItems[targetVideoIndex] : null\n      }\n\n      this.playlistItems = getSortedPlaylistItems(playlist.videos, this.sortOrder, this.currentLocale, this.reversePlaylist)\n\n      this.isLoading = false\n    },\n\n    shufflePlaylistItems: function () {\n      // Prevents the array from affecting the original object\n      const remainingItems = [].concat(this.playlistItems)\n      const items = []\n\n      if (this.currentVideo != null) {\n        items.push(this.currentVideo)\n        remainingItems.splice(this.currentVideoIndexZeroBased, 1)\n        // There is no else case\n        // If current video is absent in (removed from) the playlist, nothing should be changed\n      }\n\n      while (remainingItems.length > 0) {\n        const randomInt = Math.floor(Math.random() * remainingItems.length)\n\n        items.push(remainingItems[randomInt])\n        remainingItems.splice(randomInt, 1)\n      }\n\n      this.randomizedPlaylistItems = items\n    },\n\n    scrollToCurrentVideo: function () {\n      const container = this.$refs.playlistItemsWrapper\n      const currentVideoItemEl = container ? Array.from(container.children)[this.currentVideoIndexZeroBased] : null\n      if (container != null && currentVideoItemEl != null) {\n        // Watch view can be ready sooner than this component\n        container.scrollTop = currentVideoItemEl.offsetTop - container.offsetTop\n      }\n    },\n\n    pausePlayer: function () {\n      this.$emit('pause-player')\n    },\n\n    updateProgressBarPreview: function (event) {\n      if (!this.showProgressBarPreview) return\n\n      const rect = this.$refs.playlistProgressBar.getBoundingClientRect()\n      const mouseX = event.clientX - rect.left\n      const progressBarWidth = rect.width\n      const percentage = Math.max(0, Math.min(100, (mouseX / progressBarWidth) * 100))\n\n      this.previewPosition = percentage\n      this.previewVideoIndex = Math.max(1, Math.min(this.playlistVideoCount, Math.ceil((percentage / 100) * this.playlistVideoCount)))\n    },\n\n    handleProgressBarClick: function (event) {\n      const rect = event.currentTarget.getBoundingClientRect()\n      const clickX = event.clientX - rect.left\n      const progressBarWidth = rect.width\n      const clickPercentage = clickX / progressBarWidth\n\n      const targetVideoIndex = Math.max(1, Math.min(this.playlistVideoCount, Math.ceil(clickPercentage * this.playlistVideoCount)))\n      const targetArrayIndex = targetVideoIndex - 1\n\n      if (targetArrayIndex >= 0 && targetArrayIndex < this.playlistItems.length) {\n        const container = this.$refs.playlistItemsWrapper\n        const targetPlaylistItemEl = container ? Array.from(container.children)[targetArrayIndex] : null\n        if (container != null && targetPlaylistItemEl != null) {\n          // Watch view can be ready sooner than this component\n          container.scrollTop = targetPlaylistItemEl.offsetTop - container.offsetTop\n        }\n      }\n    },\n\n    calculateWindowWidth() {\n      this.windowWidth = window.innerWidth\n    },\n\n    ...mapMutations([\n      'setCachedPlaylist'\n    ])\n  }\n})\n"
  },
  {
    "path": "src/renderer/components/watch-video-playlist/watch-video-playlist.vue",
    "content": "<template>\n  <ft-card class=\"relative\">\n    <ft-loader\n      v-if=\"isLoading\"\n    />\n    <div\n      v-else\n    >\n      <h3\n        class=\"playlistTitle\"\n        :title=\"playlistTitle\"\n      >\n        <router-link\n          class=\"playlistTitleLink\"\n          dir=\"auto\"\n          :to=\"playlistPageLinkTo\"\n        >\n          {{ playlistTitle }}\n        </router-link>\n      </h3>\n      <template\n        v-if=\"channelName !== ''\"\n      >\n        <router-link\n          v-if=\"channelId\"\n          class=\"channelName\"\n          dir=\"auto\"\n          :to=\"`/channel/${channelId}`\"\n        >\n          {{ channelName }} -\n        </router-link>\n        <bdi\n          v-else\n          class=\"channelName\"\n        >\n          {{ channelName }} -\n        </bdi>\n      </template>\n      <span\n        class=\"playlistIndex\"\n      >\n        <label for=\"playlistProgressBar\">\n          {{ currentVideoIndexOneBased }} / {{ playlistVideoCount }}\n        </label>\n\n        <!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events, vuejs-accessibility/click-events-have-key-events -->\n        <div\n          v-if=\"!shuffleEnabled && !reversePlaylist\"\n          class=\"playlistProgressBarContainer\"\n          @mouseenter=\"showProgressBarPreview = true\"\n          @mouseleave=\"showProgressBarPreview = false\"\n          @mousemove=\"updateProgressBarPreview\"\n        >\n          <div\n            ref=\"playlistProgressBar\"\n            class=\"playlistProgressBar\"\n            :class=\"{ expanded: showProgressBarPreview }\"\n            @click=\"handleProgressBarClick\"\n          >\n            <div\n              class=\"playlistProgressBarFill\"\n              :style=\"{ width: (currentVideoIndexOneBased / playlistVideoCount) * 100 + '%' }\"\n            />\n            <div\n              v-if=\"showProgressBarPreview\"\n              class=\"progressBarPreview\"\n              :style=\"{ left: previewPosition + '%', transform: `translateX(${ previewTransformXPercentage }%)` }\"\n            >\n              <div class=\"previewTooltip\">\n                <img\n                  v-if=\"previewVideoThumbnail\"\n                  :src=\"previewVideoThumbnail\"\n                  alt=\"\"\n                  class=\"previewThumbnail\"\n                >\n                <div class=\"previewText\">\n                  {{ previewVideoIndex }} / {{ playlistVideoCount }}\n                </div>\n                <div\n                  class=\"previewVideoTitle\"\n                  dir=\"auto\"\n                >{{ previewVideoTitle }}</div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </span>\n      <div class=\"playlistButtons\">\n        <button\n          class=\"playlistButton\"\n          :class=\"{ playlistButtonActive: loopEnabled }\"\n          :aria-label=\"$t('Video.Loop Playlist')\"\n          :aria-pressed=\"loopEnabled\"\n          :title=\"$t('Video.Loop Playlist')\"\n          @click=\"toggleLoop\"\n        >\n          <font-awesome-icon\n            class=\"playlistIcon\"\n            :icon=\"['fas', 'retweet']\"\n          />\n        </button>\n        <button\n          class=\"playlistButton\"\n          :class=\"{ playlistButtonActive: shuffleEnabled }\"\n          :aria-label=\"$t('Video.Shuffle Playlist')\"\n          :aria-pressed=\"shuffleEnabled\"\n          :title=\"$t('Video.Shuffle Playlist')\"\n          @click=\"toggleShuffle\"\n        >\n          <font-awesome-icon\n            class=\"playlistIcon\"\n            :icon=\"['fas', 'random']\"\n          />\n        </button>\n        <button\n          class=\"playlistButton\"\n          :class=\"{ playlistButtonActive: reversePlaylist }\"\n          :aria-label=\"$t('Video.Reverse Playlist')\"\n          :aria-pressed=\"reversePlaylist\"\n          :title=\"$t('Video.Reverse Playlist')\"\n          @click=\"toggleReversePlaylist\"\n        >\n          <font-awesome-icon\n            class=\"playlistIcon\"\n            :icon=\"['fas', 'exchange-alt']\"\n          />\n        </button>\n      </div>\n      <div\n        v-if=\"!isLoading\"\n        ref=\"playlistItemsWrapper\"\n        class=\"playlistItemsWrapper\"\n      >\n        <ft-list-video-numbered\n          v-for=\"(item, index) in playlistItems\"\n          :key=\"item.playlistItemId || item.videoId\"\n          ref=\"playlistItem\"\n          class=\"playlistItem\"\n          :data=\"item\"\n          :playlist-id=\"playlistId\"\n          :playlist-type=\"playlistType\"\n          :playlist-index=\"reversePlaylist ? playlistItems.length - index - 1 : index\"\n          :playlist-item-id=\"item.playlistItemId\"\n          :playlist-reverse=\"reversePlaylist\"\n          :playlist-shuffle=\"shuffleEnabled\"\n          :playlist-loop=\"loopEnabled\"\n          :video-index=\"index\"\n          :is-current-video=\"currentVideoIndexZeroBased === index\"\n          appearance=\"watchPlaylistItem\"\n          :initial-visible-state=\"index < (currentVideoIndexZeroBased + 4) && index > (currentVideoIndexZeroBased - 4)\"\n          @pause-player=\"pausePlayer\"\n        />\n      </div>\n    </div>\n  </ft-card>\n</template>\n\n<script src=\"./watch-video-playlist.js\" />\n<style scoped src=\"./watch-video-playlist.css\" />\n"
  },
  {
    "path": "src/renderer/composables/colors.js",
    "content": "import { computed } from 'vue'\nimport { useI18n } from './use-i18n-polyfill'\n\nexport function useColorTranslations() {\n  const { t } = useI18n()\n\n  return computed(() => [\n    t('Settings.Theme Settings.Main Color Theme.Red'),\n    t('Settings.Theme Settings.Main Color Theme.Pink'),\n    t('Settings.Theme Settings.Main Color Theme.Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Deep Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Indigo'),\n    t('Settings.Theme Settings.Main Color Theme.Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Light Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Cyan'),\n    t('Settings.Theme Settings.Main Color Theme.Teal'),\n    t('Settings.Theme Settings.Main Color Theme.Green'),\n    t('Settings.Theme Settings.Main Color Theme.Light Green'),\n    t('Settings.Theme Settings.Main Color Theme.Lime'),\n    t('Settings.Theme Settings.Main Color Theme.Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Amber'),\n    t('Settings.Theme Settings.Main Color Theme.Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Deep Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Rosewater'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Flamingo'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Pink'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Mauve'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Red'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Maroon'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Peach'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Green'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Teal'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Sky'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Sapphire'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Frappe Lavender'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Latte Mauve'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Latte Red'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Rosewater'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Flamingo'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Pink'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Mauve'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Red'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Maroon'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Peach'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Green'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Teal'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Sky'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Sapphire'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Lavender'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Cyan'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Green'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Pink'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Red'),\n    t('Settings.Theme Settings.Main Color Theme.Dracula Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Red'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Green'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Aqua'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Dark Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Red'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Green'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Aqua'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Everforest Light Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Green'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Aqua'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Dark Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Light Red'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Light Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Light Purple'),\n    t('Settings.Theme Settings.Main Color Theme.Gruvbox Light Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Yellow'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Orange'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Red'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Magenta'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Violet'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Blue'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Cyan'),\n    t('Settings.Theme Settings.Main Color Theme.Solarized Green'),\n  ])\n}\n"
  },
  {
    "path": "src/renderer/composables/use-i18n-polyfill.js",
    "content": "/* eslint-disable @intlify/vue-i18n/no-dynamic-keys */\nimport { computed } from 'vue'\n\nimport i18n from '../i18n/index'\n\n/**\n * Polyfill for vue-i18n's useI18n composable, as it is not available in Vue 2\n * and doesn't work when vue-i18n 9+ (used for Vue 3) is set to `legacy: true`,\n * which is needed for Options API components.\n *\n * Yes, vue-i18n 9 has an `allowComposition` option,\n * but it comes with limitations that this polyfill doesn't have and was removed in vue-i18n 10.\n *\n * @see https://vue-i18n.intlify.dev/guide/migration/vue3#limitations\n * @see https://vue-i18n.intlify.dev/guide/migration/breaking10.html#drop-allowcomposition-option\n */\nexport function useI18n() {\n  const locale = computed({\n    get() {\n      return i18n.global.locale\n    },\n    set(locale) {\n      i18n.global.locale = locale\n    }\n  })\n\n  return {\n    locale,\n    t\n  }\n}\n\n/**\n * @overload\n * @param {string} key\n * @returns {string}\n */\n\n/**\n * @overload\n * @param {string} key\n * @param {number} plural\n * @returns {string}\n */\n\n/**\n * @overload\n * @param {string} key\n * @param {unknown[]} list\n * @returns {string}\n */\n\n/**\n * @overload\n * @param {string} key\n * @param {unknown[]} list\n * @param {number} plural\n * @returns {string}\n */\n\n/**\n * @overload\n * @param {string} key\n * @param {Record<string, unknown>} named\n * @returns {string}\n */\n\n/**\n * @overload\n * @param {string} key\n * @param {Record<string, unknown>} named\n * @param {number} plural\n * @returns {string}\n */\n\n/**\n * @param {...any} args\n * @returns {string}\n */\nfunction t(...args) {\n  return i18n.global.t(...args)\n}\n"
  },
  {
    "path": "src/renderer/directives/vSaferHtml.js",
    "content": "import DOMPurify from 'dompurify'\n\nconst USE_NATIVE_SANITIZER = process.env.IS_ELECTRON || ('Sanitizer' in window && typeof HTMLElement.prototype.setHTML === 'function')\n\nlet sanitizer\n/** @type {import('dompurify').Config | undefined} */\nlet domPurifyStrictConfig\n\n/** @type {import('vue').FunctionDirective<HTMLElement, string, 'lenient'>} */\nexport const vSaferHtml = (element, { value, oldValue, modifiers }) => {\n  if (oldValue === null || value !== oldValue) {\n    if (modifiers.lenient) {\n      // Use the default browser sanitizer configuration e.g. for the changelog\n      if (USE_NATIVE_SANITIZER) {\n        element.setHTML(value)\n      } else {\n        element.innerHTML = DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false })\n      }\n    } else if (USE_NATIVE_SANITIZER) {\n      // Use a much stricter sanitzer configuration, should be used in most places\n      if (sanitizer === undefined) {\n        sanitizer = new Sanitizer({\n          comments: false,\n          elements: [\n            'br',\n            'b',\n            'i',\n            's',\n            {\n              name: 'a',\n              attributes: ['data-time', 'dir', 'href', 'lang', 'tabindex']\n            },\n            // live chat emojis (see parseLocalTextRuns)\n            {\n              name: 'img',\n              attributes: ['alt', 'height', 'loading', 'src', 'style', 'title', 'width']\n            }\n          ]\n        })\n      }\n\n      element.setHTML(value, { sanitizer })\n    } else {\n      if (domPurifyStrictConfig === undefined) {\n        domPurifyStrictConfig = {\n          ALLOWED_TAGS: ['br', 'b', 'i', 's', 'a', 'img'],\n          ALLOWED_ATTR: ['alt', 'data-time', 'dir', 'height', 'href', 'lang', 'loading', 'src', 'style', 'tabindex', 'title', 'width']\n        }\n      }\n\n      element.innerHTML = DOMPurify.sanitize(value, domPurifyStrictConfig)\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/fontawesome-minimal.js",
    "content": "// https://docs.fontawesome.com/apis/javascript/plugins\n// As FontAwesome doesn't provide types for the plugins entrypoint the types are manually applied to each export\n\nimport { register, Layers, ReplaceElements } from '@fortawesome/fontawesome-svg-core/plugins'\n\n// the `icon` function is inside the ReplaceElements plugin\nconst api = register([Layers, ReplaceElements])\n\n/** @type {import('@fortawesome/fontawesome-svg-core').Library} */\nexport const library = api.library\n\n// used by the FontAwesomeIcon component\n\n/** @type {import('@fortawesome/fontawesome-svg-core')['parse']} */\nexport const parse = api.parse\n/** @type {import('@fortawesome/fontawesome-svg-core')['icon']} */\nexport const icon = api.icon\n\n// used by the FontAwesomeLayers component\n/** @type {import('@fortawesome/fontawesome-svg-core')['config']} */\nexport const config = api.config\n\n// used by the FontAwesomeLayersText component, which we don't use but we have to specify this here\n// to make webpack happy (imports are processed before unused code is removed)\nexport const text = () => { }\n"
  },
  {
    "path": "src/renderer/helpers/api/PlayerCache.js",
    "content": "export class PlayerCache {\n  async get(key) {\n    return await window.ftElectron.playerCacheGet(key)\n  }\n\n  async set(key, value) {\n    await window.ftElectron.playerCacheSet(key, value)\n  }\n\n  async remove(_key) {\n    // no-op; YouTube.js only uses remove for the OAuth credentials, but we don't use that in FreeTube\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/api/invidious.js",
    "content": "import store from '../../store/index'\nimport { calculatePublishedDate, getRelativeTimeFromDate } from '../utils'\nimport { isNullOrEmpty } from '../strings'\nimport autolinker from 'autolinker'\nimport { FormatUtils, Misc, Player } from 'youtubei.js'\n\n/** @typedef {{url: string, width: number, height: number}} InvidiousImageObject */\n/** @typedef {{quality: string, url: string, width: number, height: number}} InvidiousThumbnailObject */\n/** @typedef {{type: 'video', title: string, videoId: string, author: string, authorId: string, authorUrl: string, authorVerified: boolean, videoThumbnails: InvidiousThumbnailObject[], description: string?, descriptionHtml: string?, viewCount: number, viewCountText: string, lengthSeconds: number, published: number, publishedText: string, premiereTimestamp: number, liveNow: boolean, premium: boolean, isUpcoming: boolean, hasCaptions: boolean, is3d: boolean, is4k: boolean, is8k: boolean, isNew: boolean, isVr180: boolean, isVr360: boolean}} InvidiousVideoType */\n/** @typedef {{type: 'channel', author: string, authorId: string, authorUrl: string, authorVerified: boolean, authorThumbnails: InvidiousThumbnailObject[], autoGenerated: boolean, subCount: number, videoCount: number, description: string, descriptionHtml: string}} InvidiousChannelObject */\n/** @typedef {{type: 'playlist', title: string, playlistId: string, playlistThumbnail: string, author: string, authorId: string, authorUrl: string, authorVerified: boolean, videoCount: number, videos: {title: string, videoId: string, lengthSeconds: number, videoThumbnails: InvidiousThumbnailObject[]}[]}} InvidiousPlaylistObject */\n/** @typedef {{type: 'hashtag', title: string, url: string, channelCount: number, videoCount: number}} InvidiousHashtagObject */\n\n/**\n * @returns {string}\n */\nfunction getCurrentInstanceUrl() {\n  return store.getters.getCurrentInvidiousInstanceUrl\n}\n\n/**\n * @param {string} uri\n */\nexport function getProxyUrl(uri) {\n  const currentInstance = getCurrentInstanceUrl()\n\n  const url = new URL(uri)\n  const { origin } = url\n  if (!url.searchParams.has('host') && origin !== currentInstance) {\n    // invidious requires host param to be filled with the origin of the stream\n    url.searchParams.append('host', origin.replace('https://', ''))\n  }\n  return url.toString().replace(origin, currentInstance)\n}\n\n/**\n * @param {string | URL} url\n */\nexport function invidiousFetch(url) {\n  const authorization = store.getters.getCurrentInvidiousInstanceAuthorization\n\n  if (authorization) {\n    return fetch(url, {\n      headers: {\n        Authorization: authorization\n      }\n    })\n  } else {\n    return fetch(url)\n  }\n}\n\nfunction invidiousAPICall({ resource, id = '', params = {}, doLogError = true, subResource = '' }) {\n  return new Promise((resolve, reject) => {\n    const requestUrl = getCurrentInstanceUrl() + '/api/v1/' + resource + '/' + id + (!isNullOrEmpty(subResource) ? `/${subResource}` : '') + '?' + new URLSearchParams(params).toString()\n    invidiousFetch(requestUrl)\n      .then((response) => response.json())\n      .then((json) => {\n        if (json.error !== undefined) {\n          // community is empty, no need to display error.\n          // This code can be removed when: https://github.com/iv-org/invidious/issues/3814 is reolved\n          if (json.error === 'This channel hasn\\'t posted yet') {\n            resolve({ comments: [] })\n          } else {\n            throw new Error(json.error)\n          }\n        }\n        resolve(json)\n      })\n      .catch((error) => {\n        if (doLogError) {\n          console.error('Invidious API error', requestUrl, error)\n        }\n        reject(error)\n      })\n  })\n}\n\nasync function resolveUrl(url) {\n  return await invidiousAPICall({\n    resource: 'resolveurl',\n    params: {\n      url\n    },\n    doLogError: false\n  })\n}\n\n/**\n * Gets the channel ID for a channel URL\n * used to get the ID for channel usernames and handles\n * @param {string} url\n * @returns {Promise<string?>} channel ID\n */\nexport async function invidiousGetChannelId(url) {\n  try {\n    const response = await resolveUrl(url)\n\n    if (response.pageType === 'WEB_PAGE_TYPE_CHANNEL') {\n      return response.ucid\n    } else {\n      return null\n    }\n  } catch {\n    return null\n  }\n}\n\n/**\n * @param {string} channelId\n * @returns {Promise<{\n *  author: string,\n *  authorId: string,\n *  authorUrl: string,\n *  authorVerified: boolean,\n *  authorBanners: InvidiousImageObject[],\n *  authorThumbnails: InvidiousImageObject[],\n *  subCount: number,\n *  totalViews: number,\n *  joined: number,\n *  autoGenerated: boolean,\n *  isFamilyFriendly: boolean,\n *  description: string,\n *  descriptionHtml: string,\n *  allowedRegions: string[],\n *  tabs: ('home' | 'videos' | 'shorts' | 'live' | 'podcasts' | 'releases' | 'courses' | 'playlists' | 'community')[],\n *  latestVideos: InvidiousVideoType[],\n *  relatedChannels: InvidiousChannelObject[]\n * }>}\n */\nexport async function invidiousGetChannelInfo(channelId) {\n  const channelInfo = await invidiousAPICall({\n    resource: 'channels',\n    id: channelId,\n  })\n\n  channelInfo.tabs = channelInfo.tabs.map(tab => {\n    if (tab === 'streams') return 'live'\n    if (tab === 'posts') return 'community'\n    return tab\n  })\n\n  return channelInfo\n}\n\n/**\n * @param {string} tab\n * @param {string} channelId\n * @param {string | undefined | null} continuation\n * @param {string | undefined} sortBy\n */\nasync function getInvidiousChannelTab(tab, channelId, continuation, sortBy) {\n  const params = {}\n\n  if (continuation) {\n    params.continuation = continuation\n  }\n\n  if (sortBy) {\n    params.sort_by = sortBy\n  }\n\n  return await invidiousAPICall({\n    resource: 'channels',\n    id: channelId,\n    subResource: tab,\n    params\n  })\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined} sortBy\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelVideos(channelId, sortBy, continuation) {\n  /** @type {{continuation: string?, videos: InvidiousVideoType[]}}  */\n  const response = await getInvidiousChannelTab('videos', channelId, continuation, sortBy)\n\n  normalizeManyInvidiousVideosAttributes(response.videos, channelId)\n  setMultiplePublishedTimestamps(response.videos)\n\n  return response\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined} sortBy\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelShorts(channelId, sortBy, continuation) {\n  /** @type {{continuation: string?, videos: InvidiousVideoType[]}}  */\n  const response = await getInvidiousChannelTab('shorts', channelId, continuation, sortBy)\n\n  // workaround for Invidious sending incorrect information\n  // https://github.com/iv-org/invidious/issues/3801\n  response.videos.forEach(video => {\n    video.isUpcoming = false\n    delete video.published\n    delete video.premiereTimestamp\n  })\n\n  return response\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined} sortBy\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelLive(channelId, sortBy, continuation) {\n  /** @type {{continuation: string?, videos: InvidiousVideoType[]}}  */\n  const response = await getInvidiousChannelTab('streams', channelId, continuation, sortBy)\n\n  normalizeManyInvidiousVideosAttributes(response.videos, channelId)\n  setMultiplePublishedTimestamps(response.videos)\n\n  return response\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined} sortBy\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelPlaylists(channelId, sortBy, continuation) {\n  /** @type {{continuation: string?, playlists: InvidiousPlaylistObject[]}} */\n  return await getInvidiousChannelTab('playlists', channelId, continuation, sortBy)\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelReleases(channelId, continuation) {\n  /** @type {{continuation: string?, playlists: InvidiousPlaylistObject[]}} */\n  return await getInvidiousChannelTab('releases', channelId, continuation)\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelPodcasts(channelId, continuation) {\n  /** @type {{continuation: string?, playlists: InvidiousPlaylistObject[]}} */\n  return await getInvidiousChannelTab('podcasts', channelId, continuation)\n}\n\n/**\n * @param {string} channelId\n * @param {string | undefined | null} continuation\n */\nexport async function getInvidiousChannelCourses(channelId, continuation) {\n  /** @type {{continuation: string?, playlists: InvidiousPlaylistObject[]}} */\n  return await getInvidiousChannelTab('courses', channelId, continuation)\n}\n\n/**\n * @param {string} channelId\n * @param {string} query\n * @param {number} page\n */\nexport async function searchInvidiousChannel(channelId, query, page) {\n  /** @type {(InvidiousVideoType | InvidiousPlaylistObject)[]} */\n  const response = await invidiousAPICall({\n    resource: 'channels',\n    id: channelId,\n    subResource: 'search',\n    params: {\n      q: query,\n      page\n    }\n  })\n\n  response.forEach((item) => {\n    if (item.type === 'video') {\n      normalizeOneInvidiousVideoAttributes(item, channelId)\n      setPublishedTimestamp(item)\n    }\n  })\n\n  return response\n}\n\n/**\n * @param {string} playlistId\n * @returns {Promise<{\n *  title: string,\n *  playlistId: string,\n *  author: string,\n *  authorId: string,\n *  authorThumbnails: InvidiousImageObject[],\n *  description: string,\n *  descriptionHtml: string,\n *  videoCount: number,\n *  viewCount: number,\n *  updated: number,\n *  videos: {\n *    title: string,\n *    videoId: string,\n *    author: string,\n *    authorId: string,\n *    authorUrl: string,\n *    videoThumbnails: InvidiousThumbnailObject[],\n *    index: number,\n *    lengthSeconds: number\n *  }[]\n * }>}\n */\nexport async function invidiousGetPlaylistInfo(playlistId) {\n  const playlist = await invidiousAPICall({\n    resource: 'playlists',\n    id: playlistId,\n  })\n\n  normalizeManyInvidiousVideosAttributes(playlist.videos)\n  setMultiplePublishedTimestamps(playlist.videos)\n\n  return playlist\n}\n\n/**\n * @param {string} videoId\n * @returns {Promise<{\n *  error: string,\n *  type: 'video' | 'published',\n *  title: string,\n *  videoId: string,\n *  videoThumbnails: InvidiousThumbnailObject[],\n *  storyboards: {\n *    url: string,\n *    templateUrl: string,\n *    width: number,\n *    height: number,\n *    count: number,\n *    interval: number,\n *    storyboardWidth: number,\n *    storyboardHeight: number,\n *    storyboardCount: number\n *  }[],\n *  description: string,\n *  descriptionHtml: string,\n *  published: number,\n *  publishedText: string,\n *  keywords: string[],\n *  viewCount: number,\n *  likeCount: number,\n *  dislikeCount: number,\n *  paid: boolean,\n *  premium: boolean,\n *  isFamilyFriendly: boolean,\n *  allowedRegions: string[],\n *  genre: string,\n *  genreUrl: string,\n *  author: string,\n *  authorId: string\n *  authorUrl: string,\n *  authorThumbnails: InvidiousImageObject[],\n *  subCountText: string,\n *  lengthSeconds: number,\n *  allowRatings: boolean,\n *  rating: number,\n *  isListed: boolean,\n *  liveNow: boolean,\n *  isPostLiveDvr: boolean,\n *  isUpcoming: boolean,\n *  dashUrl: string,\n *  premiereTimestamp: number?,\n *  hlsUrl: string?,\n *  adaptiveFormats: {\n *    index: string,\n *    bitrate: string,\n *    init: string,\n *    url: string,\n *    itag: string,\n *    type; string,\n *    clen: string,\n *    lmt: string,\n *    projectionType: string,\n *    container: string,\n *    encoding: string,\n *    qualityLabel: string?,\n *    fps: number?,\n *    size: string?,\n *    resolution: string?,\n *    targetDurationSec: int?,\n *    maxDvrDurationSec: int?,\n *    audioQuality: string?,\n *    audioSampleRate: string?,\n *    audioChannels: string?,\n *    colorInfo: string?,\n *    captionTrack: string?\n *  }[],\n *  formatStreams: {\n *    url: string,\n *    itag: string,\n *    type: string,\n *    quality: string,\n *    bitrate: string?,\n *    fps: int?,\n *    container: string,\n *    encoding: string,\n *    qualityLabel: string,\n *    resolution: string,\n *    size: string\n *  }[],\n *  captions: {\n *    label: string,\n *    language_code: string,\n *    url: string\n *  }[],\n *  musicTracks: {\n *    song: string,\n *    artist: string,\n *    album: string,\n *    license: string\n *  }[]?,\n *  recommendedVideos: InvidiousVideoType[]\n * }>}\n */\nexport async function invidiousGetVideoInformation(videoId) {\n  return await invidiousAPICall({\n    resource: 'videos',\n    id: videoId,\n  })\n}\n\n/**\n * The complete Triforce, or one or more components of the Triforce.\n * @typedef {object} InvidiousComment\n * @property {string} id\n * @property {string} authorLink\n * @property {string} authorThumb\n * @property {string} author\n * @property {number} likes\n * @property {string} text\n * @property {string} dataType\n * @property {boolean} isOwner\n * @property {boolean} isPinned\n * @property {number} numReplies\n * @property {boolean} hasReplyToken\n * @property {string} replyToken\n * @property {boolean} showReplies\n * @property {InvidiousComment[]} replies\n * @property {boolean} isHearted\n * @property {boolean} isMember\n * @property {string} memberIconUrl\n * @property {string} time\n */\n/** @typedef {{commentCount: number, videoId: string, continuation: string?, comments: InvidiousComment[]}} InvidiousCommentResponse */\n\nexport async function invidiousGetComments({ id, nextPageToken = '', sortNewest = true }) {\n  const payload = {\n    resource: 'comments',\n    id: id,\n    params: {\n      continuation: nextPageToken ?? '',\n      sort_by: sortNewest ? 'new' : 'top'\n    }\n  }\n\n  /** @type {InvidiousCommentResponse} */\n  const response = await invidiousAPICall(payload)\n\n  const commentData = parseInvidiousCommentData(response)\n\n  return { response, commentData }\n}\n\nexport async function invidiousGetCommentReplies({ id, replyToken }) {\n  const payload = {\n    resource: 'comments',\n    id: id,\n    params: {\n      continuation: replyToken\n    }\n  }\n\n  const response = await invidiousAPICall(payload)\n  return { commentData: parseInvidiousCommentData(response), continuation: response.continuation ?? null }\n}\n\n/**\n * @param {string} query\n * @returns {Promise<{ query: string, suggestions: string[]}>}\n */\nexport async function getInvidiousSearchSuggestions(query) {\n  return await invidiousAPICall({\n    resource: 'search/suggestions',\n    id: '',\n    params: {\n      q: query\n    }\n  })\n}\n\n/**\n * @returns {Promise<{\n *  type: 'shortVideo',\n *  title: string,\n *  videoId: string,\n *  videoThumbnails: InvidiousThumbnailObject[],\n *  lengthSeconds: number,\n *  viewCount: number,\n *  author: string,\n *  authorId: string,\n *  authorUrl: string,\n *  published: number,\n *  publishedText: string\n * }[]>}\n */\nexport async function getInvidiousPopularFeed() {\n  const response = await invidiousAPICall({\n    resource: 'popular',\n    id: '',\n    params: {}\n  })\n\n  const items = response.filter((item) => {\n    return item.type === 'video' || item.type === 'shortVideo' || item.type === 'channel' || item.type === 'playlist'\n  })\n\n  items.forEach((item) => {\n    if (item.type === 'video' || item.type === 'shortVideo') {\n      normalizeOneInvidiousVideoAttributes(item)\n      setPublishedTimestamp(item)\n    }\n  })\n\n  return items\n}\n\n/**\n * @param {string} query\n * @param {number} page\n * @param {any} searchSettings\n */\nexport async function getInvidiousSearchResults(query, page, searchSettings) {\n  /** @type {Promise<(InvidiousChannelObject | InvidiousPlaylistObject | InvidiousVideoType | InvidiousHashtagObject)[] | null>} */\n  let results = await invidiousAPICall({\n    resource: 'search',\n    id: '',\n    params: {\n      q: query,\n      page,\n      sort_by: searchSettings.sortBy,\n      date: searchSettings.time,\n      duration: searchSettings.duration,\n      type: searchSettings.type,\n      features: searchSettings.features.join(',')\n    }\n  })\n\n  if (!results) {\n    return null\n  }\n\n  results = results.filter((item) => {\n    return item.type === 'video' || item.type === 'channel' || item.type === 'playlist' || item.type === 'hashtag'\n  })\n\n  results.forEach((item) => {\n    if (item.type === 'video') {\n      normalizeOneInvidiousVideoAttributes(item)\n      setPublishedTimestamp(item)\n    }\n  })\n\n  return results\n}\n\n/**\n * @param {string} url\n * @param {string?} currentInstance\n * @returns {string?}\n */\nexport function youtubeImageUrlToInvidious(url, currentInstance = null) {\n  if (url == null) {\n    return null\n  }\n\n  if (currentInstance === null) {\n    currentInstance = getCurrentInstanceUrl()\n  }\n  // Can be prefixed with `https://` or `//` (protocol relative)\n  if (url.startsWith('//')) {\n    url = 'https:' + url\n  }\n  const newUrl = `${currentInstance}/ggpht`\n  return url.replace('https://yt3.ggpht.com', newUrl)\n    .replace('https://yt3.googleusercontent.com', newUrl)\n    .replace(/https:\\/\\/i\\d*\\.ytimg\\.com/, newUrl)\n}\n\n/**\n * @param {string} url\n * @param {string?} currentInstance\n * @returns {string}\n */\nexport function invidiousImageUrlToInvidious(url, currentInstance = null) {\n  return url.replaceAll('/ggpht/', `${currentInstance}/ggpht/`)\n}\n\n/**\n * @param {InvidiousCommentResponse} response\n */\nfunction parseInvidiousCommentData(response) {\n  return response.comments.map((comment) => {\n    return {\n      id: comment.commentId,\n      authorLink: comment.authorId,\n      authorThumb: youtubeImageUrlToInvidious(comment.authorThumbnails.at(-1).url),\n      author: comment.author,\n      likes: comment.likeCount,\n      text: autolinker.link(invidiousImageUrlToInvidious(comment.contentHtml, getCurrentInstanceUrl())),\n      dataType: 'invidious',\n      isOwner: comment.authorIsChannelOwner,\n      isPinned: comment.isPinned,\n      numReplies: comment.replies?.replyCount ?? 0,\n      hasReplyToken: !!comment.replies?.continuation,\n      replyToken: comment.replies?.continuation ?? '',\n      showReplies: false,\n      replies: [],\n      isHearted: comment.creatorHeart !== undefined,\n      isMember: comment.isSponsor,\n      memberIconUrl: youtubeImageUrlToInvidious(comment.sponsorIconUrl),\n      time: getRelativeTimeFromDate(comment.published * 1000, false)\n    }\n  })\n}\n\nexport async function invidiousGetCommunityPosts(channelId, continuation = null) {\n  const payload = {\n    resource: 'channels',\n    id: channelId,\n    subResource: 'community',\n    params: {}\n  }\n\n  if (continuation) {\n    payload.params.continuation = continuation\n  }\n\n  const response = await invidiousAPICall(payload)\n  response.comments = response.comments.map(communityPost => parseInvidiousCommunityData(communityPost))\n  return { posts: response.comments, continuation: response.continuation ?? null }\n}\n\nexport async function getInvidiousCommunityPost(postId, authorId = null) {\n  const payload = {\n    resource: 'post',\n    id: postId,\n  }\n\n  if (authorId == null) {\n    authorId = await invidiousGetChannelId('https://www.youtube.com/post/' + postId)\n  }\n\n  payload.params = {\n    ucid: authorId\n  }\n\n  const response = await invidiousAPICall(payload)\n\n  const post = parseInvidiousCommunityData(response.comments[0])\n  post.authorId = authorId\n  post.commentCount = null\n\n  return post\n}\n\nexport async function getInvidiousCommunityPostComments({ postId, authorId }) {\n  const payload = {\n    resource: 'post',\n    id: postId,\n    subResource: 'comments',\n    params: {\n      ucid: authorId\n    }\n  }\n\n  const response = await invidiousAPICall(payload)\n  const commentData = parseInvidiousCommentData(response)\n\n  return { response, commentData }\n}\n\nexport async function getInvidiousCommunityPostCommentReplies({ postId, replyToken, authorId }) {\n  const payload = {\n    resource: 'post',\n    id: postId,\n    subResource: 'comments',\n    params: {\n      ucid: authorId,\n      continuation: replyToken\n    }\n  }\n\n  const response = await invidiousAPICall(payload)\n  return { commentData: parseInvidiousCommentData(response), continuation: response.continuation ?? null }\n}\n\nfunction parseInvidiousCommunityData(data) {\n  return {\n    // use #/ to support channel YT links.\n    // ex post: https://www.youtube.com/post/UgkxMpGt1SVlHwA1afwqDr2DZLn-hmJJQqKo\n    postText: data.contentHtml.replaceAll('href=\"/', 'href=\"#/'),\n    postId: data.commentId,\n    authorThumbnails: data.authorThumbnails.map(thumbnail => {\n      thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n      return thumbnail\n    }),\n    publishedTime: calculatePublishedDate(data.publishedText),\n    voteCount: data.likeCount,\n    postContent: parseInvidiousCommunityAttachments(data.attachment),\n    commentCount: data?.replyCount ?? 0, // https://github.com/iv-org/invidious/pull/3635/\n    authorId: data.authorId,\n    author: data.author,\n    type: 'community'\n  }\n}\n\nfunction parseInvidiousCommunityAttachments(data) {\n  if (!data) {\n    return null\n  }\n\n  // I've only seen this appear when a video was made private.\n  // This is not currently supported on local api.\n  if (data.error) {\n    return {\n      type: 'error',\n      message: data.error\n    }\n  }\n\n  if (data.type === 'image') {\n    return {\n      type: data.type,\n      content: data.imageThumbnails.map(thumbnail => {\n        thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n        return thumbnail\n      })\n    }\n  }\n\n  if (data.type === 'video') {\n    data.videoThumbnails = data.videoThumbnails?.map(thumbnail => {\n      thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n      return thumbnail\n    })\n    return {\n      type: data.type,\n      content: data\n    }\n  }\n\n  if (data.type === 'multiImage') {\n    const content = data.images.map(imageThumbnails => {\n      return imageThumbnails.map(thumbnail => {\n        thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n        return thumbnail\n      })\n    })\n    return {\n      type: 'multiImage',\n      content: content\n    }\n  }\n\n  // https://github.com/iv-org/invidious/pull/3635/files\n  if (data.type === 'poll') {\n    return {\n      type: 'poll',\n      totalVotes: data.totalVotes ?? 0,\n      content: data.choices.map(choice => {\n        return {\n          text: choice.text,\n          image: choice.image?.map(thumbnail => {\n            thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n            return thumbnail\n          })\n        }\n      })\n    }\n  }\n\n  if (data.type === 'quiz') {\n    return {\n      type: 'quiz',\n      totalVotes: data.totalVotes ?? 0,\n      content: data.choices.map(choice => {\n        return {\n          text: choice.text,\n          isCorrect: choice.isCorrect,\n          image: choice.image?.map(thumbnail => {\n            thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url)\n            return thumbnail\n          })\n        }\n      })\n    }\n  }\n\n  if (data.type === 'playlist') {\n    return {\n      type: data.type,\n      content: data\n    }\n  }\n\n  console.error(`Unknown Invidious community post type: ${data.type}`)\n  console.error(data)\n}\n\n/**\n * @param {string} hashtag\n * @param {number} page\n */\nexport async function getHashtagInvidious(hashtag, page = 1) {\n  /** @type {{results: InvidiousVideoType[]}} */\n  const response = await invidiousAPICall({\n    resource: 'hashtag',\n    id: hashtag,\n    params: {\n      page\n    }\n  })\n\n  normalizeManyInvidiousVideosAttributes(response.results)\n  setMultiplePublishedTimestamps(response.results)\n\n  return response.results\n}\n\n/**\n * Generates a DASH manifest locally from Invidious' adaptive formats and manifest,\n * doing so allows us to support multiple audio tracks, which Invidious doesn't support yet\n * @param {import('youtubei.js').Misc.Format[]} formats\n */\nexport async function generateInvidiousDashManifestLocally(formats) {\n  // create a dummy player, as deciphering requires making requests to YouTube,\n  // which we want to avoid when Invidious is selected as the backend\n  const player = new Player()\n  player.decipher = async (url) => url\n\n  let urlTransformer\n\n  if (store.getters.getProxyVideos) {\n    /**\n     * @param {URL} url\n     */\n    urlTransformer = (url) => {\n      return new URL(getProxyUrl(url.toString()))\n    }\n  }\n\n  return await FormatUtils.toDash({\n    adaptive_formats: formats\n  }, false, urlTransformer, undefined, undefined, player)\n}\n\nexport function convertInvidiousToLocalFormat(format) {\n  const [initStart, initEnd] = format.init.split('-')\n  const [indexStart, indexEnd] = format.index.split('-')\n\n  const url = new URL(format.url)\n\n  const duration = parseInt(parseFloat(url.searchParams.get('dur')) * 1000)\n\n  // only converts the properties that are needed to generate a DASH manifest with YouTube.js\n  // audioQuality and qualityLabel don't go inside the DASH manifest, but are used by YouTube.js\n  // to determine whether a format is an audio or video stream respectively.\n\n  const localFormat = new Misc.Format({\n    itag: format.itag,\n    mimeType: format.type,\n    bitrate: format.bitrate,\n    width: format.width,\n    height: format.height,\n    initRange: {\n      start: initStart,\n      end: initEnd\n    },\n    indexRange: {\n      start: indexStart,\n      end: indexEnd\n    },\n    // lastModified: format.lmt,\n    // contentLength: format.clen,\n    url: format.url,\n    approxDurationMs: duration,\n    ...(format.type.startsWith('audio/')\n      ? {\n          audioQuality: format.audioQuality,\n          audioSampleRate: format.audioSampleRate,\n          audioChannels: format.audioChannels\n        }\n      : {\n          fps: format.fps,\n          qualityLabel: format.qualityLabel,\n          ...(format.colorInfo ? { colorInfo: format.colorInfo } : {})\n        })\n  })\n\n  if (localFormat.has_audio && url.searchParams.has('xtags')) {\n    const xtags = url.searchParams.get('xtags').split(':')\n\n    localFormat.language = xtags.find((tag) => tag.startsWith('lang='))?.split('=')[1] || null\n    localFormat.is_drc = xtags.includes('drc=1')\n\n    const audioContent = xtags.find((tag) => tag.startsWith('acont='))?.split('=')[1]\n    localFormat.is_dubbed = audioContent === 'dubbed'\n    localFormat.is_descriptive = audioContent === 'descriptive'\n    localFormat.is_secondary = audioContent === 'secondary'\n    localFormat.is_auto_dubbed = audioContent === 'dubbed-auto'\n    localFormat.is_original = audioContent === 'original' ||\n      (\n        !localFormat.is_dubbed &&\n        !localFormat.is_descriptive &&\n        !localFormat.is_secondary &&\n        !localFormat.is_auto_dubbed &&\n        !localFormat.is_drc\n      )\n  }\n\n  return localFormat\n}\n\n/**\n * @param {any} format\n */\nexport function mapInvidiousLegacyFormat(format) {\n  const [stringWidth, stringHeight] = format.size.split('x')\n\n  return {\n    itag: format.itag,\n    qualityLabel: format.qualityLabel,\n    fps: format.fps,\n    bitrate: parseInt(format.bitrate),\n    mimeType: format.type,\n    height: parseInt(stringHeight),\n    width: parseInt(stringWidth),\n    url: format.url\n  }\n}\n\n/**\n * @param {{\n *  authorId: string | null,\n * }[]} videos\n * @param {string|null} [fallbackAuthorId]\n */\nfunction normalizeManyInvidiousVideosAttributes(videos, fallbackAuthorId = null) {\n  const actualFallbackAuthorId = fallbackAuthorId === '' ? null : fallbackAuthorId\n\n  videos.forEach((v) => normalizeOneInvidiousVideoAttributes(v, actualFallbackAuthorId))\n}\n\n/**\n * @param {{\n *  authorId: string | null,\n * }} video\n * @param {string|null} [fallbackAuthorId]\n */\nfunction normalizeOneInvidiousVideoAttributes(video, fallbackAuthorId = null) {\n  if (video.authorId === '') video.authorId = fallbackAuthorId\n}\n\n/**\n * @param {{\n *  liveNow: boolean,\n *  isUpcoming: boolean,\n *  premiereTimestamp: number,\n *  published: number\n * }[]} videos\n */\nfunction setMultiplePublishedTimestamps(videos) {\n  videos.forEach(setPublishedTimestamp)\n}\n\n/**\n * @param {{\n *  liveNow: boolean,\n *  isUpcoming: boolean,\n *  premiereTimestamp: number,\n *  published: number\n * }} video\n */\nfunction setPublishedTimestamp(video) {\n  if (video.liveNow) {\n    video.published = Date.now()\n  } else if (video.isUpcoming) {\n    video.published = video.premiereTimestamp * 1000\n  } else if (typeof video.published === 'number') {\n    video.published *= 1000\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/api/local.js",
    "content": "import { ClientType, Constants, Innertube, Misc, Mixins, Parser, Platform, UniversalCache, Utils, YT, YTNodes } from 'youtubei.js'\nimport Autolinker from 'autolinker'\nimport { SEARCH_CHAR_LIMIT } from '../../../constants'\n\nimport { PlayerCache } from './PlayerCache'\nimport {\n  CHANNEL_HANDLE_REGEX,\n  calculatePublishedDate,\n  escapeHTML,\n  extractNumberFromString,\n  getChannelPlaylistId,\n  getRelativeTimeFromDate,\n} from '../utils'\n\nconst TRACKING_PARAM_NAMES = [\n  'utm_source',\n  'utm_medium',\n  'utm_campaign',\n  'utm_term',\n  'utm_content',\n]\n\nif (process.env.SUPPORTS_LOCAL_API) {\n  Platform.shim.eval = (data) => {\n    return new Promise((resolve, reject) => {\n      const code = data.output\n\n      // Generate a unique ID, as there may be multiple eval calls going on at the same time (e.g. DASH manifest generation)\n      const messageId = process.env.IS_ELECTRON || crypto.randomUUID\n        ? crypto.randomUUID()\n        : `${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\n      if (process.env.IS_ELECTRON) {\n        const iframe = document.getElementById('sigFrame')\n\n        /** @param {MessageEvent} event */\n        const listener = (event) => {\n          if (event.source === iframe.contentWindow && typeof event.data === 'string') {\n            const data = JSON.parse(event.data)\n\n            if (data.id === messageId) {\n              window.removeEventListener('message', listener)\n\n              if (data.error) {\n                reject(data.error)\n              } else {\n                resolve(data.result)\n              }\n            }\n          }\n        }\n\n        window.addEventListener('message', listener)\n        iframe.contentWindow.postMessage(JSON.stringify({ id: messageId, code }), '*')\n      } else {\n        reject(new Error('Please setup the eval function for the n/sig deciphering'))\n      }\n    })\n  }\n}\n\n/**\n * Creates a lightweight Innertube instance, which is faster to create or\n * an instance that can decode the streaming URLs, which is slower to create\n * the lightweight one only needs a single web request to create the new session\n * the full one needs 3 (or 2 if the player is cached) web requests to create:\n * 1. the request for the session\n * 2. fetch a page that contains a link to the player\n * 3. if the player isn't cached, it is downloaded and transformed\n * @param {object} options\n * @param {boolean} options.withPlayer set to true to get an Innertube instance that can decode the streaming URLs\n * @param {string|undefined} options.location the geolocation to pass to YouTube get different content\n * @param {boolean} options.safetyMode whether to hide mature content\n * @param {import('youtubei.js').ClientType} options.clientType use an alterate client\n * @param {boolean} options.generateSessionLocally generate the session locally or let YouTube generate it (local is faster, remote is more accurate)\n * @param {?import('youtubei.js').FetchFunction} options.fetchFunc optional custom fetch function\n * @returns the Innertube instance\n */\nasync function createInnertube({ withPlayer = false, location = undefined, safetyMode = false, clientType = undefined, generateSessionLocally = true, fetchFunc = null } = {}) {\n  let cache\n  if (withPlayer) {\n    if (process.env.IS_ELECTRON) {\n      cache = new PlayerCache()\n    } else {\n      cache = new UniversalCache(false)\n    }\n  }\n\n  return await Innertube.create({\n    // This setting is enabled by default and results in YouTube.js reusing the same session across different Innertube instances.\n    // That behavior is highly undesirable for FreeTube, as we want to create a new session every time to limit tracking.\n    enable_session_cache: false,\n    retrieve_innertube_config: !generateSessionLocally,\n    user_agent: navigator.userAgent,\n\n    retrieve_player: !!withPlayer,\n    location: location,\n    enable_safety_mode: !!safetyMode,\n    client_type: clientType,\n\n    // use browser fetch\n    fetch: (fetchFunc ?? ((input, init) => fetch(input, init))),\n    cache,\n    generate_session_locally: !!generateSessionLocally\n  })\n}\n\n/** @type {Innertube | null} */\nlet searchSuggestionsSession = null\n\nexport async function getLocalSearchSuggestions(query) {\n  // The search suggestions endpoint does not like search queries larger than SEARCH_CHAR_LIMIT\n  // so return an empty array instead\n  if (query.length > SEARCH_CHAR_LIMIT) {\n    return []\n  }\n\n  // reuse innertube instance to keep the search suggestions snappy\n  if (searchSuggestionsSession === null) {\n    searchSuggestionsSession = await createInnertube()\n  }\n\n  return await searchSuggestionsSession.getSearchSuggestions(query)\n}\n\nexport function clearLocalSearchSuggestionsSession() {\n  searchSuggestionsSession = null\n}\n\nexport async function getLocalPlaylist(id) {\n  const innertube = await createInnertube()\n  return await innertube.getPlaylist(id)\n}\n\n/**\n * @typedef {object} SerializedContinuation\n * @property {import('youtubei.js').Context} context\n * @property {string} path\n * @property {any} payload\n */\n\n/**\n * @param {import('youtubei.js').YTNodes.ContinuationItem} continuationItem\n * @param {import('youtubei.js').Actions} actions\n */\nfunction serializeContinuationItem(continuationItem, actions) {\n  let path, payload\n\n  // Based on YouTube.js' NavigationEndpoint#call()\n  if (continuationItem.endpoint.command.is(YTNodes.CommandExecutorCommand)) {\n    /** @type {import('youtubei.js').Helpers.YTNode & import('youtubei.js').APIResponseTypes.IEndpoint} */\n    const command = continuationItem.endpoint.command.commands.at(-1)\n\n    path = command.getApiPath()\n    payload = command.buildRequest()\n  } else {\n    path = continuationItem.endpoint.metadata.api_url\n    payload = continuationItem.endpoint.payload\n  }\n\n  /** @type {SerializedContinuation} */\n  const data = {\n    path,\n    payload: payload,\n    context: actions.session.context\n  }\n\n  return JSON.stringify(data)\n}\n\n/**\n * @param {import('youtubei.js').Mixins.Feed} feed\n */\nfunction extractFeedContinuationItem(feed) {\n  let continuationItem\n\n  if (feed.page.header_memo) {\n    const headerContinuations = feed.page.header_memo.getType(YTNodes.ContinuationItem)\n    continuationItem = feed.memo.getType(YTNodes.ContinuationItem).find(\n      (continuation) => !headerContinuations.includes(continuation)\n    )\n  } else {\n    continuationItem = feed.memo.getType(YTNodes.ContinuationItem)[0]\n  }\n\n  if (!continuationItem) {\n    throw new Utils.InnertubeError('There are no continuations.')\n  }\n\n  return continuationItem\n}\n\n/**\n * Based on YouTube.js' YT.Playlist.getContinuationData method\n * @param {import('youtubei.js').YT.Playlist} playlist\n */\nexport function extractLocalCacheablePlaylistContinuation(playlist) {\n  const sectionList = playlist.memo.getType(YTNodes.SectionList)[0]\n\n  let continuationItem\n\n  // No section list means there can't be additional continuation nodes here,\n  // so no need to check.\n  if (!sectionList) {\n    continuationItem = extractFeedContinuationItem(playlist)\n  } else {\n    continuationItem = playlist.memo.getType(YTNodes.ContinuationItem)\n      .find((node) => !sectionList.contents.includes(node))\n  }\n\n  if (!continuationItem) {\n    throw new Utils.InnertubeError('There are no continuations.')\n  }\n\n  return serializeContinuationItem(continuationItem, playlist.actions)\n}\n\n/**\n * Based on YouTube.js' YT.Search.getContinuationData method\n * @param {import('youtubei.js').YT.Search} search\n * @returns {SerializedContinuation}\n */\nexport function extractLocalCacheableSearchContinuation(search) {\n  const continuationItem = extractFeedContinuationItem(search)\n\n  return serializeContinuationItem(continuationItem, search.actions)\n}\n\n/**\n * @overload\n * @param {'playlist'} type\n * @param {string} continuation\n * @returns {Promise<import('youtubei.js').YT.Playlist>}\n */\n\n/**\n * @overload\n * @param {'search'} type\n * @param {string} continuation\n * @returns {Promise<import('youtubei.js').YT.Search>}\n */\n\n/**\n * @param {'playlist' | 'search'} type\n * @param {string} continuation\n */\nexport async function getLocalCachedFeedContinuation(type, continuation) {\n  /** @type {SerializedContinuation} */\n  const data = JSON.parse(continuation)\n\n  const innertube = await createInnertube()\n  innertube.session.context = data.context\n\n  const page = await innertube.actions.execute(data.path, { ...data.payload, parse: true })\n\n  if (!page) {\n    throw new Utils.InnertubeError('Could not get continuation data')\n  }\n\n  if (type === 'playlist') {\n    return new YT.Playlist(innertube.actions, page, true)\n  } else {\n    return new YT.Search(innertube.actions, page, true)\n  }\n}\n\n/**\n * @param {import('youtubei.js').YT.Playlist} playlist\n * @returns {Promise<import('youtubei.js').YT.Playlist|null>} null when no valid playlist can be found (e.g. `empty continuation response`)\n */\nexport async function getLocalPlaylistContinuation(playlist) {\n  try {\n    return await playlist.getContinuation()\n  } catch (error) {\n    // Youtube can provide useless continuation data\n    if (!error.message.includes('Got empty continuation response.')) {\n      // Re-throw unhandled error\n      throw error\n    }\n\n    return null\n  }\n}\n\n/**\n * Callback for adding two numbers.\n *\n * @callback untilEndOfLocalPlayListCallback\n * @param {import('youtubei.js').YT.Playlist} playlist\n */\n\n/**\n * @param {import('youtubei.js').YT.Playlist} playlist\n * @param {untilEndOfLocalPlayListCallback} callback\n * @param {object} options\n * @param {boolean} options.runCallbackOnceFirst\n */\nexport async function untilEndOfLocalPlayList(playlist, callback, options = { runCallbackOnceFirst: true }) {\n  if (options.runCallbackOnceFirst) { callback(playlist) }\n\n  while (playlist != null && playlist.has_continuation) {\n    playlist = await getLocalPlaylistContinuation(playlist)\n\n    if (playlist != null) { callback(playlist) }\n  }\n}\n\n/**\n * @param {string} location\n * @param {'gaming' | 'sports' | 'podcasts'} tab\n */\nexport async function getLocalTrending(location, tab) {\n  const innertube = await createInnertube({ location })\n\n  let args\n\n  switch (tab) {\n    case 'gaming':\n      // https://www.youtube.com/gaming/trending\n      args = {\n        browseId: 'UCOpNcN46UbXVtpKMrmU4Abg',\n        params: 'Egh0cmVuZGluZ7gBAJIDAPIGBAoCMgA'\n      }\n      break\n    case 'sports':\n      // https://www.youtube.com/channel/UCEgdi0XIXXZ-qJOFPf4JSKw/sportstab?ss=CMMG\n      args = {\n        browseId: 'UCEgdi0XIXXZ-qJOFPf4JSKw',\n        params: 'EglzcG9ydHN0YWK4AQCSAwDyBgQKAjIA'\n      }\n      break\n    case 'podcasts':\n      // https://www.youtube.com/podcasts/popularepisodes\n      args = {\n        browseId: 'FEpodcasts_destination',\n        params: 'qgcCCAM%3D'\n      }\n      break\n    default:\n      throw new Error('Unknown trending tab')\n  }\n\n  const response = await innertube.actions.execute('/browse', args)\n  const feed = new Mixins.Feed(innertube.actions, response)\n\n  return feed.videos.map(video => parseLocalListVideo(video))\n}\n\n/**\n * @param {string} query\n * @param {object} filters\n * @param {boolean} safetyMode\n */\nexport async function getLocalSearchResults(query, filters, safetyMode) {\n  const innertube = await createInnertube({ safetyMode })\n  const response = await innertube.search(query, convertSearchFilters(filters))\n\n  return handleSearchResponse(response)\n}\n\n/**\n * @param {YT.Search | SerializedContinuation} continuationData\n */\nexport async function getLocalSearchContinuation(continuationData) {\n  let response\n\n  if (continuationData instanceof YT.Search) {\n    response = await continuationData.getContinuation()\n  } else {\n    response = await getLocalCachedFeedContinuation('search', continuationData)\n  }\n\n  return handleSearchResponse(response)\n}\n\n/**\n * @param {string} id\n * @returns {Promise<{\n *   info: import('youtubei.js').YT.VideoInfo,\n *   poToken: string | undefined,\n *   clientInfo: {\n *     clientName: number,\n *     clientVersion: string,\n *     osName: string,\n *     osVersion: string\n *   },\n *   adEndTimeUnixMs: number\n * }>}\n */\nexport async function getLocalVideoInfo(id) {\n  let responseTime = Date.now()\n  let totalAdTimeMilliseconds = 0\n\n  const webInnertube = await createInnertube({\n    withPlayer: true,\n    generateSessionLocally: false,\n    fetchFunc: async (input, init) => {\n      if (!(input.url?.startsWith('https://www.youtube.com/youtubei/v1/player'))) {\n        return fetch(input, init)\n      }\n\n      const response = await fetch(input, init)\n\n      const responseText = await response.text()\n\n      responseTime = Date.now()\n\n      const json = JSON.parse(responseText)\n\n      if (Array.isArray(json.adSlots)) {\n        for (const adSlot of json.adSlots) {\n          if (adSlot.adSlotRenderer?.adSlotMetadata?.triggerEvent === 'SLOT_TRIGGER_EVENT_BEFORE_CONTENT') {\n            const instreamVideoAdRenderer = adSlot.adSlotRenderer.fulfillmentContent?.fulfilledLayout?.playerBytesAdLayoutRenderer\n              ?.renderingContent?.instreamVideoAdRenderer\n\n            if (instreamVideoAdRenderer) {\n              if (typeof instreamVideoAdRenderer.skipOffsetMilliseconds === 'number') {\n                totalAdTimeMilliseconds += instreamVideoAdRenderer.skipOffsetMilliseconds\n              } else if (instreamVideoAdRenderer.playerVars) {\n                const match = instreamVideoAdRenderer.playerVars.match(/length_seconds=([\\d.]+)/)\n\n                if (match) {\n                  totalAdTimeMilliseconds += parseFloat(match[1]) * 1000\n                }\n              }\n            }\n          }\n        }\n      }\n\n      // Need to return a new response object, as you can only read the response body once.\n      return new Response(responseText, {\n        status: response.status,\n        statusText: response.statusText,\n        headers: response.headers\n      })\n    }\n  })\n\n  // based on the videoId\n  let contentPoToken\n\n  if (process.env.IS_ELECTRON) {\n    try {\n      contentPoToken = await window.ftElectron.generatePoToken(\n        id,\n        JSON.stringify(webInnertube.session.context)\n      )\n\n      webInnertube.session.player.po_token = contentPoToken\n    } catch (error) {\n      console.error('Local API, poToken generation failed', error)\n      throw error\n    }\n  }\n\n  const info = await webInnertube.getInfo(id, { po_token: contentPoToken })\n\n  // Some time would be used for parsing and maybe additional requests so end time should be calculated sooner to reduce actual waiting time\n  // Legacy format requires this\n  const adEndTimeUnixMs = responseTime + totalAdTimeMilliseconds\n\n  let { clientName, clientVersion, osName, osVersion } = webInnertube.session.context.client\n\n  let hasTrailer = info.has_trailer\n  let trailerIsAgeRestricted = info.getTrailerInfo() === null\n\n  if (\n    ((info.playability_status.status === 'UNPLAYABLE' || info.playability_status.status === 'LOGIN_REQUIRED') &&\n      info.playability_status.reason === 'Sign in to confirm your age') ||\n    (hasTrailer && trailerIsAgeRestricted)\n  ) {\n    try {\n      const webEmbeddedInnertube = await createInnertube({ clientType: ClientType.WEB_EMBEDDED })\n      webEmbeddedInnertube.session.context.client.visitorData = webInnertube.session.context.client.visitorData\n\n      const videoId = hasTrailer && trailerIsAgeRestricted ? info.playability_status.error_screen.video_id : id\n\n      // getBasicInfo needs the signature timestamp (sts) from inside the player\n      webEmbeddedInnertube.session.player = webInnertube.session.player\n\n      const bypassedInfo = await webEmbeddedInnertube.getBasicInfo(videoId, { client: 'WEB_EMBEDDED', po_token: contentPoToken })\n\n      if (bypassedInfo.playability_status.status === 'OK' && bypassedInfo.streaming_data) {\n        info.playability_status = bypassedInfo.playability_status\n        info.streaming_data = bypassedInfo.streaming_data\n        info.basic_info.start_timestamp = bypassedInfo.basic_info.start_timestamp\n        info.basic_info.duration = bypassedInfo.basic_info.duration\n        info.captions = bypassedInfo.captions\n        info.storyboards = bypassedInfo.storyboards\n\n        hasTrailer = false\n        trailerIsAgeRestricted = false;\n\n        ({ clientName, clientVersion, osName, osVersion } = webEmbeddedInnertube.session.context.client)\n      }\n    } catch (error) {\n      console.warn('WEB_EMBEDDED fallback errored, using the original response instead', error)\n    }\n  }\n\n  const clientInfo = {\n    clientName: Constants.CLIENT_NAME_IDS[clientName],\n    clientVersion,\n    osName,\n    osVersion\n  }\n\n  if ((info.playability_status.status === 'UNPLAYABLE' && (!hasTrailer || trailerIsAgeRestricted)) ||\n    info.playability_status.status === 'LOGIN_REQUIRED') {\n    return { info, poToken: undefined, clientInfo }\n  }\n\n  if (hasTrailer && info.playability_status.status !== 'OK') {\n    const trailerInfo = info.getTrailerInfo()\n\n    // don't override the timestamp of when the video will premiere for upcoming videos\n    if (info.playability_status.status !== 'LIVE_STREAM_OFFLINE') {\n      info.basic_info.start_timestamp = trailerInfo.basic_info.start_timestamp\n    }\n\n    info.playability_status = trailerInfo.playability_status\n    info.streaming_data = trailerInfo.streaming_data\n    info.basic_info.duration = trailerInfo.basic_info.duration\n    info.captions = trailerInfo.captions\n    info.storyboards = trailerInfo.storyboards\n  }\n\n  if (info.streaming_data) {\n    const player = webInnertube.session.player\n\n    await decipherFormats(info.streaming_data.formats, player)\n\n    if (info.streaming_data.server_abr_streaming_url) {\n      info.streaming_data.server_abr_streaming_url = await player.decipher(info.streaming_data.server_abr_streaming_url)\n    }\n\n    if (info.streaming_data.dash_manifest_url) {\n      info.streaming_data.dash_manifest_url = await decipherManifestUrl(\n        info.streaming_data.dash_manifest_url,\n        webInnertube.session.player,\n        contentPoToken,\n        true\n      )\n    }\n\n    if (info.streaming_data.hls_manifest_url) {\n      info.streaming_data.hls_manifest_url = await decipherManifestUrl(\n        info.streaming_data.hls_manifest_url,\n        webInnertube.session.player,\n        contentPoToken,\n        false\n      )\n    }\n  }\n\n  if (info.captions?.caption_tracks) {\n    for (const captionTrack of info.captions.caption_tracks) {\n      const url = new URL(captionTrack.base_url)\n\n      url.searchParams.set('potc', '1')\n      url.searchParams.set('pot', contentPoToken)\n      url.searchParams.set('c', clientName)\n\n      // Remove &xosf=1 as it adds `position:63% line:0%` to the subtitle lines\n      // placing them in the top right corner\n      url.searchParams.delete('xosf')\n\n      captionTrack.base_url = url.toString()\n    }\n  }\n\n  return {\n    info,\n    poToken: contentPoToken,\n    clientInfo,\n    adEndTimeUnixMs,\n  }\n}\n\n/**\n * @param {string} id\n */\nexport async function getLocalComments(id) {\n  const innertube = await createInnertube()\n  return innertube.getComments(id)\n}\n\n// I know `type & type` is typescript syntax and not valid jsdoc but I couldn't get @extends or @augments to work\n\n/**\n * @typedef {object} _LocalFormat\n * @property {string} freeTubeUrl deciphered streaming URL, stored in a custom property so the DASH manifest generation doesn't break\n *\n * @typedef {Misc.Format & _LocalFormat} LocalFormat\n */\n\n/**\n * @param {Misc.Format[]} formats\n * @param {import('youtubei.js').Player} player\n */\nasync function decipherFormats(formats, player) {\n  for (const format of formats) {\n    // toDash deciphers the format again, so if we overwrite the original URL,\n    // it breaks because the n param would get deciphered twice and then be incorrect\n    format.freeTubeUrl = await format.decipher(player)\n  }\n}\n\n/**\n * @param {string} url\n * @param {import('youtubei.js').Player} player\n * @param {string} poToken\n * @param {boolean} isDash\n */\nasync function decipherManifestUrl(url, player, poToken, isDash) {\n  const urlObject = new URL(url)\n\n  if (urlObject.searchParams.size > 0) {\n    urlObject.searchParams.set('pot', poToken)\n\n    if (isDash) {\n      urlObject.searchParams.set('mpd_version', '7')\n    }\n\n    return await player.decipher(urlObject.toString())\n  }\n\n  const pathPrefix = isDash ? '/api/manifest/dash' : '/api/manifest/hls_variant'\n\n  // Convert path params to query params\n  const pathParts = urlObject.pathname\n    .replace(pathPrefix, '')\n    .split('/')\n    .filter(part => part.length > 0)\n\n  urlObject.pathname = pathPrefix\n\n  for (let i = 0; i + 1 < pathParts.length; i += 2) {\n    urlObject.searchParams.set(pathParts[i], decodeURIComponent(pathParts[i + 1]))\n  }\n\n  // decipher\n  const deciphered = await player.decipher(urlObject.toString())\n\n  // convert query parameters back to path parameters\n  const decipheredUrlObject = new URL(deciphered)\n\n  for (const [key, value] of decipheredUrlObject.searchParams) {\n    decipheredUrlObject.pathname += `/${key}/${encodeURIComponent(value)}`\n  }\n\n  decipheredUrlObject.search = ''\n  decipheredUrlObject.pathname += `/pot/${encodeURIComponent(poToken)}`\n\n  if (isDash) {\n    decipheredUrlObject.pathname += '/mpd_version/7'\n  }\n\n  return decipheredUrlObject.toString()\n}\n\n/**\n * @param {string} url\n * @param {boolean} doLogError\n */\nexport async function getLocalChannelId(url, doLogError = false) {\n  try {\n    const innertube = await createInnertube()\n\n    // Resolve URL and allow 1 redirect, as YouTube should just do 1\n    // We want to avoid an endless loop\n    for (let i = 0; i < 2; i++) {\n      // resolveURL throws an error if the URL doesn't exist\n      const navigationEndpoint = await innertube.resolveURL(url)\n\n      if (navigationEndpoint.metadata.page_type === 'WEB_PAGE_TYPE_CHANNEL') {\n        return navigationEndpoint.payload.browseId\n      } else if (navigationEndpoint.metadata.page_type === 'WEB_PAGE_TYPE_UNKNOWN' && navigationEndpoint.payload.url?.startsWith('https://www.youtube.com/')) {\n        // handle redirects like https://www.youtube.com/@wanderbots, which resolves to https://www.youtube.com/Wanderbots, which we need to resolve again\n        url = navigationEndpoint.payload.url\n      } else if (navigationEndpoint.payload.browseId === 'FEpost_detail') {\n        // convert base64 params to string and get the channelid\n        return atob(navigationEndpoint.payload.params).replaceAll(/[^\\d\\sA-Za-z-]/g, ' ').trim().split(' ').at(-1)\n      }\n    }\n  } catch (e) {\n    if (doLogError) {\n      console.error(e)\n    }\n  }\n\n  return null\n}\n\n/**\n * Returns the channel or the channel termination reason\n * @param {string} id\n */\nexport async function getLocalChannel(id) {\n  const innertube = await createInnertube()\n  let result\n  try {\n    result = await innertube.getChannel(id)\n  } catch (error) {\n    if (error instanceof Utils.ChannelError) {\n      result = {\n        alert: error.message\n      }\n    } else {\n      throw error\n    }\n  }\n  return result\n}\n\n/**\n * @param {string} id\n */\nexport async function getLocalChannelVideos(id) {\n  const innertube = await createInnertube()\n\n  try {\n    const response = await innertube.actions.execute('/browse', {\n      browseId: id,\n      params: 'EgZ2aWRlb3PyBgQKAjoA'\n      // protobuf for the videos tab (this is the one that YouTube uses,\n      // it has some empty fields in the protobuf but it doesn't work if you remove them)\n    })\n\n    const videosTab = new YT.Channel(null, response)\n    const { id: channelId = id, name, thumbnailUrl } = parseLocalChannelHeader(videosTab, true)\n\n    let videos\n\n    // if the channel doesn't have a videos tab, YouTube returns the home tab instead\n    // so we need to check that we got the right tab\n    if (videosTab.current_tab?.endpoint.metadata.url?.endsWith('/videos')) {\n      videos = parseLocalChannelVideos(videosTab.videos, channelId, name)\n    } else if (name.endsWith('- Topic') && !!videosTab.metadata.music_artist_name) {\n      try {\n        const playlist = await innertube.getPlaylist(getChannelPlaylistId(channelId, 'videos', 'newest'))\n\n        videos = playlist.items.map(parseLocalPlaylistVideo)\n      } catch (error) {\n        // If the channel doesn't exist, the API call to channel page above would have already failed,\n        // so if we get an error that the playlist doesn't exist here, it just means that this artist topic channel\n        // doesn't have any videos.\n        if (error.message === 'The playlist does not exist.') {\n          videos = []\n        } else {\n          throw error\n        }\n      }\n    } else {\n      videos = []\n    }\n\n    return {\n      name,\n      thumbnailUrl,\n      videos\n    }\n  } catch (error) {\n    console.error(error)\n    if (error instanceof Utils.ChannelError) {\n      return null\n    } else {\n      throw error\n    }\n  }\n}\n\n/**\n * @param {string} id\n */\nexport async function getLocalChannelLiveStreams(id) {\n  const innertube = await createInnertube()\n\n  try {\n    const response = await innertube.actions.execute('/browse', {\n      browseId: id,\n      params: 'EgdzdHJlYW1z8gYECgJ6AA%3D%3D'\n      // protobuf for the live tab (this is the one that YouTube uses,\n      // it has some empty fields in the protobuf but it doesn't work if you remove them)\n    })\n\n    let liveStreamsTab = new YT.Channel(innertube.actions, response)\n    const { id: channelId = id, name, thumbnailUrl } = parseLocalChannelHeader(liveStreamsTab, true)\n\n    let videos\n\n    // if the channel doesn't have a live tab, YouTube returns the home tab instead\n    // so we need to check that we got the right tab\n    if (liveStreamsTab.current_tab?.endpoint.metadata.url?.endsWith('/streams')) {\n      // work around YouTube bug where it will return a bunch of responses with only continuations in them\n      // e.g. https://www.youtube.com/@TWLIVES/streams\n\n      let tempVideos = liveStreamsTab.videos\n      while (tempVideos.length === 0 && liveStreamsTab.has_continuation) {\n        liveStreamsTab = await liveStreamsTab.getContinuation()\n        tempVideos = liveStreamsTab.videos\n      }\n\n      videos = parseLocalChannelVideos(tempVideos, channelId, name)\n    } else {\n      videos = []\n    }\n\n    return {\n      name,\n      thumbnailUrl,\n      videos\n    }\n  } catch (error) {\n    console.error(error)\n    if (error instanceof Utils.ChannelError) {\n      return null\n    } else {\n      throw error\n    }\n  }\n}\n\nexport async function getLocalChannelCommunity(id) {\n  const innertube = await createInnertube()\n\n  try {\n    const response = await innertube.actions.execute('/browse', {\n      browseId: id,\n      params: 'EgVwb3N0c_IGBAoCSgA%3D'\n      // protobuf for the community tab (this is the one that YouTube uses,\n      // it has some empty fields in the protobuf but it doesn't work if you remove them)\n    })\n\n    const communityTab = new YT.Channel(null, response)\n\n    // if the channel doesn't have a community tab, YouTube returns the home tab instead\n    // so we need to check that we got the right tab\n    if (communityTab.current_tab?.endpoint.metadata.url?.endsWith('/posts')) {\n      return parseLocalCommunityPosts(communityTab.posts)\n    } else {\n      return []\n    }\n  } catch (error) {\n    console.error(error)\n    if (error instanceof Utils.ChannelError) {\n      return null\n    } else {\n      throw error\n    }\n  }\n}\n\n/**\n * @param {YT.Channel} channel\n */\nexport async function getLocalArtistTopicChannelReleases(channel) {\n  const rawEngagementPanel = channel.shelves[0]?.menu?.top_level_buttons?.[0]?.endpoint.payload?.engagementPanel\n\n  if (!rawEngagementPanel) {\n    return {\n      releases: channel.playlists.map(playlist => parseLocalListPlaylist(playlist)),\n      continuationData: null\n    }\n  }\n\n  /** @type {import('youtubei.js').YTNodes.EngagementPanelSectionList} */\n  const engagementPanelSectionList = Parser.parseItem(rawEngagementPanel)\n\n  /** @type {import('youtubei.js').YTNodes.ContinuationItem|undefined} */\n  const continuationItem = engagementPanelSectionList?.content?.contents?.[0]?.contents?.[0]\n\n  if (!continuationItem) {\n    return {\n      releases: channel.playlists.map(playlist => parseLocalListPlaylist(playlist)),\n      continuationData: null\n    }\n  }\n\n  return await getLocalArtistTopicChannelReleasesContinuation(channel, continuationItem)\n}\n\n/**\n * @param {YT.Channel} channel\n * @param {import('youtubei.js').YTNodes.ContinuationItem} continuationData\n */\nexport async function getLocalArtistTopicChannelReleasesContinuation(channel, continuationData) {\n  const response = await continuationData.endpoint.call(channel.actions, { parse: true })\n\n  const memo = response.on_response_received_endpoints_memo\n\n  const playlists = memo.get('GridPlaylist') ?? memo.get('LockupView') ?? memo.get('Playlist')\n\n  /** @type {import('youtubei.js').YTNodes.ContinuationItem | null} */\n  const continuationItem = memo.get('ContinuationItem')?.[0] ?? null\n\n  return {\n    releases: playlists ? playlists.map(playlist => parseLocalListPlaylist(playlist)) : [],\n    continuationData: continuationItem\n  }\n}\n\n/**\n * @param {YT.Channel} channel\n * @param {boolean} onlyIdNameThumbnail\n */\nexport function parseLocalChannelHeader(channel, onlyIdNameThumbnail = false) {\n  /** @type {string?} */\n  let id\n  /** @type {string} */\n  let name\n  /** @type {string?} */\n  let thumbnailUrl\n  /** @type {string?} */\n  let bannerUrl\n  /** @type {string?} */\n  let subscriberText\n  /** @type {string[]} */\n  const tags = []\n\n  switch (channel.header.type) {\n    case 'C4TabbedHeader': {\n      // example: Linus Tech Tips\n      // https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw\n\n      /**\n       * @type {import('youtubei.js').YTNodes.C4TabbedHeader}\n       */\n      const header = channel.header\n\n      id = header.author.id\n      name = header.author.name\n      thumbnailUrl = header.author.best_thumbnail.url\n\n      if (!onlyIdNameThumbnail) {\n        bannerUrl = header.banner?.[0]?.url\n        subscriberText = header.subscribers?.text\n      }\n      break\n    }\n    case 'CarouselHeader': {\n      // examples: Music and YouTube Gaming\n      // https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ\n      // https://www.youtube.com/channel/UCOpNcN46UbXVtpKMrmU4Abg\n\n      /**\n       * @type {import('youtubei.js').YTNodes.CarouselHeader}\n       */\n      const header = channel.header\n\n      /**\n       * @type {import('youtubei.js').YTNodes.TopicChannelDetails}\n       */\n      const topicChannelDetails = header.contents.find(node => node.type === 'TopicChannelDetails')\n      name = topicChannelDetails.title.text\n      thumbnailUrl = topicChannelDetails.avatar[0].url\n\n      if (channel.metadata.external_id) {\n        id = channel.metadata.external_id\n      } else {\n        id = topicChannelDetails.subscribe_button.channel_id\n      }\n\n      if (!onlyIdNameThumbnail) {\n        subscriberText = topicChannelDetails.subtitle.text\n      }\n      break\n    }\n    case 'InteractiveTabbedHeader': {\n      // example: Minecraft - Topic\n      // https://www.youtube.com/channel/UCQvWX73GQygcwXOTSf_VDVg\n\n      /**\n       * @type {import('youtubei.js').YTNodes.InteractiveTabbedHeader}\n       */\n      const header = channel.header\n      name = header.title.text\n      thumbnailUrl = header.box_art.at(-1).url\n      id = channel.current_tab?.endpoint.payload.browseId\n\n      if (!onlyIdNameThumbnail) {\n        bannerUrl = header.banner[0]?.url\n\n        const badges = header.badges.map(badge => badge.label).filter(tag => tag)\n        tags.push(...badges)\n      }\n      break\n    }\n    case 'PageHeader': {\n      // example: YouTube Gaming\n      // https://www.youtube.com/channel/UCOpNcN46UbXVtpKMrmU4Abg\n\n      // User channels (an A/B test at the time of writing)\n\n      /**\n       * @type {import('youtubei.js').YTNodes.PageHeader}\n       */\n      const header = channel.header\n\n      name = header.content.title.text.text\n      if (header.content.image) {\n        if (header.content.image.type === 'ContentPreviewImageView') {\n          /** @type {import('youtubei.js').YTNodes.ContentPreviewImageView} */\n          const image = header.content.image\n\n          thumbnailUrl = image.image[0].url\n        } else {\n          /** @type {import('youtubei.js').YTNodes.DecoratedAvatarView} */\n          const image = header.content.image\n          thumbnailUrl = image.avatar?.image[0].url\n        }\n      } else if (header.content.animated_image) {\n        thumbnailUrl = header.content.animated_image.image[0].url\n      }\n\n      if (!thumbnailUrl && channel.metadata.thumbnail) {\n        thumbnailUrl = channel.metadata.thumbnail[0].url\n      }\n\n      if (!onlyIdNameThumbnail && header.content.banner) {\n        bannerUrl = header.content.banner.image[0]?.url\n      }\n\n      if (header.content.actions) {\n        const modal = header.content.actions.actions_rows[0].actions[0].on_tap.modal\n\n        if (modal && modal.type === 'ModalWithTitleAndButton') {\n          /** @type {import('youtubei.js').YTNodes.ModalWithTitleAndButton} */\n          const typedModal = modal\n\n          id = typedModal.button.endpoint.next_endpoint?.payload.browseId\n        }\n      } else if (channel.metadata.external_id) {\n        id = channel.metadata.external_id\n      }\n\n      if (!onlyIdNameThumbnail && header.content.metadata) {\n        // YouTube has already changed the indexes for where the information is stored once,\n        // so we should search for it instead of using hardcoded indexes, just to be safe for the future\n\n        subscriberText = header.content.metadata.metadata_rows\n          .flatMap(row => row.metadata_parts ? row.metadata_parts : [])\n          .find(part => part.text?.text?.includes('subscriber'))\n          ?.text?.text\n      }\n\n      break\n    }\n  }\n\n  if (onlyIdNameThumbnail) {\n    return {\n      id,\n      name,\n      thumbnailUrl\n    }\n  }\n\n  return {\n    id,\n    name,\n    thumbnailUrl,\n    bannerUrl,\n    subscriberText,\n    tags\n  }\n}\n\n/**\n * @param {import('youtubei.js').YTNodes.Video[]} videos\n * @param {string} channelId\n * @param {string} channelName\n */\nexport function parseLocalChannelVideos(videos, channelId, channelName) {\n  const parsedVideos = []\n\n  for (const video of videos) {\n    // `BADGE_STYLE_TYPE_MEMBERS_ONLY` used for both `members only` and `members first` videos\n    if (video.is(YTNodes.Video) && video.badges.some(badge => badge.style === 'BADGE_STYLE_TYPE_MEMBERS_ONLY')) {\n      continue\n    }\n    parsedVideos.push(parseLocalListVideo(video, channelId, channelName))\n  }\n\n  return parsedVideos\n}\n\n/**\n * @param {YTNodes.ReelItem | YTNodes.ShortsLockupView} short\n * @param {string} [channelId]\n * @param {string} [channelName]\n */\nexport function parseShort(short, channelId, channelName) {\n  if (short.type === 'ReelItem') {\n    /** @type {import('youtubei.js').YTNodes.ReelItem} */\n    const reelItem = short\n\n    return {\n      type: 'video',\n      videoId: reelItem.id,\n      title: reelItem.title.text?.trim(),\n      author: channelName,\n      authorId: channelId,\n      viewCount: reelItem.views.isEmpty() ? null : parseLocalSubscriberCount(reelItem.views.text),\n      lengthSeconds: ''\n    }\n  } else {\n    /** @type {import('youtubei.js').YTNodes.ShortsLockupView} */\n    const shortsLockupView = short\n\n    return {\n      type: 'video',\n      videoId: shortsLockupView.on_tap_endpoint.payload.videoId,\n      title: shortsLockupView.overlay_metadata.primary_text.text?.trim(),\n      author: channelName,\n      authorId: channelId,\n      viewCount: shortsLockupView.overlay_metadata.secondary_text ? parseLocalSubscriberCount(shortsLockupView.overlay_metadata.secondary_text.text) : null,\n      lengthSeconds: ''\n    }\n  }\n}\n\n/**\n * @param {(import('youtubei.js').YTNodes.ReelItem | import('youtubei.js').YTNodes.ShortsLockupView)[]} shorts\n * @param {string} [channelId]\n * @param {string} [channelName]\n */\nexport function parseLocalChannelShorts(shorts, channelId, channelName) {\n  return shorts.map(short => parseShort(short, channelId, channelName))\n}\n\n/**\n * @param {import('youtubei.js').YTNodes.Playlist|import('youtubei.js').YTNodes.GridPlaylist|import('youtubei.js').YTNodes.LockupView} playlist\n * @param {string} channelId\n * @param {string} channelName\n */\nexport function parseLocalListPlaylist(playlist, channelId = undefined, channelName = undefined) {\n  if (playlist.type === 'LockupView') {\n    return parseLockupView(playlist, channelId, channelName)\n  } else if (playlist.type === 'CompactStation') {\n    /** @type {import('youtubei.js').YTNodes.CompactStation} */\n    const compactStation = playlist\n\n    return {\n      type: 'playlist',\n      dataSource: 'local',\n      title: compactStation.title.text,\n      thumbnail: compactStation.thumbnail[1].url,\n      playlistId: compactStation.endpoint.payload.playlistId,\n      videoCount: extractNumberFromString(compactStation.video_count.text)\n    }\n  } else if (playlist.type === 'GridPlaylist') {\n    /** @type {import('youtubei.js').YTNodes.GridPlaylist} */\n    const gridPlaylist = playlist\n\n    return {\n      type: 'playlist',\n      dataSource: 'local',\n      title: gridPlaylist.title.text,\n      thumbnail: gridPlaylist.thumbnails.at(0).url,\n      playlistId: gridPlaylist.id,\n      channelName: gridPlaylist.author?.name,\n      channelId: gridPlaylist.author?.id,\n      videoCount: extractNumberFromString(gridPlaylist.video_count.text)\n    }\n  } else {\n    let internalChannelName\n    let internalChannelId = null\n\n    if (playlist.author && playlist.author.id !== 'N/A') {\n      if (playlist.author instanceof Misc.Text) {\n        internalChannelName = playlist.author.text\n\n        if (channelId) {\n          internalChannelId = channelId\n        }\n      } else {\n        internalChannelName = playlist.author.name\n        internalChannelId = playlist.author.id\n      }\n    } else if (channelId || channelName) {\n      internalChannelName = channelName\n      internalChannelId = channelId\n    } else if (playlist.author?.name) {\n      // auto-generated album playlists don't have an author\n      // so in search results, the author text is \"Playlist\" and doesn't have a link or channel ID\n      internalChannelName = playlist.author.name\n    }\n\n    /** @type {import('youtubei.js').YTNodes.PlaylistVideoThumbnail} */\n    const thumbnailRenderer = playlist.thumbnail_renderer\n\n    return {\n      type: 'playlist',\n      dataSource: 'local',\n      title: playlist.title.text,\n      thumbnail: thumbnailRenderer ? thumbnailRenderer.thumbnail[0].url : playlist.thumbnails[0].url,\n      channelName: internalChannelName,\n      channelId: internalChannelId,\n      playlistId: playlist.id,\n      videoCount: extractNumberFromString(playlist.video_count.text)\n    }\n  }\n}\n\n/**\n * @param {YT.Search} response\n */\nfunction handleSearchResponse(response) {\n  if (!response.results) {\n    return {\n      results: [],\n      continuationData: null\n    }\n  }\n\n  const results = response.results\n    .filter((item) => {\n      return item.type === 'Video' || item.type === 'Channel' || item.type === 'Playlist' || item.type === 'HashtagTile' || item.type === 'Movie' || item.type === 'LockupView'\n    })\n    .map((item) => parseListItem(item))\n    .filter((item) => item)\n\n  return {\n    results,\n    // check the length of the results, as there can be continuations for things that we've filtered out, which we don't want\n    continuationData: response.has_continuation && results.length > 0 ? response : null\n  }\n}\n\n/**\n * @param {import('youtubei.js').YT.Channel} homeTab\n * @param {string} [channelId]\n * @param {string} [channelName]\n */\nexport function parseChannelHomeTab(homeTab, channelId, channelName) {\n  /**\n   * @type {import('youtubei.js').YTNodes.ItemSection | import('youtubei.js').YTNodes.RichSection}\n   */\n  let section\n  const shelves = []\n  for (section of homeTab.current_tab.content.contents) {\n    if (section.type === 'ItemSection') {\n      /**\n       * @type {import('youtubei.js').YTNodes.ItemSection}\n       */\n      const itemSection = section\n      if (itemSection.contents.at(0).type === 'Shelf') {\n        /** @type {import('youtubei.js').YTNodes.Shelf} */\n        const shelf = itemSection.contents.at(0)\n\n        const playlistId = shelf.play_all_button?.endpoint.payload.playlistId\n\n        // filter out the members-only video section as none of the videos in that section are playable as they require a paid channel membership\n        if (!playlistId || !playlistId.startsWith('UUMO')) {\n          shelves.push({\n            title: shelf.title.text,\n            content: shelf.content.items.map((item) => parseListItem(item, channelId, channelName)).filter(_ => _),\n            playlistId,\n            subtitle: shelf.subtitle?.text\n          })\n        }\n      } else if (itemSection.contents.at(0).type === 'ReelShelf') {\n        /** @type {import('youtubei.js').YTNodes.ReelShelf} */\n        const shelf = itemSection.contents.at(0)\n        shelves.push({\n          title: shelf.title.text,\n          content: shelf.items.map((item) => parseListItem(item, channelId, channelName)).filter(_ => _)\n        })\n      } else if (itemSection.contents.at(0).type === 'HorizontalCardList') {\n        /** @type {import('youtubei.js').YTNodes.HorizontalCardList} */\n        const shelf = itemSection.contents.at(0)\n        shelves.push({\n          title: shelf.header.title.text,\n          content: shelf.cards.map((item) => parseListItem(item, channelId, channelName)).filter(_ => _),\n          subtitle: shelf.header.subtitle.text\n        })\n      }\n    } else if (section.type === 'RichSection') {\n      if (section.content.type === 'RichShelf') {\n        /** @type {import('youtubei.js').YTNodes.RichShelf} */\n        const shelf = section.content\n        shelves.push({\n          title: shelf.title?.text,\n          content: shelf.contents.map(e => parseListItem(e.content, channelId, channelName)),\n          subtitle: shelf.subtitle?.text,\n          playlistId: shelf.endpoint?.metadata.url.includes('/playlist') ? shelf.endpoint?.metadata.url.replace('/playlist?list=', '') : null\n        })\n      }\n    }\n  }\n\n  shelves.forEach(e => {\n    e['isCommunity'] = e.content.at(0)?.type === 'community'\n  })\n  return shelves\n}\n/**\n * @param {import('youtubei.js').YTNodes.PlaylistVideo|import('youtubei.js').YTNodes.ReelItem|import('youtubei.js').YTNodes.ShortsLockupView} video\n */\nexport function parseLocalPlaylistVideo(video) {\n  if (video.type === 'ReelItem') {\n    /** @type {import('youtubei.js').YTNodes.ReelItem} */\n    const short = video\n\n    return {\n      type: 'video',\n      videoId: short.id,\n      title: short.title.text?.trim(),\n      viewCount: parseLocalSubscriberCount(short.views.text),\n      lengthSeconds: ''\n    }\n  } else if (video.type === 'ShortsLockupView') {\n    /** @type {import('youtubei.js').YTNodes.ShortsLockupView} */\n    const shortsLockupView = video\n\n    let viewCount = null\n\n    // the accessiblity text is the only place with the view count\n    if (shortsLockupView.accessibility_text) {\n      // the `.*\\s+` at the start of the regex, ensures we match the last occurence\n      // just in case the video title also contains that pattern\n      const match = shortsLockupView.accessibility_text.match(/.*\\s+(\\d+(?:[,.]\\d+)?\\s?(?:[BKMbkm]|million)?|no)\\s+views?/)\n\n      if (match) {\n        const count = match[1]\n\n        // as it's rare that a video has no views,\n        // checking the length allows us to avoid running toLowerCase unless we have to\n        if (count.length === 2 && count === 'no') {\n          viewCount = 0\n        } else {\n          const views = parseLocalSubscriberCount(count)\n\n          if (!isNaN(views)) {\n            viewCount = views\n          }\n        }\n      }\n    }\n\n    return {\n      type: 'video',\n      videoId: shortsLockupView.on_tap_endpoint.payload.videoId,\n      title: shortsLockupView.overlay_metadata.primary_text.text?.trim(),\n      viewCount,\n      lengthSeconds: ''\n    }\n  } else {\n    /** @type {import('youtubei.js').YTNodes.PlaylistVideo} */\n    const video_ = video\n\n    let viewCount = null\n\n    const viewsText = video_.video_info.runs?.find(run => VIEWS_OR_WATCHING_REGEX.test(run.text))?.text\n\n    if (viewsText) {\n      const views = parseLocalSubscriberCount(viewsText)\n      if (!isNaN(views)) {\n        viewCount = views\n      }\n    }\n\n    let publishedText\n    // normal videos have 3 text runs with the last one containing the published date\n    // OR no runs and just text with the published date (if the view count is missing)\n    // live videos have 2 text runs with the number of people watching\n    // upcoming either videos don't have any info text or the number of people waiting,\n    // but we have the premiere date for those, so we don't need the published date\n\n    if (!video_.is_upcoming && !video_.is_live) {\n      const hasRuns = !!video_.video_info.runs\n\n      if (hasRuns && video_.video_info.runs.length === 3) {\n        publishedText = video_.video_info.runs[2].text\n      } else if (!hasRuns && video_.video_info.text) {\n        publishedText = video_.video_info.text\n      }\n    }\n\n    const published = calculatePublishedDate(\n      publishedText,\n      video_.is_live,\n      video_.is_upcoming,\n      video_.upcoming\n    )\n\n    return {\n      type: 'video',\n      videoId: video_.id,\n      title: video_.title.text?.trim(),\n      author: video_.author.name,\n      authorId: (video_.author?.id != null && video_.author.id !== 'N/A') ? video_.author.id : null,\n      viewCount,\n      published,\n      lengthSeconds: isNaN(video_.duration.seconds) ? '' : video_.duration.seconds,\n      liveNow: video_.is_live,\n      isUpcoming: video_.is_upcoming,\n      premiereDate: video_.upcoming\n    }\n  }\n}\n\n/**\n * @param {import('youtubei.js').YTNodes.Video | import('youtubei.js').YTNodes.Movie} item\n * @param {string} [channelId]\n * @param {string} [channelName]\n */\nexport function parseLocalListVideo(item, channelId, channelName) {\n  if (item.type === 'Movie') {\n    /** @type {import('youtubei.js').YTNodes.Movie} */\n    const movie = item\n\n    return {\n      type: 'video',\n      videoId: movie.id,\n      title: movie.title.text?.trim(),\n      author: movie.author.name !== 'N/A' ? movie.author.name : channelName,\n      authorId: movie.author.id !== 'N/A' ? movie.author.id : channelId,\n      description: movie.description_snippet?.text,\n      lengthSeconds: isNaN(movie.duration.seconds) ? '' : movie.duration.seconds,\n      liveNow: false,\n      isUpcoming: false,\n    }\n  } else if (item.type === 'GridVideo') {\n    /** @type {import('youtubei.js').YTNodes.GridVideo} */\n    const video = item\n\n    let publishedText\n\n    if (video.published != null && !video.published.isEmpty()) {\n      publishedText = video.published.text\n    }\n\n    const isLive = video.duration.text === 'LIVE'\n\n    const published = calculatePublishedDate(\n      publishedText,\n      video.is_live,\n      video.is_upcoming || video.is_premiere,\n      video.upcoming\n    )\n\n    return {\n      type: 'video',\n      videoId: video.video_id,\n      title: video.title.text?.trim(),\n      author: video.author?.name ?? channelName,\n      authorId: (video.author?.id != null && video.author.id !== 'N/A') ? video.author.id : channelId,\n      viewCount: video.views.text == null ? null : extractNumberFromString(video.views.text),\n      published,\n      lengthSeconds: isLive ? '' : Utils.timeToSeconds(video.duration.text),\n      isUpcoming: video.is_upcoming,\n      premiereDate: video.upcoming,\n      liveNow: isLive\n    }\n  } else if (item.type === 'GridMovie') {\n    /** @type {import('youtubei.js').YTNodes.GridMovie} */\n    const movie = item\n    return {\n      type: 'video',\n      videoId: movie.id,\n      title: movie.title.text,\n      author: movie.author.name !== 'N/A' ? movie.author.name : channelName,\n      authorId: movie.author.id !== 'N/A' ? movie.author.id : channelId,\n      lengthSeconds: isNaN(movie.duration.seconds) ? '' : movie.duration.seconds,\n      isUpcoming: movie.is_upcoming,\n      premiereDate: movie.upcoming\n    }\n  } else {\n    /** @type {import('youtubei.js').YTNodes.Video} */\n    const video = item\n\n    let publishedText\n\n    if (video.published != null && !video.published.isEmpty()) {\n      publishedText = video.published.text\n    }\n\n    const published = calculatePublishedDate(\n      publishedText,\n      video.is_live,\n      video.is_upcoming || video.is_premiere,\n      video.upcoming\n    )\n\n    let viewCount = null\n\n    if (video.view_count?.text) {\n      viewCount = video.view_count.text.toLowerCase() === 'no views' ? 0 : extractNumberFromString(video.view_count.text)\n    } else if (video.short_view_count?.text) {\n      viewCount = video.short_view_count.text.toLowerCase() === 'no views' ? 0 : parseLocalSubscriberCount(video.short_view_count.text)\n    }\n\n    return {\n      type: 'video',\n      videoId: video.video_id,\n      title: video.title.text?.trim(),\n      author: video.author.name !== 'N/A' ? video.author.name : channelName,\n      authorId: video.author.id !== 'N/A' ? video.author.id : channelId,\n      description: video.description,\n      viewCount,\n      published,\n      lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,\n      liveNow: video.is_live,\n      isUpcoming: video.is_upcoming || video.is_premiere,\n      premiereDate: video.upcoming,\n      is4k: video.is_4k,\n      is8k: video.badges.some(badge => badge.label === '8K'),\n      isNew: video.badges.some(badge => badge.label === 'New'),\n      isVr180: video.badges.some(badge => badge.label === 'VR180'),\n      isVr360: video.badges.some(badge => badge.label === '360°'),\n      is3d: video.badges.some(badge => badge.label === '3D'),\n      hasCaptions: video.has_captions\n    }\n  }\n}\n\nconst VIEWS_OR_WATCHING_REGEX = /views?|watching/i\n\n/**\n * @param {import('youtubei.js').YTNodes.LockupView} lockupView\n * @param {string | undefined} channelId\n * @param {string | undefined} channelName\n */\nfunction parseLockupView(lockupView, channelId = undefined, channelName = undefined) {\n  switch (lockupView.content_type) {\n    case 'ALBUM':\n    case 'PLAYLIST':\n    case 'PODCAST': {\n      const thumbnailOverlayBadgeView = lockupView.content_image.primary_thumbnail.overlays\n        .find(overlay => overlay.is(YTNodes.ThumbnailOverlayBadgeView))\n\n      const playlistId = lockupView.content_id\n\n      // Filter out mixes without playlist pages (we don't support watch page-only mixes)\n      // https://wiki.archiveteam.org/index.php/YouTube/Technical_details#Playlists\n      if (playlistId.startsWith('RD') && !playlistId.startsWith('RDCL')) {\n        return null\n      }\n\n      const maybeChannelText = lockupView.metadata?.metadata?.metadata_rows?.[0]?.metadata_parts?.[0]?.text\n\n      if (maybeChannelText && maybeChannelText.endpoint?.metadata.page_type === 'WEB_PAGE_TYPE_CHANNEL') {\n        channelName = maybeChannelText.text\n        channelId = maybeChannelText.endpoint.payload.browseId\n      }\n\n      return {\n        type: 'playlist',\n        dataSource: 'local',\n        playlistId,\n        title: lockupView.metadata.title.text,\n        thumbnail: lockupView.content_image.primary_thumbnail.image[0].url,\n        channelName,\n        channelId,\n        videoCount: extractNumberFromString(thumbnailOverlayBadgeView.badges[0].text)\n      }\n    }\n    case 'VIDEO': {\n      let publishedText\n      let lengthSeconds = ''\n      let liveNow = false\n      let isUpcoming = false\n      let premiereDate\n\n      /** @type {YTNodes.ThumbnailBottomOverlayView | undefined } */\n      const thumbnailBottomOverlayView = lockupView.content_image?.overlays?.firstOfType(YTNodes.ThumbnailBottomOverlayView)\n\n      if (thumbnailBottomOverlayView) {\n        if (thumbnailBottomOverlayView.badges.some(badge => badge.badge_style === 'THUMBNAIL_OVERLAY_BADGE_STYLE_LIVE')) {\n          liveNow = true\n        } else if (thumbnailBottomOverlayView.badges.some(badge => badge.text.toLowerCase() === 'upcoming')) {\n          isUpcoming = true\n\n          if (lockupView.metadata.metadata?.metadata_rows[1].metadata_parts?.[1].text?.text) {\n            premiereDate = new Date(lockupView.metadata.metadata.metadata_rows[1].metadata_parts[1].text.text)\n          }\n        } else {\n          const durationBadge = thumbnailBottomOverlayView.badges.find(badge => /^[\\d:]+$/.test(badge.text))\n\n          if (durationBadge) {\n            lengthSeconds = Utils.timeToSeconds(durationBadge.text)\n          }\n\n          publishedText = lockupView.metadata.metadata?.metadata_rows[1].metadata_parts?.find(part => part.text?.text?.endsWith('ago'))?.text?.text\n        }\n      }\n\n      let viewCount = null\n\n      const viewsText = lockupView.metadata.metadata?.metadata_rows[1].metadata_parts?.find(part => {\n        return part.text?.text && VIEWS_OR_WATCHING_REGEX.test(part.text.text)\n      })?.text?.text\n\n      if (viewsText) {\n        const views = parseLocalSubscriberCount(viewsText)\n\n        if (!isNaN(views)) {\n          viewCount = views\n        }\n      }\n\n      return {\n        type: 'video',\n        videoId: lockupView.content_id,\n        title: lockupView.metadata.title.text?.trim(),\n        author: lockupView.metadata.metadata?.metadata_rows[0].metadata_parts?.[0].text?.text,\n        authorId: lockupView.metadata.image?.renderer_context?.command_context?.on_tap?.payload.browseId,\n        viewCount,\n        published: calculatePublishedDate(publishedText, liveNow, isUpcoming, premiereDate),\n        lengthSeconds,\n        liveNow,\n        isUpcoming,\n        premiereDate\n      }\n    }\n    default:\n      console.warn(`Unknown lockup content type: ${lockupView.content_type}`, lockupView)\n      return null\n  }\n}\n\n/**\n * @param {import('youtubei.js').Helpers.YTNode} item\n * @param {string} [channelId]\n * @param {string} [channelName]\n */\nfunction parseListItem(item, channelId, channelName) {\n  switch (item.type) {\n    case 'Movie':\n    case 'Video':\n    case 'GridVideo':\n    case 'GridMovie':\n    case 'VideoCard':\n      return parseLocalListVideo(item, channelId, channelName)\n    case 'GameCard': {\n      /** @type {import('youtubei.js').YTNodes.GameCard} */\n      const channel = item\n      /** @type {import('youtubei.js').YTNodes.GameDetails} */\n      const game = channel.game\n      return {\n        type: 'channel',\n        dataSource: 'local',\n        thumbnail: game.box_art.at(0).url.replace(/^\\/\\//, 'https://'),\n        name: game.title.text,\n        id: game.endpoint.payload.browseId,\n        isGame: true\n      }\n    }\n    case 'GridChannel': {\n      /** @type {import('youtubei.js').YTNodes.GridChannel} */\n      const channel = item\n      let subscribers = null\n\n      if (channel.subscribers?.text) {\n        subscribers = parseLocalSubscriberCount(channel.subscribers.text)\n      }\n\n      const videos = extractNumberFromString(channel.video_count.text)\n\n      return {\n        type: 'channel',\n        dataSource: 'local',\n        thumbnail: channel.author.best_thumbnail?.url.replace(/^\\/\\//, 'https://'),\n        name: channel.author.name,\n        id: channel.author.id,\n        subscribers,\n        videos,\n        handle: null,\n        descriptionShort: channel.description_snippet?.text\n      }\n    }\n    case 'Channel': {\n      /** @type {import('youtubei.js').YTNodes.Channel} */\n      const channel = item\n\n      // see upstream TODO: https://github.com/LuanRT/YouTube.js/blob/main/src/parser/classes/Channel.ts#L33\n\n      // according to https://github.com/iv-org/invidious/issues/3514#issuecomment-1368080392\n      // the response can be the new or old one, so we currently need to handle both here\n      let subscribers = null\n      let videos = null\n      let handle = null\n      if (channel.subscriber_count.text?.startsWith('@')) {\n        handle = channel.subscriber_count.text\n\n        if (!channel.video_count.isEmpty()) {\n          subscribers = parseLocalSubscriberCount(channel.video_count.text)\n        }\n      } else {\n        videos = extractNumberFromString(channel.video_count.text)\n\n        if (!channel.subscriber_count.isEmpty()) {\n          subscribers = parseLocalSubscriberCount(channel.subscriber_count.text)\n        }\n      }\n\n      return {\n        type: 'channel',\n        dataSource: 'local',\n        thumbnail: channel.author.best_thumbnail?.url.replace(/^\\/\\//, 'https://'),\n        name: channel.author.name,\n        id: channel.author.id,\n        subscribers,\n        videos,\n        handle,\n        descriptionShort: channel.description_snippet.text\n      }\n    }\n    case 'HashtagTile': {\n      /** @type {import('youtubei.js').YTNodes.HashtagTile} */\n      const hashtag = item\n\n      return {\n        type: 'hashtag',\n        title: hashtag.hashtag.text,\n        videoCount: hashtag.hashtag_video_count.isEmpty() ? null : parseLocalSubscriberCount(hashtag.hashtag_video_count.text),\n        channelCount: hashtag.hashtag_channel_count.isEmpty() ? null : parseLocalSubscriberCount(hashtag.hashtag_channel_count.text)\n      }\n    }\n    case 'ReelItem':\n    case 'ShortsLockupView': {\n      return parseShort(item, channelId, channelName)\n    }\n    case 'CompactStation':\n    case 'GridPlaylist':\n    case 'Playlist': {\n      return parseLocalListPlaylist(item, channelId, channelName)\n    }\n    case 'Post': {\n      return parseLocalCommunityPost(item)\n    }\n    case 'LockupView':\n      return parseLockupView(item, channelId, channelName)\n  }\n}\n\n/**\n * @param {YTNodes.CompactVideo | YTNodes.CompactMovie | YTNodes.LockupView} video\n */\nexport function parseLocalWatchNextVideo(video) {\n  if (video.is(YTNodes.CompactMovie)) {\n    return {\n      type: 'video',\n      videoId: video.id,\n      title: video.title.text?.trim(),\n      author: video.author.name,\n      authorId: video.author.id,\n      lengthSeconds: video.duration.seconds\n    }\n  } else if (video.is(YTNodes.LockupView)) {\n    return parseLockupView(video)\n  } else {\n    let publishedText\n\n    if (video.published != null && !video.published.isEmpty()) {\n      publishedText = video.published.text\n    }\n\n    const published = calculatePublishedDate(publishedText, video.is_live, video.is_premiere)\n\n    return {\n      type: 'video',\n      videoId: video.video_id,\n      title: video.title.text?.trim(),\n      author: video.author.name,\n      authorId: video.author.id,\n      viewCount: video.view_count == null ? null : extractNumberFromString(video.view_count.text),\n      published,\n      lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,\n      liveNow: video.is_live,\n      isUpcoming: video.is_premiere\n    }\n  }\n}\n\nfunction convertSearchFilters(filters) {\n  const convertedFilters = {}\n\n  // some of the fields have different names and\n  // others have empty strings that we don't want to pass to youtubei.js\n\n  if (filters) {\n    if (filters.sortBy) {\n      convertedFilters.sort_by = filters.sortBy\n    }\n\n    if (filters.time) {\n      convertedFilters.upload_date = filters.time\n    }\n\n    if (filters.type) {\n      convertedFilters.type = filters.type\n    }\n\n    if (filters.duration) {\n      convertedFilters.duration = filters.duration\n    }\n\n    if (filters.features) {\n      convertedFilters.features = filters.features\n    }\n  }\n\n  return convertedFilters\n}\n\n/**\n * @param {(Misc.TextRun|Misc.EmojiRun)[]} runs\n * @param {number} emojiSize\n * @param {{looseChannelNameDetection: boolean}} options\n */\nexport function parseLocalTextRuns(runs, emojiSize = 16, options = { looseChannelNameDetection: false }) {\n  if (!Array.isArray(runs)) {\n    throw new Error('not an array of text runs')\n  }\n\n  const timestampRegex = /^(?:\\d+:){1,2}\\d+$/\n  const spacesBeforeRegex = /^\\s+/\n  const spacesAfterRegex = /\\s+$/\n  const parsedRuns = []\n\n  for (const run of runs) {\n    // may contain HTML, so we need to escape it, as we don't render unwanted HTML\n    // example: https://youtu.be/Hh_se2Zqsdk (see pinned comment)\n    const text = escapeHTML(run.text)\n\n    if (run instanceof Misc.EmojiRun) {\n      const { emoji } = run\n\n      // empty array if video creator removes a channel emoji so we ignore.\n      // eg: pinned comment here https://youtu.be/v3wm83zoSSY\n      if (emoji.image.length > 0) {\n        let altText\n\n        if (emoji.is_custom) {\n          if (emoji.shortcuts.length > 0) {\n            altText = emoji.shortcuts[0]\n          } else if (emoji.search_terms.length > 0) {\n            altText = emoji.search_terms.join(', ')\n          } else {\n            altText = 'Custom emoji'\n          }\n        } else {\n          altText = text\n        }\n\n        // lazy load the emoji image so it doesn't delay rendering of the text\n        // by defining a height and width, that space is reserved until the image is loaded\n        // that way we avoid layout shifts when it loads\n        parsedRuns.push(`<img src=\"${emoji.image[0].url}\" alt=\"${altText}\" width=\"${emojiSize}\" height=\"${emojiSize}\" loading=\"lazy\" style=\"vertical-align: middle\">`)\n      }\n    } else {\n      const { bold, italics, strikethrough, endpoint } = run\n\n      if (endpoint) {\n        switch (endpoint.metadata.page_type) {\n          case 'WEB_PAGE_TYPE_WATCH':\n            if (timestampRegex.test(text)) {\n              parsedRuns.push(text)\n            } else {\n              parsedRuns.push(`https://www.youtube.com${endpoint.metadata.url}`)\n            }\n            break\n          case 'WEB_PAGE_TYPE_CHANNEL': {\n            const trimmedText = text.trim()\n            // In comments, mention can be `@Channel Name` (not handle, but name)\n            if (CHANNEL_HANDLE_REGEX.test(trimmedText) || options.looseChannelNameDetection) {\n              // Note that in regex `\\s` must be used since the text contain non-default space (the half-width space char when we press spacebar)\n              const spacesBefore = (spacesBeforeRegex.exec(text) || [''])[0]\n              const spacesAfter = (spacesAfterRegex.exec(text) || [''])[0]\n              parsedRuns.push(`${spacesBefore}<a href=\"https://www.youtube.com/channel/${endpoint.payload.browseId}\">${trimmedText}</a>${spacesAfter}`)\n            } else {\n              parsedRuns.push(`https://www.youtube.com${endpoint.metadata.url}`)\n            }\n            break\n          }\n          case 'WEB_PAGE_TYPE_PLAYLIST':\n          case 'WEB_PAGE_TYPE_SHORTS':\n            parsedRuns.push(`https://www.youtube.com${endpoint.metadata.url}`)\n            break\n          case 'WEB_PAGE_TYPE_BROWSE':\n            parsedRuns.push(`<a href=\"https://www.youtube.com${endpoint.metadata.url}\">${text}</a>`)\n            break\n          case 'WEB_PAGE_TYPE_UNKNOWN':\n          default: {\n            const url = new URL((endpoint.dialog?.type === 'ConfirmDialog' && endpoint.dialog.confirm_button.endpoint.payload.url) || endpoint.payload.url)\n            if (url.hostname === 'www.youtube.com' && url.pathname === '/redirect' && url.searchParams.has('q')) {\n              // remove utm tracking parameters\n              const realURLStr = url.searchParams.get('q')\n              const realURL = new URL(realURLStr)\n              let urlChanged = false\n\n              TRACKING_PARAM_NAMES.forEach((paramName) => {\n                if (!realURL.searchParams.has(paramName)) { return }\n\n                realURL.searchParams.delete(paramName)\n                urlChanged = true\n              })\n\n              // `searchParams.delete` changes query string unnecessarily\n              // Using original unless there is any change\n              parsedRuns.push(urlChanged ? realURL.toString() : realURLStr)\n            } else {\n              // this is probably a special YouTube URL like http://www.youtube.com/approachingnirvana\n              parsedRuns.push(endpoint.payload.url)\n            }\n            break\n          }\n        }\n      } else {\n        let formattedText = text\n        if (bold) {\n          formattedText = `<b>${formattedText}</b>`\n        }\n\n        if (italics) {\n          formattedText = `<i>${formattedText}</i>`\n        }\n\n        if (strikethrough) {\n          formattedText = `<s>${formattedText}</s>`\n        }\n\n        parsedRuns.push(formattedText)\n      }\n    }\n  }\n\n  return parsedRuns.join('')\n}\n\n/**\n * @param {LocalFormat} format\n */\nexport function mapLocalLegacyFormat(format) {\n  return {\n    itag: format.itag,\n    qualityLabel: format.quality_label,\n    fps: format.fps,\n    bitrate: format.bitrate,\n    mimeType: format.mime_type,\n    height: format.height,\n    width: format.width,\n    url: format.freeTubeUrl\n  }\n}\n\n/**\n * The complete Triforce, or one or more components of the Triforce.\n * @typedef {object} LocalComment\n * @property {string} id\n * @property {string} dataType\n * @property {string} authorLink\n * @property {string} author\n * @property {string} authorId\n * @property {string} authorThumb\n * @property {boolean} isPinned\n * @property {boolean} isOwner\n * @property {boolean} isMember\n * @property {string} text\n * @property {boolean} isHearted\n * @property {boolean} hasOwnerReplied\n * @property {boolean} hasReplyToken\n * @property {CommentThread} replyToken\n * @property {boolean} showReplies\n * @property {LocalComment[]} replies\n * @property {string} memberIconUrl\n * @property {string} time\n * @property {number} likes\n * @property {number} numReplies\n */\n/**\n * @param {import('youtubei.js').YTNodes.CommentView} comment\n * @param {import('youtubei.js').YTNodes.CommentThread} commentThread\n * @return LocalComment\n */\nexport function parseLocalComment(comment, commentThread = undefined) {\n  let hasOwnerReplied = false\n  let replyToken = null\n  let hasReplyToken = false\n\n  if (commentThread?.has_replies) {\n    hasOwnerReplied = commentThread.comment_replies_data.has_channel_owner_replied\n    replyToken = commentThread\n    hasReplyToken = true\n  }\n\n  const commentTextRuns = comment.voice_reply_container?.transcript_text ? comment.voice_reply_container.transcript_text.runs : comment.content.runs\n\n  return {\n    id: comment.comment_id,\n    dataType: 'local',\n    authorLink: comment.author.id,\n    author: comment.author.name,\n    authorId: comment.author.id,\n    authorThumb: comment.author.best_thumbnail.url,\n    isPinned: comment.is_pinned,\n    isOwner: !!comment.author_is_channel_owner,\n    isMember: !!comment.is_member,\n    text: Autolinker.link(parseLocalTextRuns(commentTextRuns, 16, { looseChannelNameDetection: true })),\n    isHearted: !!comment.is_hearted,\n    hasOwnerReplied,\n    hasReplyToken,\n    replyToken,\n    showReplies: false,\n    replies: [],\n    memberIconUrl: comment.is_member ? comment.member_badge.url : '',\n    time: getRelativeTimeFromDate(calculatePublishedDate(comment.published_time.replace('(edited)', '').trim()), false),\n    likes: comment.like_count,\n    numReplies: parseLocalSubscriberCount(comment.reply_count)\n  }\n}\n\n/**\n * @param {string} text\n */\nexport function parseLocalSubscriberCount(text) {\n  const match = text.match(/(\\d+)(?:[,.](\\d+))?\\s?([BKMbkm]|million)\\b/)\n\n  if (match) {\n    let multiplier = 0\n\n    switch (match[3]) {\n      case 'K':\n      case 'k':\n        multiplier = 3\n        break\n      case 'M':\n      case 'm':\n      case 'million':\n        multiplier = 6\n        break\n      case 'B':\n      case 'b':\n        multiplier = 9\n        break\n    }\n\n    let parsedDecimals\n    if (typeof match[2] === 'undefined') {\n      parsedDecimals = '0'.repeat(multiplier)\n    } else {\n      parsedDecimals = match[2].padEnd(multiplier, '0')\n    }\n\n    return parseInt(match[1] + parsedDecimals)\n  } else {\n    return extractNumberFromString(text)\n  }\n}\n\n/**\n * Parse community posts\n * @param {import('youtubei.js').YTNodes.BackstagePost[] | import('youtubei.js').YTNodes.SharedPost[] | import('youtubei.js').YTNodes.Post[] } posts\n */\nexport function parseLocalCommunityPosts(posts) {\n  const foundIds = []\n  // `posts` includes the SharedPost's attached post for some reason so we need to filter that out.\n  // see: https://github.com/FreeTubeApp/FreeTube/issues/3252#issuecomment-1546675781\n  // we don't currently support SharedPost's so that is also filtered out\n  for (const post of posts) {\n    if (post.type === 'SharedPost') {\n      foundIds.push(post.original_post.id, post.id)\n    }\n  }\n\n  return posts.filter(post => {\n    return !foundIds.includes(post.id)\n  }).map(parseLocalCommunityPost)\n}\n\n/**\n * Parse community post\n * @param {import('youtubei.js').YTNodes.BackstagePost} post\n */\nfunction parseLocalCommunityPost(post) {\n  let replyCount = post.action_buttons?.reply_button?.text ?? null\n  if (replyCount !== null) {\n    replyCount = parseLocalSubscriberCount(post?.action_buttons.reply_button.text)\n  }\n\n  const authorThumbnails = post.author.thumbnails\n\n  authorThumbnails.forEach((thumbnail) => {\n    if (thumbnail.url.startsWith('//')) {\n      thumbnail.url = 'https:' + thumbnail.url\n    }\n  })\n\n  return {\n    postText: post.content.isEmpty() ? '' : Autolinker.link(parseLocalTextRuns(post.content.runs, 16)),\n    postId: post.id,\n    authorThumbnails,\n    publishedTime: calculatePublishedDate(post.published.text),\n    // YouTube hides the vote/like count on posts when it is zero\n    voteCount: post.vote_count ? parseLocalSubscriberCount(post.vote_count.text) : 0,\n    postContent: parseLocalAttachment(post.attachment),\n    commentCount: replyCount,\n    authorId: post.author.id,\n    author: post.author.name,\n    type: 'community'\n  }\n}\n\nfunction parseLocalAttachment(attachment) {\n  if (!attachment) {\n    return null\n  }\n  // image post\n  if (attachment.type === 'BackstageImage') {\n    return {\n      type: 'image',\n      content: attachment.image\n    }\n  } else if (attachment.type === 'Video') {\n    return {\n      type: 'video',\n      content: parseLocalListVideo(attachment)\n    }\n  } else if (attachment.type === 'Playlist') {\n    return {\n      type: 'playlist',\n      content: parseLocalListPlaylist(attachment)\n    }\n  } else if (attachment.type === 'PostMultiImage') {\n    return {\n      type: 'multiImage',\n      content: attachment.images.map(thumbnail => thumbnail.image)\n    }\n  } else if (attachment.type === 'Poll') {\n    return {\n      type: 'poll',\n      totalVotes: parseLocalSubscriberCount(attachment.total_votes.text) ?? 0,\n      content: attachment.choices.map(choice => {\n        return {\n          text: choice.text.text,\n          image: choice.image\n        }\n      })\n    }\n  } else if (attachment.type === 'Quiz') {\n    return {\n      type: 'quiz',\n      totalVotes: parseLocalSubscriberCount(attachment.total_votes.text) ?? 0,\n      content: Object.values(attachment.choices).map(choice => {\n        return {\n          text: choice.text.text,\n          isCorrect: choice.is_correct,\n          image: choice.image\n        }\n      })\n    }\n  } else {\n    console.error(`Unknown Local community post type: ${attachment.type}`)\n    console.error(attachment)\n  }\n}\n\nexport async function getHashtagLocal(hashtag) {\n  const innertube = await createInnertube()\n  return await innertube.getHashtag(hashtag)\n}\n\nexport async function getLocalCommunityPost(postId, channelId) {\n  const innertube = await createInnertube()\n  if (channelId == null) {\n    channelId = await getLocalChannelId('https://www.youtube.com/post/' + postId, true)\n  }\n\n  const postPage = await innertube.getPost(postId, channelId)\n  return parseLocalCommunityPost(postPage.posts[0])\n}\n\n/**\n * @param {string} postId\n * @param {string} channelId\n */\nexport async function getLocalCommunityPostComments(postId, channelId) {\n  const innertube = await createInnertube()\n\n  return await innertube.getPostComments(postId, channelId)\n}\n"
  },
  {
    "path": "src/renderer/helpers/channels.js",
    "content": "import { invidiousGetChannelInfo } from './api/invidious'\nimport { getLocalChannel, parseLocalChannelHeader } from './api/local'\n\n/**\n * @param {string} id\n * @param {{\n *   preference: string,\n *   fallback: boolean,\n *   invalid: boolean,\n * }} backendOptions\n */\nasync function findChannelById(id, backendOptions) {\n  try {\n    if (!process.env.SUPPORTS_LOCAL_API || backendOptions.preference === 'invidious') {\n      return await invidiousGetChannelInfo(id)\n    } else {\n      return await getLocalChannel(id)\n    }\n  } catch (err) {\n    // don't bother with fallback if channel doesn't exist\n    if (err.message && err.message === 'This channel does not exist.') {\n      return { invalid: true }\n    }\n    if (process.env.SUPPORTS_LOCAL_API && backendOptions.fallback) {\n      if (backendOptions.preference === 'invidious') {\n        return await getLocalChannel(id)\n      }\n      if (backendOptions.preference === 'local') {\n        return await invidiousGetChannelInfo(id)\n      }\n    } else {\n      throw err\n    }\n  }\n}\n\n/**\n * @param {string} id\n * @param {{\n *   preference: string,\n *   fallback: boolean,\n * }} backendOptions\n * @returns {Promise<{icon: string, iconHref: string, preferredName: string} | { invalidId: boolean }>}\n */\nexport async function findChannelTagInfo(id, backendOptions) {\n  if (!checkYoutubeChannelId(id)) return { invalidId: true }\n  try {\n    const channel = await findChannelById(id, backendOptions)\n    if (!process.env.SUPPORTS_LOCAL_API || backendOptions.preference === 'invidious') {\n      if (channel.invalid) return { invalidId: true }\n      return {\n        preferredName: channel.author,\n        icon: channel.authorThumbnails[0].url\n      }\n    } else {\n      if (channel.alert) return { invalidId: true }\n\n      const { name, thumbnailUrl } = parseLocalChannelHeader(channel)\n\n      return {\n        preferredName: name,\n        icon: thumbnailUrl,\n        iconHref: `/channel/${id}`\n      }\n    }\n  } catch (err) {\n    console.error(err)\n    return { preferredName: '', icon: '', iconHref: '', err }\n  }\n}\n\n/**\n * Check whether Id provided might be a YouTube Id\n * @param {string} id\n * @returns {boolean}\n */\nexport function checkYoutubeChannelId(id) {\n  return /^UC[\\w-]{22}$/.test(id)\n}\n"
  },
  {
    "path": "src/renderer/helpers/colors.js",
    "content": "import { randomArrayItem } from './utils'\n\n// When adding new colors here,\n// remember to update the name translations in `src/renderer/composables/colors.js`\nexport const colors = [\n  { name: 'Red', value: '#d50000' },\n  { name: 'Pink', value: '#C51162' },\n  { name: 'Purple', value: '#AA00FF' },\n  { name: 'DeepPurple', value: '#6200EA' },\n  { name: 'Indigo', value: '#304FFE' },\n  { name: 'Blue', value: '#2962FF' },\n  { name: 'LightBlue', value: '#0091EA' },\n  { name: 'Cyan', value: '#00B8D4' },\n  { name: 'Teal', value: '#00BFA5' },\n  { name: 'Green', value: '#00C853' },\n  { name: 'LightGreen', value: '#64DD17' },\n  { name: 'Lime', value: '#AEEA00' },\n  { name: 'Yellow', value: '#FFD600' },\n  { name: 'Amber', value: '#FFAB00' },\n  { name: 'Orange', value: '#FF6D00' },\n  { name: 'DeepOrange', value: '#DD2C00' },\n  { name: 'CatppuccinFrappeRosewater', value: '#f2d5cf' },\n  { name: 'CatppuccinFrappeFlamingo', value: '#eebebe' },\n  { name: 'CatppuccinFrappePink', value: '#f4b8e4' },\n  { name: 'CatppuccinFrappeMauve', value: '#ca9ee6' },\n  { name: 'CatppuccinFrappeRed', value: '#e78284' },\n  { name: 'CatppuccinFrappeMaroon', value: '#ea999c' },\n  { name: 'CatppuccinFrappePeach', value: '#ef9f76' },\n  { name: 'CatppuccinFrappeYellow', value: '#e5c890' },\n  { name: 'CatppuccinFrappeGreen', value: '#a6d189' },\n  { name: 'CatppuccinFrappeTeal', value: '#81c8be' },\n  { name: 'CatppuccinFrappeSky', value: '#99d1db' },\n  { name: 'CatppuccinFrappeSapphire', value: '#85c1dc' },\n  { name: 'CatppuccinFrappeBlue', value: '#8caaee' },\n  { name: 'CatppuccinFrappeLavender', value: '#babbf1' },\n  { name: 'CatppuccinLatteMauve', value: '#8839ef' },\n  { name: 'CatppuccinLatteRed', value: '#d20f39' },\n  { name: 'CatppuccinMochaRosewater', value: '#F5E0DC' },\n  { name: 'CatppuccinMochaFlamingo', value: '#F2CDCD' },\n  { name: 'CatppuccinMochaPink', value: '#F5C2E7' },\n  { name: 'CatppuccinMochaMauve', value: '#CBA6F7' },\n  { name: 'CatppuccinMochaRed', value: '#F38BA8' },\n  { name: 'CatppuccinMochaMaroon', value: '#EBA0AC' },\n  { name: 'CatppuccinMochaPeach', value: '#FAB387' },\n  { name: 'CatppuccinMochaYellow', value: '#F9E2AF' },\n  { name: 'CatppuccinMochaGreen', value: '#A6E3A1' },\n  { name: 'CatppuccinMochaTeal', value: '#94E2D5' },\n  { name: 'CatppuccinMochaSky', value: '#89DCEB' },\n  { name: 'CatppuccinMochaSapphire', value: '#74C7EC' },\n  { name: 'CatppuccinMochaBlue', value: '#89B4FA' },\n  { name: 'CatppuccinMochaLavender', value: '#B4BEFE' },\n  { name: 'DraculaCyan', value: '#8BE9FD' },\n  { name: 'DraculaGreen', value: '#50FA7B' },\n  { name: 'DraculaOrange', value: '#FFB86C' },\n  { name: 'DraculaPink', value: '#FF79C6' },\n  { name: 'DraculaPurple', value: '#BD93F9' },\n  { name: 'DraculaRed', value: '#FF5555' },\n  { name: 'DraculaYellow', value: '#F1FA8C' },\n  { name: 'EverforestDarkRed', value: '#E67E80' },\n  { name: 'EverforestDarkOrange', value: '#E69875' },\n  { name: 'EverforestDarkYellow', value: '#DBBC7F' },\n  { name: 'EverforestDarkGreen', value: '#A7C080' },\n  { name: 'EverforestDarkAqua', value: '#83C092' },\n  { name: 'EverforestDarkBlue', value: '#7FBBB3' },\n  { name: 'EverforestDarkPurple', value: '#D699B6' },\n  { name: 'EverforestLightRed', value: '#D83532' },\n  { name: 'EverforestLightOrange', value: '#D55D0F' },\n  { name: 'EverforestLightYellow', value: '#A96E00' },\n  { name: 'EverforestLightGreen', value: '#6D8100' },\n  { name: 'EverforestLightAqua', value: '#25976C' },\n  { name: 'EverforestLightBlue', value: '#2a84b5' },\n  { name: 'EverforestLightPurple', value: '#CF59aa' },\n  { name: 'GruvboxDarkGreen', value: '#b8bb26' },\n  { name: 'GruvboxDarkYellow', value: '#fabd2f' },\n  { name: 'GruvboxDarkBlue', value: '#83a593' },\n  { name: 'GruvboxDarkPurple', value: '#d3869b' },\n  { name: 'GruvboxDarkAqua', value: '#8ec07c' },\n  { name: 'GruvboxDarkOrange', value: '#fe8019' },\n  { name: 'GruvboxLightRed', value: '#9d0006' },\n  { name: 'GruvboxLightBlue', value: '#076678' },\n  { name: 'GruvboxLightPurple', value: '#8f3f71' },\n  { name: 'GruvboxLightOrange', value: '#af3a03' },\n  { name: 'SolarizedYellow', value: '#b58900' },\n  { name: 'SolarizedOrange', value: '#cb4b16' },\n  { name: 'SolarizedRed', value: '#dc322f' },\n  { name: 'SolarizedMagenta', value: '#d33682' },\n  { name: 'SolarizedViolet', value: '#6c71c4' },\n  { name: 'SolarizedBlue', value: '#268bd2' },\n  { name: 'SolarizedCyan', value: '#2aa198' },\n  { name: 'SolarizedGreen', value: '#859900' },\n]\n\nexport function getRandomColorClass() {\n  return 'main' + getRandomColor().name\n}\n\nexport function getRandomColor() {\n  return randomArrayItem(colors)\n}\n\nexport function calculateColorLuminance(colorValue) {\n  const cutHex = colorValue.substring(1, 7)\n  const colorValueR = parseInt(cutHex.substring(0, 2), 16)\n  const colorValueG = parseInt(cutHex.substring(2, 4), 16)\n  const colorValueB = parseInt(cutHex.substring(4, 6), 16)\n\n  const luminance = (0.299 * colorValueR + 0.587 * colorValueG + 0.114 * colorValueB) / 255\n\n  if (luminance > 0.5) {\n    return '#000000'\n  } else {\n    return '#FFFFFF'\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/EbmlParser.js",
    "content": "// Based on https://github.com/shaka-project/shaka-player/blob/main/lib/dash/ebml_parser.js\n// Adapted for use in FreeTube:\n// - General changes such as removing Closure compiler specific stuff\n\nimport shaka from 'shaka-player'\n\nconst ShakaError = shaka.util.Error\nconst BufferUtils = shaka.util.BufferUtils\n\nexport class EbmlParser {\n  /**\n   * @param {BufferSource} data\n   */\n  constructor(data) {\n    /** @private */\n    this.dataView_ = BufferUtils.toDataView(data)\n\n    /** @private */\n    this.reader_ = new shaka.util.DataViewReader(this.dataView_, shaka.util.DataViewReader.Endianness.BIG_ENDIAN)\n  }\n\n  /**\n   * @returns {boolean} True if the parser has more data, false otherwise.\n   */\n  hasMoreData() {\n    return this.reader_.hasMoreData()\n  }\n\n  /**\n   * Parses an EBML element from the parser's current position, and advances\n   * the parser.\n   * @returns {EbmlElement} The EBML element.\n   * @see http://matroska.org/technical/specs/rfc/index.html\n   */\n  parseElement() {\n    const id = this.parseId_()\n\n    // Parse the element's size.\n    const vint = this.parseVint_()\n    let size\n    if (/** @__NOINLINE__ */isDynamicSizeValue(vint)) {\n      // If this has an unknown size, assume that it takes up the rest of the\n      // data.\n      size = this.dataView_.byteLength - this.reader_.getPosition()\n    } else {\n      size = /** @__NOINLINE__ */ getVintValue(vint)\n    }\n\n    // Note that if the element's size is larger than the buffer then we are\n    // parsing a \"partial element\". This may occur if for example we are\n    // parsing the beginning of some WebM container data, but our buffer does\n    // not contain the entire WebM container data.\n    const elementSize =\n      this.reader_.getPosition() + size <= this.dataView_.byteLength\n        ? size\n        : this.dataView_.byteLength - this.reader_.getPosition()\n\n    const dataView = BufferUtils.toDataView(this.dataView_, this.reader_.getPosition(), elementSize)\n\n    this.reader_.skip(elementSize)\n\n    return new EbmlElement(id, dataView)\n  }\n\n  /**\n   * Parses an EBML ID from the parser's current position, and advances the\n   * parser.\n   * @returns {number} The EBML ID.\n   * @private\n   */\n  parseId_() {\n    const vint = this.parseVint_()\n\n    if (vint.length > 7) {\n      throw new ShakaError(\n        ShakaError.Severity.CRITICAL,\n        ShakaError.Category.MEDIA,\n        ShakaError.Code.EBML_OVERFLOW\n      )\n    }\n\n    let id = 0\n    for (const /* byte */ b of vint) {\n      // Note that we cannot use << since |value| may exceed 32 bits.\n      id = (256 * id) + b\n    }\n\n    return id\n  }\n\n  /**\n   * Parses a variable sized integer from the parser's current position, and\n   * advances the parser.\n   * For example:\n   *   1 byte  wide: 1xxx xxxx\n   *   2 bytes wide: 01xx xxxx xxxx xxxx\n   *   3 bytes wide: 001x xxxx xxxx xxxx xxxx xxxx\n   * @returns {Uint8Array} The variable sized integer.\n   * @private\n   */\n  parseVint_() {\n    const position = this.reader_.getPosition()\n    const firstByte = this.reader_.readUint8()\n    if (firstByte === 0) {\n      throw new ShakaError(\n        ShakaError.Severity.CRITICAL,\n        ShakaError.Category.MEDIA,\n        ShakaError.Code.EBML_OVERFLOW\n      )\n    }\n\n    // Determine the index of the highest bit set.\n    const index = Math.floor(Math.log2(firstByte))\n    const numBytes = 8 - index\n\n    if (process.env.NODE_ENV === 'development' && (numBytes > 8 || numBytes < 1)) {\n      throw new Error('Assertion failure: Incorrect log2 value')\n    }\n\n    this.reader_.skip(numBytes - 1)\n    return BufferUtils.toUint8(this.dataView_, position, numBytes)\n  }\n}\n\n// Lets us use the type in ./WebmSegmentIndexParser.js without actually exporting the class\n/** @typedef {EbmlElement} EbmlElement */\n\nclass EbmlElement {\n  /**\n   * @param {number} id The ID.\n   * @param {DataView} dataView The DataView.\n   */\n  constructor(id, dataView) {\n    /** @type {number} */\n    this.id = id\n\n    /** @private {DataView} */\n    this.dataView_ = dataView\n  }\n\n  /**\n   * Gets the element's offset from the beginning of the buffer.\n   * @returns {number}\n   */\n  getOffset() {\n    return this.dataView_.byteOffset\n  }\n\n  /**\n   * Interpret the element's data as a list of sub-elements.\n   * @returns {EbmlParser} A parser over the sub-elements.\n   */\n  createParser() {\n    return new EbmlParser(this.dataView_)\n  }\n\n  /**\n   * Interpret the element's data as an unsigned integer.\n   * @returns {number}\n   */\n  getUint() {\n    if (this.dataView_.byteLength > 8) {\n      throw new ShakaError(\n        ShakaError.Severity.CRITICAL,\n        ShakaError.Category.MEDIA,\n        ShakaError.Code.EBML_OVERFLOW\n      )\n    }\n\n    // Ensure we have at most 53 meaningful bits.\n    if ((this.dataView_.byteLength === 8) &&\n      (this.dataView_.getUint8(0) & 0xe0)) {\n      throw new ShakaError(\n        ShakaError.Severity.CRITICAL,\n        ShakaError.Category.MEDIA,\n        ShakaError.Code.JS_INTEGER_OVERFLOW\n      )\n    }\n\n    let value = 0\n\n    for (let i = 0; i < this.dataView_.byteLength; i++) {\n      const chunk = this.dataView_.getUint8(i)\n      value = (256 * value) + chunk\n    }\n\n    return value\n  }\n\n  /**\n   * Interpret the element's data as a floating point number\n   * (32 bits or 64 bits). 80-bit floating point numbers are not supported.\n   * @returns {number}\n   */\n  getFloat() {\n    if (this.dataView_.byteLength === 4) {\n      return this.dataView_.getFloat32(0)\n    } else if (this.dataView_.byteLength === 8) {\n      return this.dataView_.getFloat64(0)\n    } else {\n      throw new ShakaError(\n        ShakaError.Severity.CRITICAL,\n        ShakaError.Category.MEDIA,\n        ShakaError.Code.EBML_BAD_FLOATING_POINT_SIZE\n      )\n    }\n  }\n}\n\n/**\n * Gets the value of a variable sized integer.\n * For example, the x's below are part of the vint's value.\n *    7-bit value: 1xxx xxxx\n *   14-bit value: 01xx xxxx xxxx xxxx\n *   21-bit value: 001x xxxx xxxx xxxx xxxx xxxx\n * @param {Uint8Array} vint The variable sized integer.\n * @returns {number} The value of the variable sized integer.\n */\nfunction getVintValue(vint) {\n  // If |vint| is 8 bytes wide then we must ensure that it does not have more\n  // than 53 meaningful bits. For example, assume |vint| is 8 bytes wide,\n  // so it has the following structure,\n  // 0000 0001 | xxxx xxxx ...\n  // Thus, the first 3 bits following the first byte of |vint| must be 0.\n  if ((vint.length === 8) && (vint[1] & 0xe0)) {\n    throw new ShakaError(\n      ShakaError.Severity.CRITICAL,\n      ShakaError.Category.MEDIA,\n      ShakaError.Code.JS_INTEGER_OVERFLOW\n    )\n  }\n\n  let value = 0\n  for (let i = 0; i < vint.length; i++) {\n    const item = vint[i]\n    if (i === 0) {\n      // Mask out the first few bits of |vint|'s first byte to get the most\n      // significant bits of |vint|'s value. If |vint| is 8 bytes wide then\n      // |value| will be set to 0.\n      const mask = 0x1 << (8 - vint.length)\n      value = item & (mask - 1)\n    } else {\n      // Note that we cannot use << since |value| may exceed 32 bits.\n      value = (256 * value) + item\n    }\n  }\n\n  return value\n}\n\nconst DYNAMIC_SIZES = [\n  [0xff],\n  [0x7f, 0xff],\n  [0x3f, 0xff, 0xff],\n  [0x1f, 0xff, 0xff, 0xff],\n  [0x0f, 0xff, 0xff, 0xff, 0xff],\n  [0x07, 0xff, 0xff, 0xff, 0xff, 0xff],\n  [0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],\n  [0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]\n]\n\n/**\n * Checks if the given variable sized integer represents a dynamic size value.\n * @param {Uint8Array} vint The variable sized integer.\n * @returns {boolean} true if |vint| represents a dynamic size value,\n *   false otherwise.\n */\nfunction isDynamicSizeValue(vint) {\n  for (const dynamicSizeConst of DYNAMIC_SIZES) {\n    if (BufferUtils.equal(vint, new Uint8Array(dynamicSizeConst))) {\n      return true\n    }\n  }\n\n  return false\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/Mp4SegmentIndexParser.js",
    "content": "// Based on https://github.com/shaka-project/shaka-player/blob/main/lib/dash/mp4_segment_index_parser.js\n// Adapted for use in FreeTube:\n// - General changes such as removing Closure compiler specific stuff\n// - Rewritten to use functions instead of a class\n// - The segment URLs receive the start time and segment number\n\nimport shaka from 'shaka-player'\n\nconst ShakaError = shaka.util.Error\nconst SeverityCritical = ShakaError.Severity.CRITICAL\nconst CategoryMedia = ShakaError.Category.MEDIA\n\n/**\n * Parses SegmentReferences from an ISO BMFF SIDX structure.\n * @param {BufferSource} sidxData The MP4's container's SIDX.\n * @param {number} sidxOffset The SIDX's offset, in bytes, from the start of\n *   the MP4 container.\n * @param {string} uri The location of the MP4 file that contains the segments.\n * @param {shaka.media.InitSegmentReference} initSegmentReference\n * @param {number} timestampOffset\n * @param {number} appendWindowStart\n * @param {number} appendWindowEnd\n * @returns {shaka.media.SegmentReference[]}\n */\nexport function parseMp4SegmentIndex(\n  sidxData,\n  sidxOffset,\n  uri,\n  initSegmentReference,\n  timestampOffset,\n  appendWindowStart,\n  appendWindowEnd\n) {\n  let references\n\n  const parser = new shaka.util.Mp4Parser()\n    .fullBox('sidx', (box) => {\n      references = /** @__NOINLINE__ */ parseSIDX(\n        sidxOffset,\n        initSegmentReference,\n        timestampOffset,\n        appendWindowStart,\n        appendWindowEnd,\n        uri,\n        box\n      )\n    })\n\n  if (sidxData) {\n    parser.parse(sidxData)\n  }\n\n  if (references) {\n    return references\n  } else {\n    console.error('[parseMp4SegmentIndex] Invalid box type, expected \"sidx\".')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.MP4_SIDX_WRONG_BOX_TYPE\n    )\n  }\n}\n\n/**\n * Parse a SIDX box from the given reader.\n *\n * @param {number} sidxOffset\n * @param {shaka.media.InitSegmentReference} initSegmentReference\n * @param {number} timestampOffset\n * @param {number} appendWindowStart\n * @param {number} appendWindowEnd\n * @param {string} uri The location of the MP4 file that contains the segments.\n * @param {shaka.extern.ParsedBox} box\n * @returns {shaka.media.SegmentReference[]}\n */\nfunction parseSIDX(\n  sidxOffset,\n  initSegmentReference,\n  timestampOffset,\n  appendWindowStart,\n  appendWindowEnd,\n  uri,\n  box\n) {\n  if (process.env.NODE_ENV === 'development' && box.version == null) {\n    throw new Error('Assertion failure: SIDX is a full box and should have a valid version.')\n  }\n\n  const references = []\n\n  // Parse the SIDX structure.\n  // Skip reference_ID (32 bits).\n  box.reader.skip(4)\n\n  const timescale = box.reader.readUint32()\n\n  if (timescale === 0) {\n    console.error('[parseMp4SegmentIndex] Invalid timescale.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.MP4_SIDX_INVALID_TIMESCALE\n    )\n  }\n\n  let earliestPresentationTime\n  let firstOffset\n\n  if (box.version === 0) {\n    earliestPresentationTime = box.reader.readUint32()\n    firstOffset = box.reader.readUint32()\n  } else {\n    earliestPresentationTime = box.reader.readUint64()\n    firstOffset = box.reader.readUint64()\n  }\n\n  // Skip reserved (16 bits).\n  box.reader.skip(2)\n\n  // Add references.\n  const referenceCount = box.reader.readUint16()\n\n  // Subtract the presentation time offset\n  let unscaledStartTime = earliestPresentationTime\n  let startByte = sidxOffset + box.size + firstOffset\n\n  for (let i = 0; i < referenceCount; i++) {\n    // |chunk| is 1 bit for |referenceType|, and 31 bits for |referenceSize|.\n    const chunk = box.reader.readUint32()\n    const referenceType = (chunk & 0x80000000) >>> 31\n    const referenceSize = chunk & 0x7FFFFFFF\n\n    const subsegmentDuration = box.reader.readUint32()\n\n    // Skipping 1 bit for |startsWithSap|, 3 bits for |sapType|, and 28 bits\n    // for |sapDelta|.\n    box.reader.skip(4)\n\n    // If |referenceType| is 1 then the reference is to another SIDX.\n    // We do not support this.\n    if (referenceType === 1) {\n      console.error('[parseMp4SegmentIndex] Hierarchical SIDXs are not supported.')\n      throw new ShakaError(\n        SeverityCritical,\n        CategoryMedia,\n        ShakaError.Code.MP4_SIDX_TYPE_NOT_SUPPORTED\n      )\n    }\n\n    // The media timestamps inside the container.\n    const nativeStartTime = unscaledStartTime / timescale\n    const nativeEndTime =\n      (unscaledStartTime + subsegmentDuration) / timescale\n\n    const uris = [`${uri}&startTimeMs=${Math.round((nativeStartTime + timestampOffset) * 1000)}&sq=${i + 1}`]\n\n    references.push(\n      new shaka.media.SegmentReference(\n        nativeStartTime + timestampOffset,\n        nativeEndTime + timestampOffset,\n        () => uris,\n        startByte,\n        startByte + referenceSize - 1,\n        initSegmentReference,\n        timestampOffset,\n        appendWindowStart,\n        appendWindowEnd\n      )\n    )\n\n    unscaledStartTime += subsegmentDuration\n    startByte += referenceSize\n  }\n\n  box.parser.stop()\n  return references\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/SabrManifestParser.js",
    "content": "import shaka from 'shaka-player'\nimport { parseWebmSegmentIndex } from './WebmSegmentIndexParser'\nimport { parseMp4SegmentIndex } from './Mp4SegmentIndexParser'\n\n/**\n * @typedef {{\n *   duration: number,\n *   formats: {\n *     itag: number,\n *     lastModified: string,\n *     mimeType: string,\n *     xtags: string | undefined,\n *     bitrate: number,\n *     initRange: {\n *       start: number,\n *       end: number\n *     },\n *     indexRange: {\n *       start: number,\n *       end: number\n *     },\n *     width: number | undefined,\n *     height: number | undefined,\n *     frameRate: number | undefined,\n *     quality: string,\n *     language: string | undefined,\n *     audioSampleRate: number | undefined,\n *     audioChannels: number | undefined,\n *     isDrc: boolean | undefined,\n *     isVoiceBoost: boolean | undefined,\n *     isOriginal: boolean | undefined,\n *     isDubbed: boolean | undefined,\n *     isAutoDubbed: boolean | undefined,\n *     isDescriptive: boolean | undefined,\n *     isSecondary: boolean | undefined,\n *     spatialAudio: boolean\n *     label: string | undefined,\n *     colorTransferCharacteristics: 'BT709' | 'BT2020_10' | 'SMPTEST2084' | 'ARIB_STD_B67' | undefined,\n *     colorPrimaries: 'BT709' | 'BT2020' | undefined\n *   }[],\n *   captions: {\n *     id: string,\n *     label: string,\n *     mimeType: string,\n *     language: string,\n *     url: string\n *   }[],\n *   storyboards: {\n *     templateUrl: string,\n *     mimeType: string,\n *     columns: number,\n *     rows: number,\n *     thumbnailCount: number,\n *     thumbnailWidth: number,\n *     thumbnailHeight: number,\n *     storyboardCount: number,\n *     interval: number\n *   }[]\n * }} SabrManifest\n */\n\nconst NetworkingEngine = shaka.net.NetworkingEngine\n\nexport const MANIFEST_TYPE_SABR = 'application/sabr+json'\n\nconst CODECS_REGEX = /codecs=\"?([^\"]+)\"?/\n\nconst VIDEO_CODEC_PRIORITIES = [\n  'av01',\n  'vp09',\n  'vp9',\n  'avc1'\n]\n\n/**\n * @implements {shaka.extern.ManifestParser}\n */\nclass SabrManifestParser {\n  constructor() {\n    /**\n     * @private\n     * @type {shaka.extern.ManifestConfiguration | null}\n     */\n    this._config = null\n  }\n\n  /**\n   * @param {string} _uri\n   */\n  banLocation(_uri) {\n  }\n\n  /**\n   * @param {shaka.extern.ManifestConfiguration} config\n   * @param {(() => boolean) | undefined} _isPreloadFn\n   */\n  configure(config, _isPreloadFn) {\n    this._config = config\n  }\n\n  /**\n   * @param {shaka.extern.Variant} _variant\n   */\n  onInitialVariantChosen(_variant) {\n  }\n\n  /**\n   * @param {HTMLMediaElement | null} _mediaElement\n   */\n  setMediaElement(_mediaElement) {\n  }\n\n  /**\n   * @param {string} uri\n   * @param {shaka.extern.ManifestParser.PlayerInterface} playerInterface\n   * @returns {Promise<shaka.extern.Manifest>}\n   */\n  async start(uri, { filter, networkingEngine }) {\n    // As SABR manifests are a FreeTube internal thing we can skip going through the networking engine\n    // because we know it will always have the same format\n\n    // \"data:\" (5) + mime type length + \",\" (1)\n    const uriPrefixLength = 5 + MANIFEST_TYPE_SABR.length + 1\n\n    /** @type {SabrManifest} */\n    const manifestData = JSON.parse(decodeURIComponent(uri.slice(uriPrefixLength)))\n\n    const presentationTimeline = new shaka.media.PresentationTimeline(0, 0, true)\n    presentationTimeline.setStatic(true)\n    presentationTimeline.setSegmentAvailabilityDuration(Infinity)\n    presentationTimeline.lockStartTime()\n    presentationTimeline.setDuration(manifestData.duration)\n\n    let currentId = 0\n\n    /** @type {shaka.extern.Stream[]} */\n    const audioStreams = []\n    /** @type {shaka.extern.Stream[]} */\n    const videoStreams = []\n\n    const hasDrcAudio = manifestData.formats.some(format => format.isDrc)\n    const hasVoiceBoostAudio = manifestData.formats.some(format => format.isVoiceBoost)\n\n    // For audio only playback we still need to specify a video fromat ID\n    // the server won't return it but it will error if we don't list one\n    // so lets pick the worst video quality  just in case\n    let fakeVideoFormatId\n\n    if (this._config.disableVideo) {\n      const worstVideoFormat = manifestData.formats.reduce((previousFormat, currentFormat) => {\n        if (currentFormat.width === undefined) {\n          return previousFormat\n        } else if (previousFormat === null) {\n          return currentFormat\n        } else {\n          return currentFormat.bitrate < previousFormat.bitrate ? currentFormat : previousFormat\n        }\n      }, null)\n\n      fakeVideoFormatId = buildFormatId(worstVideoFormat)\n    }\n\n    for (const format of manifestData.formats) {\n      if (format.mimeType.startsWith('audio/')) {\n        if (format.xtags === 'CgcKAnZiEgEx') {\n          // Workaround to reject certain xtags value to avoid reload\n          // https://github.com/LuanRT/googlevideo/issues/42\n          // console.log('CgcKAnZiEgEx audio format', format)\n          continue\n        }\n        audioStreams.push(\n          /** @__NOINLINE__ */ createAudioStream(\n            format,\n            currentId++,\n            hasDrcAudio,\n            hasVoiceBoostAudio,\n            presentationTimeline,\n            networkingEngine,\n            fakeVideoFormatId\n          )\n        )\n      } else if (!this._config.disableVideo) {\n        videoStreams.push(\n          /** @__NOINLINE__ */ createVideoStream(format, currentId++, presentationTimeline, networkingEngine)\n        )\n      }\n    }\n\n    audioStreams.sort((a, b) => b.bandwidth - a.bandwidth)\n\n    if (!this._config.disableVideo) {\n      videoStreams.sort((a, b) => {\n        return VIDEO_CODEC_PRIORITIES.findIndex(codec => a.codecs.startsWith(codec)) -\n          VIDEO_CODEC_PRIORITIES.findIndex(codec => b.codecs.startsWith(codec))\n      })\n    }\n\n    /** @type {shaka.extern.Variant[]} */\n    const variants = []\n    let variantId = 0\n\n    if (this._config.disableVideo) {\n      for (const stream of audioStreams) {\n        variants.push({\n          id: variantId++,\n          audio: stream,\n          bandwidth: stream.bandwidth,\n          language: stream.language,\n          allowedByApplication: true,\n          allowedByKeySystem: true,\n          decodingInfos: [],\n          disabledUntilTime: 0,\n          primary: stream.primary,\n          video: null\n        })\n      }\n    } else {\n      for (const audioStream of audioStreams) {\n        for (const videoStream of videoStreams) {\n          variants.push({\n            id: variantId++,\n            audio: audioStream,\n            video: videoStream,\n            bandwidth: audioStream.bandwidth + videoStream.bandwidth,\n            language: audioStream.language,\n            allowedByApplication: true,\n            allowedByKeySystem: true,\n            decodingInfos: [],\n            disabledUntilTime: 0,\n            primary: audioStream.primary\n          })\n        }\n      }\n    }\n\n    const textStreams = /** @__NOINLINE__ */ createTextStreams(manifestData.captions, presentationTimeline, currentId)\n    currentId += textStreams.length\n\n    const imageStreams = /** @__NOINLINE__ */ createImageStreams(manifestData.storyboards, presentationTimeline, currentId)\n\n    /** @type {shaka.extern.Manifest} */\n    const manifest = {\n      type: 'SABR',\n      startTime: 0,\n      variants,\n      textStreams,\n      imageStreams,\n      chapterStreams: [],\n      presentationTimeline,\n\n      gapCount: 0,\n      ignoreManifestTimestampsInSegmentsMode: false,\n      isLowLatency: false,\n      nextUrl: null,\n      offlineSessionIds: [],\n      periodCount: 1,\n      sequenceMode: false,\n      serviceDescription: null,\n    }\n\n    await filter(manifest)\n\n    return manifest\n  }\n\n  /**\n   * @returns {Promise<void>}\n   */\n  stop() {\n    this._config = null\n    return Promise.resolve()\n  }\n}\n\n/**\n * @param {SabrManifest['formats'][0]} format\n */\nfunction buildFormatId(format) {\n  return `${format.itag}-${format.lastModified ?? '0'}-${format.xtags ?? ''}`\n}\n\n/**\n * @param {SabrManifest['formats'][0]} format\n * @param {number} id\n * @param {boolean} hasDrcAudio\n * @param {boolean} hasVoiceBoostAudio\n * @param {shaka.media.PresentationTimeline} presentationTimeline\n * @param {shaka.net.NetworkingEngine} networkingEngine\n * @param {string | undefined} fakeVideoFormatId\n */\nfunction createAudioStream(\n  format,\n  id,\n  hasDrcAudio,\n  hasVoiceBoostAudio,\n  presentationTimeline,\n  networkingEngine,\n  fakeVideoFormatId\n) {\n  const roles = []\n\n  if (format.isDrc) {\n    roles.push('drc')\n  } else if (format.isVoiceBoost) {\n    roles.push('voice-boost')\n  } else if (format.isDubbed) {\n    roles.push('dubbed')\n  } else if (format.isAutoDubbed) {\n    roles.push('dubbed-auto')\n  } else if (format.isDescriptive) {\n    roles.push('descriptive')\n  } else if (format.isSecondary) {\n    roles.push('secondary')\n  } else if (format.isOriginal) {\n    roles.push('main')\n  }\n\n  let label = null\n\n  if (format.label) {\n    if (format.isDrc) {\n      label = `${format.label} (Stable Volume)`\n    } else if (format.isVoiceBoost) {\n      label = `${format.label} (Voice Boost)`\n    } else {\n      label = format.label\n    }\n  } else if (hasDrcAudio || hasVoiceBoostAudio) {\n    if (format.isDrc) {\n      label = 'Stable Volume'\n    } else if (format.isVoiceBoost) {\n      label = 'Voice Boost'\n    } else {\n      label = 'Original'\n    }\n  }\n\n  /** @type {shaka.extern.Stream} */\n  const stream = {\n    type: 'audio',\n    id,\n    originalId: buildFormatId(format),\n    mimeType: format.mimeType.split(';', 1)[0],\n    codecs: format.mimeType.match(CODECS_REGEX)[1],\n    fullMimeTypes: new Set([format.mimeType]),\n    bandwidth: format.bitrate,\n    audioSamplingRate: format.audioSampleRate ?? null,\n    channelsCount: format.audioChannels ?? null,\n    label,\n    language: format.language ?? 'und',\n    originalLanguage: format.language ?? null,\n    spatialAudio: format.spatialAudio,\n    roles,\n    primary: roles.includes('main'),\n    segmentIndex: null,\n    createSegmentIndex: async () => {\n      // shaka-player sometimes calls the create function even when the segment index already exists\n      if (stream.segmentIndex) { return }\n\n      stream.segmentIndex = await createMediaSegmentIndex(\n        format,\n        stream,\n        presentationTimeline,\n        networkingEngine,\n        fakeVideoFormatId\n      )\n    },\n    closeSegmentIndex: () => {\n      if (stream.segmentIndex) {\n        stream.segmentIndex.release()\n        stream.segmentIndex = null\n      }\n    },\n\n    accessibilityPurpose: null,\n    closedCaptions: null,\n    drmInfos: [],\n    emsgSchemeIdUris: null,\n    encrypted: false,\n    external: false,\n    fastSwitching: false,\n    forced: false,\n    groupId: null,\n    isAudioMuxedInVideo: false,\n    keyIds: new Set(),\n    trickModeVideo: null\n  }\n\n  return stream\n}\n\n/**\n * @param {SabrManifest['formats'][0]} format\n * @param {number} id\n * @param {shaka.media.PresentationTimeline} presentationTimeline\n * @param {shaka.net.NetworkingEngine} networkingEngine\n */\nfunction createVideoStream(format, id, presentationTimeline, networkingEngine) {\n  const colorGamut = format.colorPrimaries === 'BT2020' ? 'rec2020' : 'srgb'\n\n  let hdr = 'SDR'\n\n  if (format.colorTransferCharacteristics === 'SMPTEST2084') {\n    hdr = 'PQ'\n  } else if (format.colorTransferCharacteristics === 'ARIB_STD_B67') {\n    hdr = 'HLG'\n  }\n\n  /** @type {shaka.extern.Stream} */\n  const stream = {\n    type: 'video',\n    id,\n    originalId: buildFormatId(format),\n    mimeType: format.mimeType.split(';', 1)[0],\n    codecs: format.mimeType.match(CODECS_REGEX)[1],\n    fullMimeTypes: new Set([format.mimeType]),\n    bandwidth: format.bitrate,\n    width: format.width,\n    height: format.height,\n    frameRate: format.frameRate,\n    colorGamut,\n    hdr,\n    roles: [],\n    segmentIndex: null,\n    createSegmentIndex: async () => {\n      // shaka-player sometimes calls the create function even when the segment index already exists\n      if (stream.segmentIndex) { return }\n\n      stream.segmentIndex = await createMediaSegmentIndex(format, stream, presentationTimeline, networkingEngine)\n    },\n    closeSegmentIndex: () => {\n      if (stream.segmentIndex) {\n        stream.segmentIndex.release()\n        stream.segmentIndex = null\n      }\n    },\n\n    accessibilityPurpose: null,\n    audioSamplingRate: null,\n    channelsCount: null,\n    closedCaptions: null,\n    drmInfos: [],\n    emsgSchemeIdUris: null,\n    encrypted: false,\n    external: false,\n    fastSwitching: false,\n    forced: false,\n    groupId: null,\n    isAudioMuxedInVideo: false,\n    keyIds: new Set(),\n    label: null,\n    language: 'und',\n    originalLanguage: null,\n    primary: false,\n    spatialAudio: false,\n    trickModeVideo: null\n  }\n\n  return stream\n}\n\n/**\n * @param {SabrManifest['captions']} captions\n * @param {shaka.media.PresentationTimeline} presentationTimeline\n * @param {number} currentId\n */\nfunction createTextStreams(captions, presentationTimeline, currentId) {\n  return captions.map((caption) => {\n    /** @type {shaka.extern.Stream} */\n    const stream = {\n      type: 'text',\n      id: currentId++,\n      originalId: caption.id,\n      mimeType: caption.mimeType,\n      fullMimeTypes: new Set([caption.mimeType]),\n      label: caption.label,\n      language: caption.language,\n      originalLanguage: caption.language,\n      kind: 'captions',\n      segmentIndex: null,\n      createSegmentIndex: () => {\n        stream.segmentIndex = shaka.media.SegmentIndex.forSingleSegment(\n          0,\n          presentationTimeline.getDuration(),\n          [caption.url]\n        )\n\n        stream.segmentIndex.get(0).mimeType = caption.mimeType\n\n        return Promise.resolve()\n      },\n      closeSegmentIndex: () => {\n        if (stream.segmentIndex) {\n          stream.segmentIndex.release()\n          stream.segmentIndex = null\n        }\n      },\n\n      accessibilityPurpose: null,\n      audioSamplingRate: null,\n      channelsCount: null,\n      closedCaptions: null,\n      codecs: '',\n      drmInfos: [],\n      emsgSchemeIdUris: null,\n      encrypted: false,\n      external: false,\n      fastSwitching: false,\n      forced: false,\n      groupId: null,\n      isAudioMuxedInVideo: false,\n      keyIds: new Set(),\n      primary: false,\n      roles: [],\n      spatialAudio: false,\n      trickModeVideo: null\n    }\n\n    return stream\n  })\n}\n\n/**\n * @param {SabrManifest['storyboards']} storyboards\n * @param {shaka.media.PresentationTimeline} presentationTimeline\n * @param {number} currentId\n */\nfunction createImageStreams(storyboards, presentationTimeline, currentId) {\n  return storyboards.map((storyboard) => {\n    const tilesLayout = `${storyboard.columns}x${storyboard.rows}`\n\n    /** @type {shaka.extern.Stream} */\n    const stream = {\n      type: 'image',\n      id: currentId++,\n      mimeType: storyboard.mimeType,\n      fullMimeTypes: new Set([storyboard.mimeType]),\n      tilesLayout,\n      width: storyboard.thumbnailWidth * storyboard.columns,\n      height: storyboard.thumbnailHeight * storyboard.rows,\n      segmentIndex: null,\n      createSegmentIndex: () => {\n        const duration = presentationTimeline.getDuration()\n\n        const interval = storyboard.interval > 0 ? storyboard.interval : duration / storyboard.thumbnailCount\n        const segmentDuration = interval * storyboard.columns * storyboard.rows\n\n        const references = []\n\n        for (let i = 0; i < storyboard.storyboardCount; i++) {\n          const startTime = i * segmentDuration\n          const endTime = Math.min(startTime + segmentDuration, duration)\n\n          const urls = [storyboard.templateUrl.replace('$M', i)]\n\n          const segmentReference = new shaka.media.SegmentReference(\n            startTime,\n            endTime,\n            () => urls,\n            0,\n            null,\n            null,\n            0,\n            0,\n            Infinity,\n            undefined,\n            tilesLayout,\n            interval\n          )\n\n          segmentReference.mimeType = storyboard.mimeType\n\n          references.push(segmentReference)\n        }\n\n        stream.segmentIndex = new shaka.media.SegmentIndex(references)\n\n        return Promise.resolve()\n      },\n      closeSegmentIndex: () => {\n        if (stream.segmentIndex) {\n          stream.segmentIndex.release()\n          stream.segmentIndex = null\n        }\n      },\n\n      accessibilityPurpose: null,\n      audioSamplingRate: null,\n      channelsCount: null,\n      closedCaptions: null,\n      codecs: '',\n      drmInfos: [],\n      emsgSchemeIdUris: null,\n      encrypted: false,\n      external: false,\n      fastSwitching: false,\n      forced: false,\n      groupId: null,\n      isAudioMuxedInVideo: false,\n      keyIds: new Set(),\n      label: null,\n      language: 'und',\n      originalId: null,\n      originalLanguage: null,\n      primary: false,\n      roles: [],\n      spatialAudio: false,\n      trickModeVideo: null\n    }\n\n    return stream\n  })\n}\n\n/**\n * @param {SabrManifest['formats'][0]} format\n * @param {shaka.extern.Stream} stream\n * @param {shaka.media.PresentationTimeline} presentationTimeline\n * @param {shaka.net.NetworkingEngine} networkingEngine\n * @param {string | undefined} fakeVideoFormatId\n */\nasync function createMediaSegmentIndex(\n  format,\n  stream,\n  presentationTimeline,\n  networkingEngine,\n  fakeVideoFormatId = undefined\n) {\n  let url = `sabr:${stream.type}?formatId=${encodeURIComponent(stream.originalId)}`\n\n  if (fakeVideoFormatId) {\n    url += `&videoFormatId=${encodeURIComponent(fakeVideoFormatId)}`\n  }\n\n  if (format.isDrc) {\n    url += '&drc'\n  } else if (format.isVoiceBoost) {\n    url += '&vb'\n  }\n\n  if (stream.type === 'video') {\n    const resolution = format.height || 360\n\n    url += `&resolution=${resolution}`\n  }\n\n  /** @type {shaka.extern.Request} */\n  const request = {\n    method: 'GET',\n    uris: [`${url}&init`],\n    contentType: stream.type,\n    body: null,\n    headers: {},\n    allowCrossSiteCredentials: false,\n    retryParameters: NetworkingEngine.defaultRetryParameters(),\n    licenseRequestType: null,\n    sessionId: null,\n    drmInfo: null,\n    initData: null,\n    initDataType: null,\n    streamDataCallback: null,\n  }\n\n  /** @type {shaka.extern.Response} */\n  const response = await networkingEngine.request(\n    NetworkingEngine.RequestType.SEGMENT,\n    request,\n    {\n      stream: stream,\n      type: NetworkingEngine.AdvancedRequestType.INIT_SEGMENT\n    }\n  ).promise\n\n  return /** @__NOINLINE__ */ createVodMediaSegmentIndex(url, response, format, stream, presentationTimeline.getDuration())\n}\n\n/**\n * @param {string} url\n * @param {shaka.extern.Response} response\n * @param {SabrManifest['formats'][0]} format\n * @param {shaka.extern.Stream} stream\n * @param {number} duration\n */\nfunction createVodMediaSegmentIndex(url, response, format, stream, duration) {\n  /** @type {shaka.extern.MediaQualityInfo} */\n  const mediaQuality = {\n    contentType: stream.type,\n    bandwidth: stream.bandwidth,\n    mimeType: stream.mimeType,\n    codecs: stream.codecs,\n    language: stream.language,\n    label: stream.label,\n    audioSamplingRate: stream.audioSamplingRate,\n    channelsCount: stream.channelsCount,\n    width: stream.width ?? null,\n    height: stream.height ?? null,\n    frameRate: stream.frameRate ?? null,\n    roles: stream.roles,\n    pixelAspectRatio: stream.pixelAspectRatio ?? null\n  }\n\n  const buffer = ArrayBuffer.isView(response.data) ? response.data.buffer : response.data\n\n  const initData = buffer.slice(format.initRange.start, format.initRange.end + 1)\n  const indexData = buffer.slice(format.indexRange.start, format.indexRange.end + 1)\n\n  const initUrls = [`${url}&init`]\n\n  const initSegmentReference = new shaka.media.InitSegmentReference(\n    () => initUrls,\n    format.initRange.start,\n    format.initRange.end,\n    mediaQuality,\n    null,\n    initData,\n    null\n  )\n\n  initSegmentReference.mimeType = stream.mimeType\n  initSegmentReference.codecs = stream.codecs\n\n  /** @type {shaka.media.SegmentReference[] | undefined} */\n  let references\n\n  if (stream.mimeType.endsWith('/webm')) {\n    references = /** @__NOINLINE__ */ parseWebmSegmentIndex(indexData, initData, url, initSegmentReference, 0, 0, duration)\n  } else {\n    references = /** @__NOINLINE__ */ parseMp4SegmentIndex(indexData, format.indexRange.start, url, initSegmentReference, 0, 0, duration)\n  }\n\n  for (const reference of references) {\n    reference.mimeType = stream.mimeType\n    reference.codecs = stream.codecs\n  }\n\n  return new shaka.media.SegmentIndex(references)\n}\n\nif (process.env.SUPPORTS_LOCAL_API) {\n  shaka.media.ManifestParser.registerParserByMime(MANIFEST_TYPE_SABR, () => new SabrManifestParser())\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/SabrSchemePlugin.js",
    "content": "import { base64ToU8, concatenateChunks, EventEmitterLike, MAX_INT32_VALUE } from 'googlevideo/utils'\nimport { CompositeBuffer, UmpReader } from 'googlevideo/ump'\nimport {\n  UMPPartId,\n  VideoPlaybackAbrRequest,\n  StreamProtectionStatus,\n  SabrError,\n  SabrRedirect,\n  MediaHeader,\n  SabrContextSendingPolicy,\n  SabrContextUpdate,\n  SabrContextWritePolicy,\n  NextRequestPolicy,\n  PlaybackCookie,\n  ReloadPlaybackContext,\n} from 'googlevideo/protos'\nimport shaka from 'shaka-player'\n\nimport { deepCopy } from '../utils'\n\nconst AbortableOperation = shaka.util.AbortableOperation\nconst ShakaError = shaka.util.Error\n\n/**\n * @typedef OperationInputs\n * @type {object}\n * @property {string} uri\n * @property {shaka.extern.Request} request\n * @property {shaka.net.NetworkingEngine.RequestType} requestType\n * @property {shaka.extern.HeadersReceived} headersReceived\n * The following are calculated from above properties\n * @property {string} formatIdString\n * @property {boolean} isInit\n * @property {number} sequenceNumber\n */\n/**\n * @typedef AbortStatus\n * @type {object}\n * @property {boolean} cancelled\n * @property {boolean} timedOut\n * @property {boolean} playerReloadRequested\n * @property {boolean} finished\n */\n/**\n * @typedef CurrentState\n * @type {object}\n * @property {Map<string, Uint8Array>} initDataCache\n * @property {VideoPlaybackAbrRequest} abrRequest\n * @property {RequestInit} requestInit\n * @property {AbortStatus} abortStatus\n * @property {AbortController} abortController\n * @property {SabrStreamState} sabrStreamState\n * @property {?TimeoutController} timeoutController\n * @property {?EventEmitterLike} eventEmitter\n * @property {number} cumulativeBackOffTimeMs\n * @property {number} cumulativeBackOffRequested\n * @property {number} cumulativeRetryDueToNextRequestPolicy\n */\n/**\n * @typedef SabrStreamState\n * @type {object}\n * @property {string} sabrUrl\n * @property {Set<number>} activeSabrContextTypes\n * @property {Map<number, SabrContextUpdate>} sabrContexts\n * @property {?NextRequestPolicy} nextRequestPolicy\n * @property {boolean} playerReloadRequested\n * @property {number} requestNumber\n */\n/**\n * @typedef TimeoutController\n * @type {object}\n * @property {() => void} resetTimeoutOnce\n * @property {() => void} clearTimeout\n */\n/**\n * @typedef SabrStream\n * @type {object}\n * @property {(cb: ({backoffMs: number}) => void) => void} onBackoffRequested\n * @property {(cb: () => void) => void} onReloadOnce\n * @property {() => void | undefined} cleanup\n */\n\n/**\n * @param {string} str\n */\nfunction formatIdFromString(str) {\n  const videoFormatIdParts = str.split('-')\n\n  return {\n    itag: parseInt(videoFormatIdParts[0]),\n    lastModified: videoFormatIdParts[1],\n    xtags: videoFormatIdParts[2]\n  }\n}\n\n/**\n * @param {import('googlevideo/protos').FormatId} formatId\n * @param {shaka.extern.BufferedRange} buffered\n * @param {shaka.media.SegmentIndex} segmentIndex\n */\nfunction createBufferedRange(formatId, buffered, segmentIndex) {\n  let endSegmentIndex = segmentIndex.find(buffered.end)\n  if (endSegmentIndex == null) {\n    // Using Last end time will get `null` in `segmentIndex.find`\n    endSegmentIndex = segmentIndex.getNumReferences() - 1\n  }\n\n  return {\n    formatId,\n    startTimeMs: String(Math.round(buffered.start * 1000)),\n    durationMs: String(Math.round((buffered.end - buffered.start) * 1000)),\n    startSegmentIndex: segmentIndex.find(buffered.start),\n    endSegmentIndex: endSegmentIndex,\n  }\n}\n\n/**\n * Creates a bogus buffered range for a format. Used when we want to signal to the server to not send any\n * segments for this format.\n * @param {import('googlevideo/protos').FormatId} formatId - The format to create a full buffer range for.\n * @returns {import('googlevideo/protos').BufferedRange} A BufferedRange object indicating the entire format is buffered.\n */\nfunction createFullBufferRange(formatId) {\n  return {\n    formatId: formatId,\n    durationMs: MAX_INT32_VALUE,\n    startTimeMs: '0',\n    startSegmentIndex: parseInt(MAX_INT32_VALUE),\n    endSegmentIndex: parseInt(MAX_INT32_VALUE),\n    timeRange: {\n      durationTicks: MAX_INT32_VALUE,\n      startTicks: '0',\n      timescale: 1000\n    }\n  }\n}\n\n/**\n * @param {shaka.Player} player\n * @param {shaka.extern.Manifest} manifest\n * @param {boolean} audioFormatsActive\n * @param {boolean} streamIsVideo - Fake audio bufferRange can be used\n * @param {boolean} streamIsAudio - Fake video bufferRange can be used\n * @param {import('googlevideo/protos').BufferedRange[]} bufferedRanges\n * @param {shaka.extern.Track} activeVariant\n */\nfunction fillBufferedRanges(player, manifest, audioFormatsActive, streamIsVideo, streamIsAudio, bufferedRanges, activeVariant) {\n  const bufferedInfo = player.getBufferedInfo()\n\n  if (bufferedInfo.audio.length > 0 || bufferedInfo.video.length > 0) {\n    let activeManifestVariant\n    if (audioFormatsActive) {\n      activeManifestVariant = manifest.variants.find((variant) => {\n        return variant.audio.originalId === activeVariant.originalAudioId\n      })\n    } else {\n      activeManifestVariant = manifest.variants.find((variant) => {\n        return variant.audio.originalId === activeVariant.originalAudioId &&\n          variant.video.originalId === activeVariant.originalVideoId\n      })\n    }\n\n    const audioFormatId = formatIdFromString(activeVariant.originalAudioId)\n    const audioSegmentIndex = activeManifestVariant.audio.segmentIndex\n\n    if (streamIsVideo) {\n      bufferedRanges.push(createFullBufferRange(audioFormatId))\n    } else {\n      for (const buffered of bufferedInfo.audio) {\n        bufferedRanges.push(createBufferedRange(audioFormatId, buffered, audioSegmentIndex))\n      }\n    }\n\n    // Lazily initialize these variables as video data won't exist for audio-only playback\n    let videoFormatId\n    let videoSegmentIndex\n\n    if (streamIsAudio && bufferedInfo.video.length > 0) {\n      videoFormatId = formatIdFromString(activeVariant.originalVideoId)\n      bufferedRanges.push(createFullBufferRange(videoFormatId))\n    } else {\n      for (const buffered of bufferedInfo.video) {\n        if (!videoFormatId) {\n          videoFormatId = formatIdFromString(activeVariant.originalVideoId)\n        }\n\n        if (!videoSegmentIndex) {\n          videoSegmentIndex = activeManifestVariant.video.segmentIndex\n        }\n\n        bufferedRanges.push(createBufferedRange(videoFormatId, buffered, videoSegmentIndex))\n      }\n    }\n  }\n}\n\n/**\n * @param {string} uri\n * @param {shaka.extern.Request} request\n * @param {Uint8Array} data\n * @returns {shaka.util.AbortableOperation<shaka.extern.Response>}\n */\nfunction createCacheResponse(uri, request, data) {\n  return AbortableOperation.completed({\n    data,\n    fromCache: true,\n    headers: {},\n    originalRequest: request,\n    originalUri: uri,\n    uri\n  })\n}\n\n/**\n * @param {shaka.util.Error.Code} code\n * @param {...any} args\n */\nfunction createRecoverableNetworkError(code, ...args) {\n  return new ShakaError(ShakaError.Severity.RECOVERABLE, ShakaError.Category.NETWORK, code, ...args)\n}\n\n/**\n * @param {SabrStreamState} sabrStreamState\n */\nfunction prepareSabrContexts(sabrStreamState) {\n  /** @type {SabrContextUpdate[]} */\n  const sabrContexts = []\n  /** @type {number[]} */\n  const unsentSabrContexts = []\n\n  for (const ctxUpdate of sabrStreamState.sabrContexts.values()) {\n    if (sabrStreamState.activeSabrContextTypes.has(ctxUpdate.type)) {\n      sabrContexts.push(ctxUpdate)\n    } else {\n      unsentSabrContexts.push(ctxUpdate.type)\n    }\n  }\n\n  return { sabrContexts, unsentSabrContexts }\n}\n\n/**\n * @template T\n * @param {import('googlevideo/shared-types').Part} part\n * @param {{ decode: (data: Uint8Array) => T }} decoder\n * @returns {T | undefined}\n */\nfunction decodePart(part, decoder) {\n  if (!part.data.chunks.length) return undefined\n\n  try {\n    const chunk = part.data.chunks.length === 1 ? part.data.chunks[0] : concatenateChunks(part.data.chunks)\n    return decoder.decode(chunk)\n  } catch {\n    return undefined\n  }\n}\n\n/**\n * @param {(args: void) => void} callback\n * @param {number} timeoutMs\n * @return TimeoutController\n */\nfunction createTimeoutController(callback, timeoutMs) {\n  return {\n    _timeout: setTimeout(callback, timeoutMs),\n    _resetCount: 0,\n    resetTimeoutOnce() {\n      if (this._resetCount > 0) return\n\n      this.clearTimeout()\n      this._timeout = setTimeout(callback, timeoutMs)\n      this._resetCount++\n    },\n    clearTimeout() {\n      clearTimeout(this._timeout)\n    },\n  }\n}\n\n/**\n * @param {OperationInputs} operationInputs - readonly\n * @param {CurrentState} currentState - can be updated\n */\nasync function doRequest(\n  operationInputs,\n  currentState,\n) {\n  let response\n  /** @type {CompositeBuffer | null} */\n  let chunkedDataBuffer = null\n  /** @type {Uint8Array[]} */\n  const responseDataChunks = []\n  let segmentComplete = false\n  let shouldRetry = false\n  let shouldRetryDueToNextRequestPolicy = false\n\n  let invalidPoToken = false\n  let error\n\n  if (currentState.sabrStreamState.playerReloadRequested) {\n    // Multiple requests might be issued at the same time, other requests should abort themselves once reload requested\n    throw createRecoverableNetworkError(ShakaError.Code.OPERATION_ABORTED, operationInputs.uri, operationInputs.requestType)\n  }\n\n  try {\n    let shouldReloadDueToBackoffLoop = false\n    if ((currentState.sabrStreamState.nextRequestPolicy?.backoffTimeMs || 0) > 0) {\n      const currentBackoffTimeMs = currentState.sabrStreamState.nextRequestPolicy.backoffTimeMs\n      currentState.eventEmitter.emit('backoff-requested', { backoffMs: currentBackoffTimeMs })\n      // Wait but can be aborted\n      await new Promise((resolve, reject) => {\n        setTimeout(resolve, currentBackoffTimeMs)\n        currentState.abortController.signal.addEventListener('abort', reject)\n      })\n      // Must reset AFTER waiting to avoid requested aborted\n      // Since long backoff time mostly happens on the start of video playback we only reset timeout once\n      // i.e. backoff time parts received will not reset timeout - counted as video loading issue\n      currentState.timeoutController?.resetTimeoutOnce()\n\n      currentState.cumulativeBackOffTimeMs += currentState.sabrStreamState.nextRequestPolicy.backoffTimeMs\n      currentState.cumulativeBackOffRequested += 1\n      const timeoutMs = operationInputs.request.retryParameters.timeout\n      // Detect infinite backoff loop by no. of times requested and cumulative time approaching timeout\n      if (currentState.cumulativeBackOffRequested >= 3 || (timeoutMs > 0 && timeoutMs <= (currentState.cumulativeBackOffTimeMs + currentBackoffTimeMs))) {\n        shouldReloadDueToBackoffLoop = true\n      }\n    }\n    if (shouldReloadDueToBackoffLoop || currentState.cumulativeRetryDueToNextRequestPolicy >= 100) {\n      // Fire fake reload event due to detecting retry loop\n      currentState.sabrStreamState.playerReloadRequested = true\n      if (!currentState.abortController.signal.aborted) {\n        currentState.abortController.abort()\n        currentState.eventEmitter.emit('reload')\n      }\n    }\n\n    const sabrURL = new URL(currentState.sabrStreamState.sabrUrl)\n    sabrURL.searchParams.set('rn', String(currentState.sabrStreamState.requestNumber++))\n    response = await fetch(sabrURL.toString(), currentState.requestInit)\n\n    operationInputs.headersReceived({})\n\n    const { itag, lastModified, xtags } = formatIdFromString(operationInputs.formatIdString)\n    let mediaHeaderId\n\n    const reader = response.body.getReader()\n    let readObj = await reader.read()\n\n    while (!readObj.done && !currentState.abortStatus.finished) {\n      if (chunkedDataBuffer) {\n        chunkedDataBuffer.append(readObj.value)\n      } else {\n        chunkedDataBuffer = new CompositeBuffer([readObj.value])\n      }\n\n      const remainingData = new UmpReader(chunkedDataBuffer).read((part) => {\n        switch (part.type) {\n          case UMPPartId.STREAM_PROTECTION_STATUS: {\n            const streamProtectionStatus = decodePart(part, StreamProtectionStatus)\n            if (streamProtectionStatus.status === 3) {\n              invalidPoToken = true\n            }\n            break\n          }\n          case UMPPartId.SABR_ERROR: {\n            const sabrError = decodePart(part, SabrError)\n            if (!sabrError) break\n\n            error = `SABR Error: type: ${sabrError.type}, code: ${sabrError.code}`\n            break\n          }\n          case UMPPartId.SABR_REDIRECT: {\n            const sabrRedirect = decodePart(part, SabrRedirect)\n            if (!sabrRedirect) break\n\n            currentState.sabrUrl = sabrRedirect.url\n            shouldRetry = true\n            break\n          }\n          case UMPPartId.MEDIA_HEADER: {\n            if (mediaHeaderId === undefined) {\n              const mediaHeader = decodePart(part, MediaHeader)\n              if (!mediaHeader) break\n\n              if (\n                mediaHeader.formatId.itag === itag &&\n                mediaHeader.formatId.lastModified === lastModified &&\n                mediaHeader.formatId.xtags === xtags\n              ) {\n                if (operationInputs.isInit && mediaHeader.isInitSeg) {\n                  mediaHeaderId = mediaHeader.headerId\n                } else if (!operationInputs.isInit && mediaHeader.sequenceNumber === operationInputs.sequenceNumber) {\n                  mediaHeaderId = mediaHeader.headerId\n                }\n              }\n            }\n\n            break\n          }\n          case UMPPartId.MEDIA: {\n            if (mediaHeaderId === part.data.getUint8(0)) {\n              responseDataChunks.push(...part.data.split(1).remainingBuffer.chunks)\n            }\n            break\n          }\n          case UMPPartId.MEDIA_END: {\n            if (mediaHeaderId === part.data.getUint8(0)) {\n              segmentComplete = true\n              currentState.abortStatus.finished = true\n              currentState.abortController.abort()\n            }\n            break\n          }\n          case UMPPartId.NEXT_REQUEST_POLICY: {\n            const nextRequestPolicy = decodePart(part, NextRequestPolicy)\n\n            shouldRetry = true\n            shouldRetryDueToNextRequestPolicy = true\n\n            currentState.sabrStreamState.nextRequestPolicy = nextRequestPolicy\n            currentState.abrRequest.streamerContext.playbackCookie = nextRequestPolicy?.playbackCookie ? PlaybackCookie.encode(nextRequestPolicy.playbackCookie).finish() : undefined\n\n            currentState.abrRequest.streamerContext.backoffTimeMs = nextRequestPolicy?.backoffTimeMs\n            break\n          }\n          case UMPPartId.FORMAT_INITIALIZATION_METADATA: {\n            break\n          }\n          case UMPPartId.SABR_CONTEXT_UPDATE: {\n            const sabrContextUpdate = decodePart(part, SabrContextUpdate)\n            if (!sabrContextUpdate) break\n\n            if (sabrContextUpdate.type !== undefined && sabrContextUpdate.value?.length) {\n              if (\n                sabrContextUpdate.writePolicy === SabrContextWritePolicy.KEEP_EXISTING &&\n                currentState.sabrStreamState.sabrContexts.has(sabrContextUpdate.type)\n              ) {\n                break\n              }\n\n              currentState.sabrStreamState.sabrContexts.set(sabrContextUpdate.type, sabrContextUpdate)\n\n              if (sabrContextUpdate.sendByDefault) {\n                currentState.sabrStreamState.activeSabrContextTypes.add(sabrContextUpdate.type)\n              }\n            }\n            break\n          }\n          case UMPPartId.SABR_CONTEXT_SENDING_POLICY: {\n            const sabrContextSendingPolicy = decodePart(part, SabrContextSendingPolicy)\n            if (!sabrContextSendingPolicy) break\n\n            for (const startPolicy of sabrContextSendingPolicy.startPolicy) {\n              if (!currentState.sabrStreamState.activeSabrContextTypes.has(startPolicy)) {\n                currentState.sabrStreamState.activeSabrContextTypes.add(startPolicy)\n              }\n            }\n\n            for (const stopPolicy of sabrContextSendingPolicy.stopPolicy) {\n              if (currentState.sabrStreamState.activeSabrContextTypes.has(stopPolicy)) {\n                currentState.sabrStreamState.activeSabrContextTypes.delete(stopPolicy)\n              }\n            }\n\n            for (const discardPolicy of sabrContextSendingPolicy.discardPolicy) {\n              if (currentState.sabrStreamState.sabrContexts.has(discardPolicy)) {\n                currentState.sabrStreamState.sabrContexts.delete(discardPolicy)\n              }\n            }\n            break\n          }\n          case UMPPartId.RELOAD_PLAYER_RESPONSE: {\n            const reloadPlaybackContext = decodePart(part, ReloadPlaybackContext)\n            if (!reloadPlaybackContext) break\n\n            // Whole video cannot be played\n            currentState.sabrStreamState.playerReloadRequested = true\n            if (!currentState.abortController.signal.aborted) {\n              currentState.abortController.abort()\n              currentState.eventEmitter.emit('reload')\n            }\n            break\n          }\n          default: {\n            break\n          }\n        }\n      })\n\n      if (!currentState.abortStatus.finished) {\n        if (remainingData) {\n          chunkedDataBuffer = remainingData.data\n        } else {\n          chunkedDataBuffer = null\n        }\n\n        readObj = await reader.read()\n      }\n    }\n  } catch (error) {\n    if (currentState.abortStatus.cancelled) {\n      throw createRecoverableNetworkError(ShakaError.Code.OPERATION_ABORTED, operationInputs.uri, operationInputs.requestType)\n    } else if (currentState.abortStatus.timedOut) {\n      throw createRecoverableNetworkError(ShakaError.Code.TIMEOUT, operationInputs.uri, operationInputs.requestType)\n    } else if (!currentState.abortStatus.finished) {\n      throw createRecoverableNetworkError(ShakaError.Code.HTTP_ERROR, operationInputs.uri, error, operationInputs.requestType)\n    }\n  }\n\n  if (currentState.abortStatus.cancelled) {\n    throw createRecoverableNetworkError(ShakaError.Code.OPERATION_ABORTED, operationInputs.uri, operationInputs.requestType)\n  } else if (currentState.abortStatus.timedOut) {\n    throw createRecoverableNetworkError(ShakaError.Code.TIMEOUT, operationInputs.uri, operationInputs.requestType)\n  }\n\n  if (responseDataChunks.length > 0 && segmentComplete) {\n    const data = /** @__NOINLINE__ */ concatenateChunks(responseDataChunks)\n\n    if (operationInputs.isInit) {\n      currentState.initDataCache.set(operationInputs.formatIdString, data)\n    }\n\n    /** @type {shaka.extern.Response} */\n    return {\n      uri: operationInputs.uri,\n      originalUri: operationInputs.uri,\n      data,\n      status: response.status,\n      headers: {},\n      fromCache: false,\n      originalRequest: operationInputs.request,\n    }\n  } else if (shouldRetry) {\n    if (shouldRetryDueToNextRequestPolicy) {\n      // Only count on actual retry to avoid counting false positive (when segmentComplete\n      currentState.cumulativeRetryDueToNextRequestPolicy += 1\n    }\n\n    const { sabrContexts, unsentSabrContexts } = prepareSabrContexts(currentState.sabrStreamState)\n\n    currentState.abrRequest.streamerContext.sabrContexts = sabrContexts\n    currentState.abrRequest.streamerContext.unsentSabrContexts = unsentSabrContexts\n\n    let body\n\n    try {\n      body = VideoPlaybackAbrRequest.encode(currentState.abrRequest).finish()\n    } catch (error) {\n      console.error('Invalid VideoPlaybackAbrRequest data', currentState.abrRequest)\n      throw error\n    }\n\n    currentState.requestInit = {\n      body,\n      method: 'POST',\n      headers: {\n        'content-type': 'application/x-protobuf',\n        'accept-encoding': 'identity',\n        accept: 'application/vnd.yt-ump',\n      },\n      signal: currentState.abortController.signal,\n    }\n    currentState.abortStatus.timedOut = false\n\n    currentState.abortStatus.finished = false\n    return doRequest(operationInputs, currentState)\n  } else if (invalidPoToken) {\n    throw new ShakaError(\n      ShakaError.Severity.CRITICAL,\n      ShakaError.Category.NETWORK,\n      ShakaError.Code.HTTP_ERROR,\n      operationInputs.uri,\n      new Error('Invalid PO token'),\n      operationInputs.requestType,\n    )\n  } else if (error) {\n    throw createRecoverableNetworkError(\n      ShakaError.Code.HTTP_ERROR,\n      operationInputs.uri,\n      new Error(error),\n      operationInputs.requestType,\n    )\n  } else if (responseDataChunks.length > 0 && !segmentComplete) {\n    throw createRecoverableNetworkError(\n      ShakaError.Code.HTTP_ERROR,\n      operationInputs.uri,\n      new Error('Incomplete segment, missing MEDIA_END part'),\n      operationInputs.requestType,\n    )\n  } else if (response.status === 200) {\n    throw createRecoverableNetworkError(\n      ShakaError.Code.HTTP_ERROR,\n      operationInputs.uri,\n      new Error('Empty response, this should not happen'),\n      operationInputs.requestType,\n    )\n  } else {\n    const severity = response.status === 401 || response.status === 403\n      ? ShakaError.Severity.CRITICAL\n      : ShakaError.Severity.RECOVERABLE\n\n    throw new ShakaError(\n      severity,\n      ShakaError.Category.NETWORK,\n      ShakaError.Code.BAD_HTTP_STATUS,\n      operationInputs.uri,\n      response.status,\n      '',\n      {},\n      operationInputs.requestType,\n      operationInputs.uri,\n    )\n  }\n}\n\n/**\n * @param {import('../../views/Watch/Watch').SabrData} sabrData\n * @param {() => shaka.Player} getPlayer\n * @param {() => shaka.extern.Manifest} getManifest\n * @param {import('vue').ComputedRef<number>} playerWidth\n * @param {import('vue').ComputedRef<number>} playerHeight\n * @return SabrStream\n */\nexport function setupSabrScheme(sabrData, getPlayer, getManifest, playerWidth, playerHeight) {\n  const eventEmitter = new EventEmitterLike()\n\n  /**\n   * Caches the init data until the video ends\n   * that way changing qualities and between audio and DASH\n   * doesn't have to fetch the init data and segment index again\n   * @type {Map<string, Uint8Array>}\n   */\n  const initDataCache = new Map()\n\n  const poToken = base64ToU8(sabrData.poToken)\n  const videoPlaybackUstreamerConfig = base64ToU8(sabrData.ustreamerConfig)\n  const clientInfo = deepCopy(sabrData.clientInfo)\n\n  /** @type {SabrStreamState} */\n  const sabrStreamState = {\n    sabrUrl: sabrData.url,\n    activeSabrContextTypes: new Set(),\n    sabrContexts: new Map(),\n    nextRequestPolicy: undefined,\n    playerReloadRequested: false,\n    requestNumber: 0,\n  }\n\n  shaka.net.NetworkingEngine.registerScheme('sabr', (uri, request, requestType, _progressUpdated, headersReceived, _config) => {\n    // lazily fetch it as the variable is only set after setupSabrScheme is called\n    // but it will definitely exist when we receive a request here.\n    const player = getPlayer()\n    if (player == null) {\n      // This is true during reload, returning a promise to suppress error\n      return new AbortableOperation(Promise.resolve())\n    }\n    const isAudioOnly = player.isAudioOnly()\n\n    const url = new URL(request.uris[0])\n\n    const isInit = url.searchParams.has('init')\n    const formatIdString = url.searchParams.get('formatId')\n\n    if (isInit && initDataCache.has(formatIdString)) {\n      return /** @__NOINLINE__ */ createCacheResponse(uri, request, initDataCache.get(formatIdString))\n    }\n\n    const variantTracks = player.getVariantTracks()\n    const activeVariant = variantTracks.find(track => track.active)\n\n    const streamIsAudio = url.pathname === 'audio'\n    const streamIsVideo = url.pathname === 'video'\n\n    let audioFormatId\n    let videoFormatId\n\n    if (streamIsAudio) {\n      audioFormatId = formatIdFromString(formatIdString)\n\n      if (isAudioOnly) {\n        // We need to specify a video format even for audio only otherwise we get an error response\n        videoFormatId = formatIdFromString(url.searchParams.get('videoFormatId'))\n      } else {\n        videoFormatId = formatIdFromString((activeVariant ?? variantTracks[0]).originalVideoId)\n      }\n    } else if (streamIsVideo) {\n      videoFormatId = formatIdFromString(formatIdString)\n\n      // for the first fetching of the initial data there won't be an active variant\n      // (shaka-player only sets it to active after it has fetched the init/segment data)\n      if (activeVariant) {\n        audioFormatId = formatIdFromString(activeVariant.originalAudioId)\n      } else {\n        const candidates = variantTracks.filter((track) => track.audioRoles.includes('main'))\n\n        const probableAudioFormat = candidates.reduce((previous, current) => {\n          return current.audioBandwidth >= previous.audioBandwidth ? current : previous\n        }, candidates[0])\n\n        audioFormatId = formatIdFromString(probableAudioFormat.originalAudioId)\n      }\n    }\n\n    /** @type {import('googlevideo/protos').BufferedRange[]} */\n    const bufferedRanges = []\n\n    if (!isInit && activeVariant) {\n      /** @__NOINLINE__ */ fillBufferedRanges(player, getManifest(), isAudioOnly, streamIsVideo, streamIsAudio, bufferedRanges, activeVariant)\n    }\n\n    let playerTimeMs = '0'\n\n    if (url.searchParams.has('startTimeMs')) {\n      playerTimeMs = url.searchParams.get('startTimeMs')\n    }\n\n    const drcEnabled = url.searchParams.has('drc') || !!(activeVariant && activeVariant.audioRoles.includes('drc'))\n    const enableVoiceBoost = url.searchParams.has('vb') || !!(activeVariant && activeVariant.audioRoles.includes('vb'))\n\n    const resolution = streamIsVideo ? parseInt(url.searchParams.get('resolution')) : undefined\n\n    const { sabrContexts, unsentSabrContexts } = prepareSabrContexts(sabrStreamState)\n\n    /** @type {VideoPlaybackAbrRequest} */\n    const requestData = {\n      clientAbrState: {\n        bandwidthEstimate: String(Math.round(player.getStats().estimatedBandwidth)),\n        timeSinceLastManualFormatSelectionMs: streamIsVideo ? '0' : undefined,\n        stickyResolution: resolution,\n        lastManualSelectedResolution: resolution,\n        playbackRate: player.getPlaybackRate(),\n        enabledTrackTypesBitfield: streamIsAudio ? 1 : 0,\n        drcEnabled,\n        enableVoiceBoost,\n        playerTimeMs,\n        clientViewportWidth: playerWidth.value,\n        clientViewportHeight: playerHeight.value,\n        clientViewportIsFlexible: false\n      },\n      preferredAudioFormatIds: [audioFormatId],\n      preferredVideoFormatIds: [videoFormatId],\n      preferredSubtitleFormatIds: [],\n      selectedFormatIds: isInit ? [] : [audioFormatId, videoFormatId],\n      bufferedRanges,\n      streamerContext: {\n        poToken,\n        clientInfo,\n        sabrContexts,\n        unsentSabrContexts,\n        playbackCookie: sabrStreamState.nextRequestPolicy?.playbackCookie ? PlaybackCookie.encode(sabrStreamState.nextRequestPolicy.playbackCookie).finish() : undefined,\n      },\n      field1000: [],\n      videoPlaybackUstreamerConfig,\n    }\n\n    let body\n\n    try {\n      body = VideoPlaybackAbrRequest.encode(requestData).finish()\n    } catch (error) {\n      console.error('Invalid VideoPlaybackAbrRequest data', requestData)\n      throw error\n    }\n\n    const sequenceNumber = parseInt(url.searchParams.get('sq'))\n\n    /**\n     * Stores whatever state that should be updated across the whole \"session\"\n     * @type {OperationInputs}\n     */\n    const opInputs = {\n      uri,\n      request,\n      requestType,\n      headersReceived,\n\n      formatIdString,\n      isInit,\n      sequenceNumber,\n    }\n\n    const abortController = new AbortController()\n\n    /** @type {RequestInit} */\n    const init = {\n      body,\n      method: 'POST',\n      headers: {\n        'content-type': 'application/x-protobuf',\n        'accept-encoding': 'identity',\n        accept: 'application/vnd.yt-ump',\n      },\n      signal: abortController.signal,\n    }\n\n    /**\n     * Stores whatever state that should be updated across the whole \"session\"\n     * @type {AbortStatus}\n     */\n    const abortStatus = {\n      cancelled: false,\n      timedOut: false,\n      finished: false,\n    }\n\n    const timeoutMs = request.retryParameters.timeout\n    let timeoutController = null\n    if (timeoutMs) {\n      timeoutController = createTimeoutController(() => {\n        abortStatus.timedOut = true\n        abortController.abort()\n      }, timeoutMs)\n    }\n\n    /**\n     * Stores whatever state that should be updated across the whole \"session\"\n     * @type {CurrentState}\n     */\n    const currentState = {\n      initDataCache,\n      abrRequest: requestData,\n      requestInit: init,\n      abortStatus: abortStatus,\n      abortController,\n      sabrStreamState,\n      timeoutController,\n      eventEmitter,\n      cumulativeBackOffTimeMs: 0,\n      cumulativeBackOffRequested: 0,\n      cumulativeRetryDueToNextRequestPolicy: 0,\n    }\n\n    const pendingRequest = doRequest(opInputs, currentState)\n\n    const op = new AbortableOperation(pendingRequest, () => {\n      abortStatus.cancelled = true\n      abortController.abort()\n      return Promise.resolve()\n    })\n\n    if (timeoutController) {\n      op.finally(() => {\n        timeoutController.clearTimeout()\n      })\n    }\n\n    return op\n  })\n\n  const cleanup = () => {\n    shaka.net.NetworkingEngine.unregisterScheme('sabr')\n    initDataCache.clear()\n  }\n\n  return {\n    onBackoffRequested(callback) {\n      eventEmitter.on('backoff-requested', callback)\n    },\n    onReloadOnce(callback) {\n      eventEmitter.once('reload', callback)\n    },\n    cleanup,\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/WebmSegmentIndexParser.js",
    "content": "// Based on https://github.com/shaka-project/shaka-player/blob/main/lib/dash/webm_segment_index_parser.js\n// Adapted for use in FreeTube:\n// - General changes such as removing Closure compiler specific stuff\n// - Rewritten to use functions instead of a class\n// - The segment URLs receive the start time and segment number\n\nimport shaka from 'shaka-player'\nimport { EbmlParser } from './EbmlParser'\n\nconst EBML_ID = 0x1a45dfa3\nconst SEGMENT_ID = 0x18538067\nconst INFO_ID = 0x1549a966\nconst TIMECODE_SCALE_ID = 0x2ad7b1\nconst DURATION_ID = 0x4489\nconst CUES_ID = 0x1c53bb6b\nconst CUE_POINT_ID = 0xbb\nconst CUE_TIME_ID = 0xb3\nconst CUE_TRACK_POSITIONS_ID = 0xb7\nconst CUE_CLUSTER_POSITION = 0xf1\n\nconst ShakaError = shaka.util.Error\nconst SeverityCritical = ShakaError.Severity.CRITICAL\nconst CategoryMedia = ShakaError.Category.MEDIA\n\n/**\n * Parses SegmentReferences from a WebM container.\n * @param {BufferSource} cuesData The WebM container's \"Cueing Data\" section.\n * @param {BufferSource} initData The WebM container's headers.\n * @param {string} uri The location of the WebM file that contains the segments.\n * @param {shaka.media.InitSegmentReference} initSegmentReference\n * @param {number} timestampOffset\n * @param {number} appendWindowStart\n * @param {number} appendWindowEnd\n * @returns {shaka.media.SegmentReference[]}\n * @see http://www.matroska.org/technical/specs/index.html\n * @see http://www.webmproject.org/docs/container/\n */\nexport function parseWebmSegmentIndex(\n  cuesData,\n  initData,\n  uri,\n  initSegmentReference,\n  timestampOffset,\n  appendWindowStart,\n  appendWindowEnd\n) {\n  const tuple = /** @__NOINLINE__ */ parseWebmContainer(initData)\n  const parser = new EbmlParser(cuesData)\n  const cuesElement = parser.parseElement()\n  if (cuesElement.id !== CUES_ID) {\n    console.error('[parseWebmSegmentIndex] Not a Cues element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_CUES_ELEMENT_MISSING\n    )\n  }\n\n  return /** @__NOINLINE__ */ parseCues(\n    cuesElement,\n    tuple.segmentOffset,\n    tuple.timecodeScale,\n    tuple.duration,\n    uri,\n    initSegmentReference,\n    timestampOffset,\n    appendWindowStart,\n    appendWindowEnd\n  )\n}\n\n/**\n * Parses a WebM container to get the segment's offset, timecode scale, and\n * duration.\n *\n * @param {BufferSource} initData\n * @returns {{segmentOffset: number, timecodeScale: number, duration: number}}\n *   The segment's offset in bytes, the segment's timecode scale in seconds,\n *   and the duration in seconds.\n */\nfunction parseWebmContainer(initData) {\n  const parser = new EbmlParser(initData)\n\n  // Check that the WebM container data starts with the EBML header, but\n  // skip its contents.\n  const ebmlElement = parser.parseElement()\n  if (ebmlElement.id !== EBML_ID) {\n    console.error('Not an EBML element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_EBML_HEADER_ELEMENT_MISSING\n    )\n  }\n\n  const segmentElement = parser.parseElement()\n  if (segmentElement.id !== SEGMENT_ID) {\n    console.error('[parseWebmSegmentIndex] Not a Segment element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_SEGMENT_ELEMENT_MISSING\n    )\n  }\n\n  // This value is used as the initial offset to the first referenced segment.\n  const segmentOffset = segmentElement.getOffset()\n\n  // Parse the Segment element to get the segment info.\n  const segmentInfo = /** @__NOINLINE__ */ parseSegment(segmentElement)\n  return {\n    segmentOffset: segmentOffset,\n    timecodeScale: segmentInfo.timecodeScale,\n    duration: segmentInfo.duration,\n  }\n}\n\n/**\n * Parses a WebM Info element to get the segment's timecode scale and\n * duration.\n * @param {import('./EbmlParser').EbmlElement} segmentElement\n * @returns {{timecodeScale: number, duration: number}} The segment's timecode\n *   scale in seconds and duration in seconds.\n */\nfunction parseSegment(segmentElement) {\n  const parser = segmentElement.createParser()\n\n  // Find the Info element.\n  let infoElement = null\n  while (parser.hasMoreData()) {\n    const elem = parser.parseElement()\n    if (elem.id !== INFO_ID) {\n      continue\n    }\n\n    infoElement = elem\n\n    break\n  }\n\n  if (!infoElement) {\n    console.error('[parseWebmSegmentIndex] Not an Info element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_INFO_ELEMENT_MISSING\n    )\n  }\n\n  return /** @__NOINLINE__ */ parseInfo(infoElement)\n}\n\n/**\n * Parses a WebM Info element to get the segment's timecode scale and\n * duration.\n * @param {import('./EbmlParser').EbmlElement} infoElement\n * @returns {{timecodeScale: number, duration: number}} The segment's timecode\n *   scale in seconds and duration in seconds.\n */\nfunction parseInfo(infoElement) {\n  const parser = infoElement.createParser()\n\n  // The timecode scale factor in units of [nanoseconds / T], where [T] are\n  // the units used to express all other time values in the WebM container.\n  // By default it's assumed that [T] == [milliseconds].\n  let timecodeScaleNanoseconds = 1000000\n  /** @type {?number} */\n  let durationScale = null\n\n  while (parser.hasMoreData()) {\n    const elem = parser.parseElement()\n    if (elem.id === TIMECODE_SCALE_ID) {\n      timecodeScaleNanoseconds = elem.getUint()\n    } else if (elem.id === DURATION_ID) {\n      durationScale = elem.getFloat()\n    }\n  }\n  if (durationScale == null) {\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_DURATION_ELEMENT_MISSING\n    )\n  }\n\n  // The timecode scale factor in units of [seconds / T].\n  const timecodeScale = timecodeScaleNanoseconds / 1000000000\n  // The duration is stored in units of [T]\n  const durationSeconds = durationScale * timecodeScale\n\n  return { timecodeScale: timecodeScale, duration: durationSeconds }\n}\n\n/**\n * Parses a WebM CuesElement.\n * @param {import('./EbmlParser').EbmlElement} cuesElement\n * @param {number} segmentOffset\n * @param {number} timecodeScale\n * @param {number} duration\n * @param {string} uri\n * @param {shaka.media.InitSegmentReference} initSegmentReference\n * @param {number} timestampOffset\n * @param {number} appendWindowStart\n * @param {number} appendWindowEnd\n * @returns {shaka.media.SegmentReference[]}\n */\nfunction parseCues(\n  cuesElement,\n  segmentOffset,\n  timecodeScale,\n  duration,\n  uri,\n  initSegmentReference,\n  timestampOffset,\n  appendWindowStart,\n  appendWindowEnd\n) {\n  const references = []\n\n  const parser = cuesElement.createParser()\n\n  let lastTime = null\n  let lastOffset = null\n  let sq = 1\n\n  while (parser.hasMoreData()) {\n    const elem = parser.parseElement()\n    if (elem.id !== CUE_POINT_ID) {\n      continue\n    }\n\n    const tuple = parseCuePoint(elem)\n    if (!tuple) {\n      continue\n    }\n\n    // Subtract the presentation time offset from the unscaled time\n    const currentTime = timecodeScale * tuple.unscaledTime\n    const currentOffset = segmentOffset + tuple.relativeOffset\n\n    if (lastTime != null) {\n      if (process.env.NODE_ENV === 'development' && lastOffset == null) {\n        throw new Error('Assertion failure: last offset cannot be null')\n      }\n\n      const uris = [`${uri}&startTimeMs=${Math.round((lastTime + timestampOffset) * 1000)}&sq=${sq++}`]\n\n      references.push(\n        new shaka.media.SegmentReference(\n          lastTime + timestampOffset,\n          currentTime + timestampOffset,\n          () => uris,\n          /* startByte= */ lastOffset, /* endByte= */ currentOffset - 1,\n          initSegmentReference,\n          timestampOffset,\n          appendWindowStart,\n          appendWindowEnd\n        )\n      )\n    }\n\n    lastTime = currentTime\n    lastOffset = currentOffset\n  }\n\n  if (lastTime != null) {\n    if (process.env.NODE_ENV === 'development' && lastOffset == null) {\n      throw new Error('Assertion failure: last offset cannot be null')\n    }\n\n    const uris = [`${uri}&startTimeMs=${Math.round((lastTime + timestampOffset) * 1000)}&sq=${sq}`]\n\n    references.push(\n      new shaka.media.SegmentReference(\n        lastTime + timestampOffset,\n        duration + timestampOffset,\n        () => uris,\n        /* startByte= */ lastOffset, /* endByte= */ null,\n        initSegmentReference,\n        timestampOffset,\n        appendWindowStart,\n        appendWindowEnd\n      )\n    )\n  }\n\n  return references\n}\n\n/**\n * Parses a WebM CuePointElement to get an \"unadjusted\" segment reference.\n * @param {import('./EbmlParser').EbmlElement} cuePointElement\n * @returns {{unscaledTime: number, relativeOffset: number}} The referenced\n *   segment's start time in units of [T] (see parseInfo_()), and the\n *   referenced segment's offset in bytes, relative to a WebM Segment\n *   element.\n */\nfunction parseCuePoint(cuePointElement) {\n  const parser = cuePointElement.createParser()\n\n  // Parse CueTime element.\n  const cueTimeElement = parser.parseElement()\n  if (cueTimeElement.id !== CUE_TIME_ID) {\n    console.warn('[parseWebmSegmentIndex] Not a CueTime element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_CUE_TIME_ELEMENT_MISSING\n    )\n  }\n  const unscaledTime = cueTimeElement.getUint()\n\n  // Parse CueTrackPositions element.\n  const cueTrackPositionsElement = parser.parseElement()\n  if (cueTrackPositionsElement.id !== CUE_TRACK_POSITIONS_ID) {\n    console.warn('[parseWebmSegmentIndex] Not a CueTrackPositions element.')\n    throw new ShakaError(\n      SeverityCritical,\n      CategoryMedia,\n      ShakaError.Code.WEBM_CUE_TRACK_POSITIONS_ELEMENT_MISSING\n    )\n  }\n\n  const cueTrackParser = cueTrackPositionsElement.createParser()\n  let relativeOffset = 0\n\n  while (cueTrackParser.hasMoreData()) {\n    const elem = cueTrackParser.parseElement()\n    if (elem.id !== CUE_CLUSTER_POSITION) {\n      continue\n    }\n\n    relativeOffset = elem.getUint()\n    break\n  }\n\n  return { unscaledTime: unscaledTime, relativeOffset: relativeOffset }\n}\n"
  },
  {
    "path": "src/renderer/helpers/player/utils.js",
    "content": "import shaka from 'shaka-player'\nimport { deepCopy } from '../utils'\nimport i18n from '../../i18n/index'\nimport { sponsorBlockSkipSegments } from '../sponsorblock'\n\n/** @typedef {import('../sponsorblock').SponsorBlockCategory} SponsorBlockCategory */\n\n/**\n * @param {shaka.util.Error} error\n * @param {string} context\n * @param {string} videoId\n * @param {object?} details\n */\nexport function logShakaError(error, context, videoId, details) {\n  const { Severity, Category, Code } = shaka.util.Error\n\n  // shaka's error type also has a message property but that is apparently only available in uncompiled mode\n\n  /** @type {keyof Severity} */\n  const severityText = Object.keys(Severity).find((/** @type {keyof Severity} */ key) => Severity[key] === error.severity)\n\n  /** @type {keyof Category} */\n  const categoryText = Object.keys(Category).find((/** @type {keyof Category} */ key) => Category[key] === error.category)\n\n  /** @type {keyof Code} */\n  const codeText = Object.keys(Code).find((/** @type {keyof Code} */ key) => Code[key] === error.code)\n\n  const message =\n    'Player Error (category and code explainations here: https://shaka-player-demo.appspot.com/docs/api/shaka.util.Error.html)\\n' +\n    `Video ID: \"${videoId}\"\\n` +\n    `FreeTube player context: \"${context}\"\\n\\n` +\n    `Severity: ${severityText} (${error.severity})\\n` +\n    `Category: ${categoryText} (${error.category})\\n` +\n    `Code: ${codeText} (${error.code})\\n` +\n    `Stack trace:\\n${error.stack}`\n\n  /** @type {*[]} */\n  const args = [message]\n\n  if (error.data && error.data.length > 0) {\n    args.push(\n      '\\n\\nshaka-player Data:',\n      error.data\n    )\n  }\n\n  if (details) {\n    args.push(\n      '\\n\\nFreeTube data:',\n      // use deepCopy to get rid of Vue's proxying,\n      // as that requires you click the 3 dots for every property in the logged object to see their values\n      // doing it like this, results in a \"clean\" object where everything is immediately visible\n      typeof details === 'object' ? deepCopy(details) : details\n    )\n  }\n\n  console.error(...args)\n}\n\n/**\n * @param {string} videoId\n * @param {SponsorBlockCategory[]} categories\n */\nexport async function getSponsorBlockSegments(videoId, categories) {\n  const segments = await sponsorBlockSkipSegments(videoId, categories)\n\n  if (segments.length === 0) {\n    return {\n      segments: [],\n      averageDuration: 0\n    }\n  }\n\n  const averageDuration = segments.reduce((accumulator, segment) => {\n    return accumulator + segment.videoDuration\n  }, 0) / segments.length\n\n  const mappedSegments = segments.map(({ category, segment: [startTime, endTime], UUID }) => {\n    return {\n      uuid: UUID,\n      category,\n      startTime,\n      endTime\n    }\n  })\n\n  mappedSegments.sort((a, b) => a.startTime - b.startTime)\n\n  return {\n    segments: mappedSegments,\n    averageDuration\n  }\n}\n\n/**\n * @param {SponsorBlockCategory} category\n */\nexport function translateSponsorBlockCategory(category) {\n  switch (category) {\n    case 'sponsor':\n      return i18n.global.t('Video.Sponsor Block category.sponsor')\n    case 'intro':\n      return i18n.global.t('Video.Sponsor Block category.intro')\n    case 'outro':\n      return i18n.global.t('Video.Sponsor Block category.outro')\n    case 'recap':\n      return i18n.global.t('Video.Sponsor Block category.recap')\n    case 'selfpromo':\n      return i18n.global.t('Video.Sponsor Block category.self-promotion')\n    case 'interaction':\n      return i18n.global.t('Video.Sponsor Block category.interaction')\n    case 'music_offtopic':\n      return i18n.global.t('Video.Sponsor Block category.music offtopic')\n    case 'filler':\n      return i18n.global.t('Video.Sponsor Block category.filler')\n    default:\n      console.error(`Unknown translation for SponsorBlock category ${category}`)\n      return category\n  }\n}\n\n/**\n * Moves the captions that are the most similar to the display language to the top\n * and sorts the remaining ones alphabetically.\n * @param {{\n *   url: string,\n *   label: string,\n *   language: string,\n *   mimeType: string,\n *   isAutotranslated?: boolean\n * }[]} captions\n */\nexport function sortCaptions(captions) {\n  const currentLocale = i18n.global.locale\n  const userLocale = currentLocale.split('-') // ex. [en,US]\n\n  const collator = new Intl.Collator([currentLocale, 'en'])\n\n  return captions.sort((captionA, captionB) => {\n    const aCode = captionA.language.split('-') // ex. [en,US] or [en]\n    const bCode = captionB.language.split('-')\n    const aName = captionA.label // ex: english (auto-generated)\n    const bName = captionB.label\n    const aIsAutotranslated = !!captionA.isAutotranslated\n    const bIsAutotranslated = !!captionB.isAutotranslated\n    if (aCode[0] === userLocale[0]) { // caption a has same language as user's locale\n      if (bCode[0] === userLocale[0]) { // caption b has same language as user's locale\n        if (bName.includes('auto')) {\n          // prefer caption a: b is auto-generated captions\n          return -1\n        } else if (aName.includes('auto')) {\n          // prefer caption b: a is auto-generated captions\n          return 1\n        } else if (bIsAutotranslated) {\n          // prefer caption a: b is auto-translated captions\n          return -1\n        } else if (aIsAutotranslated) {\n          // prefer caption b: a is auto-translated captions\n          return 1\n        } else if (aCode[1] === userLocale[1]) {\n          // prefer caption a: caption a has same county code as user's locale\n          return -1\n        } else if (bCode[1] === userLocale[1]) {\n          // prefer caption b: caption b has same county code as user's locale\n          return 1\n        } else if (aCode[1] === undefined) {\n          // prefer caption a: no country code is better than wrong country code\n          return -1\n        } else if (bCode[1] === undefined) {\n          // prefer caption b: no country code is better than wrong country code\n          return 1\n        }\n      } else {\n        // prefer caption a: b does not match user's language\n        return -1\n      }\n    } else if (bCode[0] === userLocale[0]) {\n      // prefer caption b: a does not match user's language\n      return 1\n    }\n    // sort alphabetically\n    return collator.compare(aName, bName)\n  })\n}\n\n/**\n * When the build doesn't support the local API\n * we have to use Invidious' DASH manifest, instead of generating our own one.\n * This function cleans it up, so that we can use it.\n *\n * Here is a list of things this function does:\n * - Removes bogus roles and labels\n * - Extracts the languages from the audio URLs if available and adds it to the adapation sets\n * - Adds roles and labels when possible to add support for multiple audio tracks\n *\n * Things this function does not do:\n * - Separate DRC (Stable Volume) from their original counterparts\n * - Tag HDR video streams (Invidious puts all video streams in the same adaptation set,\n * to tag HDR and SDR streams we would have to separate them out into multiple adaptation sets)\n * @param {shaka.extern.xml.Node[]} periods\n */\nexport function repairInvidiousManifest(periods) {\n  /** @type {shaka.extern.xml.Node[]} */\n  const audioAdaptationSets = []\n\n  for (const period of periods) {\n    if (Array.isArray(period.children)) {\n      for (const periodChild of period.children) {\n        if (typeof periodChild !== 'string' && periodChild.tagName === 'AdaptationSet' && periodChild.attributes.mimeType?.startsWith('audio/')) {\n          audioAdaptationSets.push(periodChild)\n        }\n      }\n    }\n  }\n\n  // match YouTube's local API response with English\n  const languageNames = new Intl.DisplayNames('en-US', { type: 'language', languageDisplay: 'standard' })\n\n  for (const audioAdaptationSet of audioAdaptationSets) {\n    // Invidious adds a label to every audio stream with it's bitrate\n    // we need to remove those labels, so that they don't get treated as multiple audio tracks\n    if (audioAdaptationSet.attributes.label) {\n      delete audioAdaptationSet.attributes.label\n    }\n\n    if (Array.isArray(audioAdaptationSet.children)) {\n      // Invidious gives the first audio stream the main role and then the rest of them the alternate role\n      // regardless of which one is actually the main track\n      const roleIndex = audioAdaptationSet.children.findIndex((adaptationSetChild) => {\n        return typeof adaptationSetChild !== 'string' && adaptationSetChild.tagName === 'Role'\n      })\n\n      if (roleIndex !== -1) {\n        audioAdaptationSet.children.splice(roleIndex, 1)\n      }\n\n      // Extract the language and audio content type from the URL if available\n      // and add the language, role and label to the adaption set\n\n      /** @type {shaka.extern.xml.Node | undefined} */\n      const representation = audioAdaptationSet.children\n        .find((child) => typeof child !== 'string' && child.tagName === 'Representation')\n\n      if (representation && Array.isArray(representation.children)) {\n        /** @type {string | undefined} */\n        const baseUrl = representation.children\n          .find((child) => typeof child !== 'string' && child.tagName === 'BaseURL')\n          ?.children[0]\n\n        if (baseUrl) {\n          const url = new URL(baseUrl.replaceAll('&amp;', '&'))\n\n          if (url.searchParams.has('xtags')) {\n            const xtags = url.searchParams.get('xtags').split(':')\n\n            const lang = xtags.find(xtag => xtag.startsWith('lang='))?.replace('lang=', '')\n            const audioContent = xtags.find(xtag => xtag.startsWith('acont='))?.replace('acont=', '')\n\n            const labelParts = []\n\n            if (lang) {\n              audioAdaptationSet.attributes.lang = lang\n\n              labelParts.push(languageNames.of(lang))\n            }\n\n            if (audioContent) {\n              let role\n\n              switch (audioContent) {\n                case 'original':\n                  role = 'main'\n                  labelParts.push('original')\n                  break\n                case 'dubbed':\n                case 'dubbed-auto':\n                  role = 'dub'\n                  break\n                case 'descriptive':\n                  role = 'description'\n                  labelParts.push('descriptive')\n                  break\n                case 'secondary':\n                  role = 'alternate'\n                  labelParts.push('secondary')\n                  break\n                default:\n                  role = 'alternate'\n                  labelParts.push('alternative')\n                  break\n              }\n\n              audioAdaptationSet.children.push({\n                tagName: 'Role',\n                attributes: {\n                  schemeIdUri: 'urn:mpeg:dash:role:2011',\n                  value: role\n                },\n                children: [],\n                parent: audioAdaptationSet\n              })\n            }\n\n            if (labelParts.length > 0) {\n              audioAdaptationSet.attributes.label = labelParts.join(' ')\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\n/**\n * @param {shaka.extern.TrackList} variants\n * @param {number} bandwidthToMatch\n */\nexport function findMostSimilarAudioBandwidth(variants, bandwidthToMatch) {\n  let closestAudioBandwithDifference = Infinity\n  let closestVariant\n\n  for (const variant of variants) {\n    const difference = Math.abs(variant.audioBandwidth - bandwidthToMatch)\n\n    if (difference < closestAudioBandwithDifference) {\n      closestAudioBandwithDifference = difference\n      closestVariant = variant\n    }\n  }\n\n  return closestVariant\n}\n\n/**\n * @param {shaka.extern.AudioTrack[]} tracks\n */\nexport function deduplicateAudioTracks(tracks) {\n  /** @type {Map<string, shaka.extern.AudioTrack>} */\n  const knownTracks = new Map()\n\n  for (const track of tracks) {\n    const id = `${track.label}_${track.language}_${track.channelsCount}_${track.spatialAudio}`\n\n    if (!knownTracks.has(id) || track.active) {\n      knownTracks.set(id, track)\n    }\n  }\n\n  return knownTracks\n}\n"
  },
  {
    "path": "src/renderer/helpers/playlists.js",
    "content": "export const SORT_BY_VALUES = {\n  DateAddedNewest: 'date_added_descending',\n  DateAddedOldest: 'date_added_ascending',\n  PublishedNewest: 'published_descending',\n  PublishedOldest: 'published_ascending',\n  AuthorAscending: 'author_ascending',\n  AuthorDescending: 'author_descending',\n  VideoTitleAscending: 'video_title_ascending',\n  VideoTitleDescending: 'video_title_descending',\n  VideoDurationAscending: 'video_duration_ascending',\n  VideoDurationDescending: 'video_duration_descending',\n  Custom: 'custom'\n}\n\nexport function getSortedPlaylistItems(playlistItems, sortOrder, locale, reversed = false) {\n  if (sortOrder === SORT_BY_VALUES.Custom) {\n    return reversed ? playlistItems.toReversed() : playlistItems\n  }\n\n  let collator\n\n  if (\n    sortOrder === SORT_BY_VALUES.VideoTitleAscending ||\n    sortOrder === SORT_BY_VALUES.VideoTitleDescending ||\n    sortOrder === SORT_BY_VALUES.AuthorAscending ||\n    sortOrder === SORT_BY_VALUES.AuthorDescending ||\n    sortOrder === SORT_BY_VALUES.VideoDurationAscending ||\n    sortOrder === SORT_BY_VALUES.VideoDurationDescending\n  ) {\n    collator = new Intl.Collator([locale, 'en'])\n  }\n\n  return playlistItems.toSorted((a, b) => {\n    const first = !reversed ? a : b\n    const second = !reversed ? b : a\n    return compareTwoPlaylistItems(first, second, sortOrder, collator)\n  })\n}\n\nexport function videoDurationPresent(video) {\n  if (typeof video.lengthSeconds !== 'number') { return false }\n\n  return !(isNaN(video.lengthSeconds) || video.lengthSeconds === 0)\n}\n\nexport function videoDurationWithFallback(video) {\n  if (videoDurationPresent(video)) { return video.lengthSeconds }\n\n  // Fallback\n  return 0\n}\n\nfunction publishedWithFallback(video) {\n  const published = video.published\n  return typeof published === 'number' && !isNaN(published) && published !== 0 ? published : 0\n}\n\nfunction compareTwoPlaylistItems(a, b, sortOrder, collator) {\n  switch (sortOrder) {\n    case SORT_BY_VALUES.DateAddedNewest:\n      return b.timeAdded - a.timeAdded\n    case SORT_BY_VALUES.DateAddedOldest:\n      return a.timeAdded - b.timeAdded\n    case SORT_BY_VALUES.PublishedNewest:\n      return publishedWithFallback(b) - publishedWithFallback(a)\n    case SORT_BY_VALUES.PublishedOldest:\n      return publishedWithFallback(a) - publishedWithFallback(b)\n    case SORT_BY_VALUES.VideoTitleAscending:\n      return collator.compare(a.title, b.title)\n    case SORT_BY_VALUES.VideoTitleDescending:\n      return collator.compare(b.title, a.title)\n    case SORT_BY_VALUES.AuthorAscending:\n      return collator.compare(a.author, b.author)\n    case SORT_BY_VALUES.AuthorDescending:\n      return collator.compare(b.author, a.author)\n    case SORT_BY_VALUES.VideoDurationAscending: {\n      return videoDurationWithFallback(a) - videoDurationWithFallback(b)\n    }\n    case SORT_BY_VALUES.VideoDurationDescending: {\n      return videoDurationWithFallback(b) - videoDurationWithFallback(a)\n    }\n    default:\n      console.error(`Unknown sortOrder: ${sortOrder}`)\n      return 0\n  }\n}\n\nexport const generateRandomUniqueId = crypto.randomUUID\n  ? crypto.randomUUID.bind(crypto)\n  : () => `id-${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\n/**\n * @param {any} videoData\n */\nexport function processToBeAddedPlaylistVideo(videoData) {\n  if (videoData.timeAdded == null) {\n    videoData.timeAdded = Date.now()\n  }\n\n  if (videoData.playlistItemId == null) {\n    videoData.playlistItemId = generateRandomUniqueId()\n  }\n\n  // For backward compatibility\n  if (videoData.type == null) {\n    videoData.type = 'video'\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/sponsorblock.js",
    "content": "import store from '../store/index'\n\nasync function getVideoHash(videoId) {\n  const videoIdBuffer = new TextEncoder().encode(videoId)\n\n  const hashBuffer = await crypto.subtle.digest('SHA-256', videoIdBuffer)\n  const hashArray = new Uint8Array(hashBuffer)\n\n  return hashArray[0].toString(16).padStart(2, '0') +\n    hashArray[1].toString(16).padStart(2, '0')\n}\n\n/**\n * @typedef {'sponsor' | 'selfpromo' | 'interaction' | 'intro' | 'outro' | 'preview' | 'music_offtopic' | 'filler'} SponsorBlockCategory\n */\n\n/**\n * @param {string} videoId\n * @param {SponsorBlockCategory[]} categories\n * @returns {Promise<{\n *   UUID: string,\n *   actionType: string,\n *   category: SponsorBlockCategory,\n *   description: string,\n *   locked: 1|0,\n *   segment: [\n *     number,\n *     number\n *   ],\n *   videoDuration: number,\n *   votes: number\n * }[]>}\n */\nexport async function sponsorBlockSkipSegments(videoId, categories) {\n  const videoIdHashPrefix = await getVideoHash(videoId)\n  const requestUrl = `${store.getters.getSponsorBlockUrl}/api/skipSegments/${videoIdHashPrefix}?categories=${JSON.stringify(categories)}`\n\n  try {\n    const response = await fetch(requestUrl)\n\n    // 404 means that there are no segments registered for the video\n    if (response.status === 404) {\n      return []\n    }\n\n    // Sometimes the sponsor block server goes down or returns other errors\n    if (!response.ok) {\n      throw new Error(await response.text())\n    }\n\n    const json = await response.json()\n    return json\n      .filter((result) => result.videoID === videoId)\n      .flatMap((result) => result.segments)\n  } catch (error) {\n    console.error('failed to fetch SponsorBlock segments', requestUrl, error)\n    throw error\n  }\n}\n\nexport async function deArrowData(videoId) {\n  const videoIdHashPrefix = await getVideoHash(videoId)\n  const requestUrl = `${store.getters.getSponsorBlockUrl}/api/branding/${videoIdHashPrefix}`\n\n  try {\n    const response = await fetch(requestUrl)\n\n    // 404 means that there are no segments registered for the video\n    if (response.status === 404) {\n      return undefined\n    }\n\n    const json = await response.json()\n    return json[videoId] ?? undefined\n  } catch (error) {\n    console.error('failed to fetch DeArrow data', requestUrl, error)\n    throw error\n  }\n}\n\nexport async function deArrowThumbnail(videoId, timestamp) {\n  let requestUrl = `${store.getters.getDeArrowThumbnailGeneratorUrl}/api/v1/getThumbnail?videoID=` + videoId\n  if (timestamp != null) {\n    requestUrl += `&time=${timestamp}`\n  }\n\n  try {\n    const response = await fetch(requestUrl)\n\n    // 204 means that there are no thumbnails found for the video\n    if (response.status === 204) {\n      return undefined\n    }\n\n    if (response.ok) {\n      return response.url\n    }\n\n    // this usually means that a thumbnail was not generated on the server yet so we'll log the error but otherwise ignore it.\n    const json = await response.json()\n    console.error(json)\n    return undefined\n  } catch (error) {\n    console.error('failed to fetch DeArrow data', requestUrl, error)\n    throw error\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/strings.js",
    "content": "import i18n from '../i18n/index'\n\n/**\n * This will return true if a string is null, undefined or empty.\n * @param {string|null|undefined} _string the string to process\n * @returns {boolean} whether the string is empty or not\n */\nexport function isNullOrEmpty(_string) {\n  return _string == null || _string === ''\n}\n\n/**\n * Is KeyboardEvent.key a printable char\n * @param {string} eventKey the string from KeyboardEvent.key to process\n * @returns {boolean} whether the string from KeyboardEvent.key is a printable char or not\n */\nexport function isKeyboardEventKeyPrintableChar(eventKey) {\n  // Most printable chars are all strings with length 1 (except Unicode)\n  // https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n  // https://www.w3.org/TR/DOM-Level-3-Events-key/\n  if (eventKey.length === 1) { return true }\n  // Emoji\n  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape\n  if (/\\p{Emoji_Presentation}/u.test(eventKey)) { return true }\n\n  return false\n}\n\n/**\n * @param {string} title\n */\nexport function translateWindowTitle(title) {\n  switch (title) {\n    case 'Subscriptions':\n      return i18n.global.t('Subscriptions.Subscriptions')\n    case 'Channels':\n      return i18n.global.t('Channels.Title')\n    case 'Trending':\n      return i18n.global.t('Trending.Trending')\n    case 'Most Popular':\n      return i18n.global.t('Most Popular')\n    case 'Your Playlists':\n      return i18n.global.t('User Playlists.Your Playlists')\n    case 'History':\n      return i18n.global.t('History.History')\n    case 'Settings':\n      return i18n.global.t('Settings.Settings')\n    case 'About':\n      return i18n.global.t('About.About')\n    case 'Profile Settings':\n      return i18n.global.t('Profile.Profile Settings')\n    case 'Playlist':\n      return i18n.global.t('Playlist.Playlist')\n    default:\n      return null\n  }\n}\n\n/**\n * Returns the first user-perceived character,\n * respecting language specific rules and\n * emojis made up of multiple codepoints\n * like flags, families and skin tone modifiers.\n * @param {string} text\n * @param {string} locale\n * @returns {string}\n */\nexport function getFirstCharacter(text, locale) {\n  if (text.length === 0) {\n    return ''\n  }\n\n  const segmenter = new Intl.Segmenter([locale, 'en'], { granularity: 'grapheme' })\n\n  // Use iterator directly as we only need the first segment\n  const firstSegment = segmenter.segment(text)[Symbol.iterator]().next().value\n  return firstSegment.segment\n}\n"
  },
  {
    "path": "src/renderer/helpers/subscriptions.js",
    "content": "import store from '../store/index'\n\n/**\n * Filtering and sort based on user preferences\n * @param {any[]} videos\n */\nexport function updateVideoListAfterProcessing(videos) {\n  let videoList = videos\n\n  if (store.getters.getHideLiveStreams) {\n    videoList = videoList.filter(item => {\n      return (!item.liveNow && !item.isUpcoming)\n    })\n  }\n\n  if (store.getters.getHideUpcomingPremieres) {\n    videoList = videoList.filter(item => {\n      if (item.isRSS) {\n        // viewCount is our only method of detecting premieres in RSS\n        // data without sending an additional request.\n        // If we ever get a better flag, use it here instead.\n        return item.viewCount !== '0'\n      }\n      // Observed for premieres in Local API Subscriptions.\n      return (item.premiereDate == null ||\n        // Invidious API\n        // `premiereTimestamp` only available on premiered videos\n        // https://docs.invidious.io/api/common_types/#videoobject\n        item.premiereTimestamp == null\n      )\n    })\n  }\n\n  // ordered last to show first eligible video from channel\n  // if the first one incidentally failed one of the above checks\n  if (store.getters.getOnlyShowLatestFromChannel) {\n    const authors = new Map()\n    videoList = videoList.filter((video) => {\n      if (!video.authorId) {\n        return true\n      }\n\n      if (!authors.has(video.authorId)) {\n        authors.set(video.authorId, 1)\n        return true\n      } else {\n        const currentVideos = authors.get(video.authorId)\n\n        if (currentVideos < store.getters.getOnlyShowLatestFromChannelNumber) {\n          authors.set(video.authorId, currentVideos + 1)\n          return true\n        }\n      }\n\n      return false\n    })\n  }\n\n  videoList.sort((a, b) => {\n    return b.published - a.published\n  })\n\n  return videoList\n}\n\n/**\n * @param {string} rssString\n * @param {string} channelId\n */\nexport async function parseYouTubeRSSFeed(rssString, channelId) {\n  // doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel\n  try {\n    const xmlDom = new DOMParser().parseFromString(rssString, 'application/xml')\n    const channelName = xmlDom.querySelector('author > name').textContent\n    const entries = xmlDom.querySelectorAll('entry')\n\n    const promises = []\n\n    for (const entry of entries) {\n      promises.push(parseRSSEntry(entry, channelId, channelName))\n    }\n\n    return {\n      name: channelName,\n      videos: await Promise.all(promises)\n    }\n  } catch {\n    return {\n      videos: []\n    }\n  }\n}\n\n/**\n * @param {Element} entry\n * @param {string} channelId\n * @param {string} channelName\n */\nasync function parseRSSEntry(entry, channelId, channelName) {\n  // doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel\n\n  const rawViewCount = entry.getElementsByTagName('media:statistics')[0]?.getAttribute('views')\n\n  let viewCount = null\n\n  if (rawViewCount) {\n    const parsedViewCount = parseInt(rawViewCount)\n\n    if (!isNaN(parsedViewCount)) {\n      viewCount = parsedViewCount\n    }\n  }\n\n  return {\n    authorId: channelId,\n    author: channelName,\n    // querySelector doesn't support xml namespaces so we have to use getElementsByTagName here\n    videoId: entry.getElementsByTagName('yt:videoId')[0].textContent,\n    title: entry.querySelector('title').textContent,\n    published: Date.parse(entry.querySelector('published').textContent),\n    viewCount,\n    type: 'video',\n    lengthSeconds: '0:00',\n    isRSS: true\n  }\n}\n"
  },
  {
    "path": "src/renderer/helpers/utils.js",
    "content": "import { nextTick } from 'vue'\nimport i18n from '../i18n/index'\nimport router from '../router/index'\nimport { UnsupportedPlayerActions } from '../../constants'\n\n// allowed characters in channel handle: A-Z, a-z, 0-9, -, _, .\n// https://support.google.com/youtube/answer/11585688#change_handle\nexport const CHANNEL_HANDLE_REGEX = /^@[\\w.-]{3,30}$/\n\nconst PUBLISHED_TEXT_REGEX = /(\\d+)\\s?([a-z]+)/i\n\n/**\n * @param {string} sortPreference\n * @returns {string[]}\n */\nexport function getIconForSortPreference(sortPreference) {\n  switch (sortPreference) {\n    case 'name_descending':\n    case 'author_descending':\n    case 'video_title_descending':\n      // text descending\n      return ['fas', 'sort-alpha-down-alt']\n    case 'name_ascending':\n    case 'author_ascending':\n    case 'video_title_ascending':\n      // text ascending\n      return ['fas', 'sort-alpha-down']\n    case 'latest_updated_first':\n    case 'latest_created_first':\n    case 'latest_played_first':\n    case 'date_added_descending':\n    case 'published_descending':\n    case 'last':\n    case 'newest':\n    case 'popular':\n    case 'custom':\n      // quantity descending\n      return ['fas', 'arrow-down-wide-short']\n    case 'earliest_updated_first':\n    case 'earliest_created_first':\n    case 'earliest_played_first':\n    case 'date_added_ascending':\n    case 'published_ascending':\n    case 'oldest':\n    default:\n      // quantity ascending\n      return ['fas', 'arrow-down-short-wide']\n  }\n}\n\n/**\n * @param {string} publishedText\n * @param {boolean} isLive\n * @param {boolean} isUpcoming\n * @param {Date|undefined} premiereDate\n */\nexport function calculatePublishedDate(publishedText, isLive = false, isUpcoming = false, premiereDate = undefined) {\n  const now = Date.now()\n\n  if (isLive) {\n    return now\n  } else if (isUpcoming) {\n    if (premiereDate) {\n      return premiereDate.getTime()\n    } else {\n      // should never happen but just to be sure that we always return a number\n      return now\n    }\n  }\n\n  if (!publishedText) {\n    console.error(\"publishedText is missing but the video isn't live or upcoming\")\n    return undefined\n  }\n\n  const match = publishedText.match(PUBLISHED_TEXT_REGEX)\n\n  const timeFrame = match[2]\n  const timeAmount = parseInt(match[1])\n  let timeSpan = null\n\n  if (timeFrame.startsWith('second') || timeFrame === 's') {\n    timeSpan = timeAmount * 1000\n  } else if (timeFrame.startsWith('minute') || timeFrame === 'm') {\n    timeSpan = timeAmount * 60000\n  } else if (timeFrame.startsWith('hour') || timeFrame === 'h') {\n    timeSpan = timeAmount * 3600000\n  } else if (timeFrame.startsWith('day') || timeFrame === 'd') {\n    timeSpan = timeAmount * 86400000\n  } else if (timeFrame.startsWith('week') || timeFrame === 'w') {\n    timeSpan = timeAmount * 604800000\n  } else if (timeFrame.startsWith('month') || timeFrame === 'mo') {\n    // 30 day month being used\n    timeSpan = timeAmount * 2592000000\n  } else if (timeFrame.startsWith('year') || timeFrame === 'y') {\n    timeSpan = timeAmount * 31556952000\n  }\n\n  return now - timeSpan\n}\n\n/**\n * @param {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData} storyboard\n * @param {number} videoLengthSeconds\n * @returns {string}\n */\nexport function buildVTTFileLocally(storyboard, videoLengthSeconds) {\n  let vttString = 'WEBVTT\\n\\n'\n  // how many images are in one image\n  const numberOfSubImagesPerImage = storyboard.columns * storyboard.rows\n  // the number of storyboard images\n  const numberOfImages = Math.ceil(storyboard.thumbnail_count / numberOfSubImagesPerImage)\n  let intervalInSeconds\n  if (storyboard.interval > 0) {\n    intervalInSeconds = storyboard.interval / 1000\n  } else {\n    intervalInSeconds = videoLengthSeconds / (numberOfImages * numberOfSubImagesPerImage)\n  }\n  let startHours = 0\n  let startMinutes = 0\n  let startSeconds = 0\n  let endHours = 0\n  let endMinutes = 0\n  let endSeconds = intervalInSeconds\n  for (let i = 0; i < numberOfImages; i++) {\n    const currentUrl = storyboard.template_url.replace('$M.jpg', `${i}.jpg`)\n    let xCoord = 0\n    let yCoord = 0\n    for (let j = 0; j < numberOfSubImagesPerImage; j++) {\n      // add the timestamp information\n      const paddedStartHours = startHours.toString().padStart(2, '0')\n      const paddedStartMinutes = startMinutes.toString().padStart(2, '0')\n      const paddedStartSeconds = startSeconds.toFixed(3).padStart(6, '0')\n      const paddedEndHours = endHours.toString().padStart(2, '0')\n      const paddedEndMinutes = endMinutes.toString().padStart(2, '0')\n      const paddedEndSeconds = endSeconds.toFixed(3).padStart(6, '0')\n      vttString += `${paddedStartHours}:${paddedStartMinutes}:${paddedStartSeconds} --> ${paddedEndHours}:${paddedEndMinutes}:${paddedEndSeconds}\\n`\n      // add the current image url as well as the x, y, width, height information\n      vttString += `${currentUrl}#xywh=${xCoord},${yCoord},${storyboard.thumbnail_width},${storyboard.thumbnail_height}\\n\\n`\n      // update the variables\n      startHours = endHours\n      startMinutes = endMinutes\n      startSeconds = endSeconds\n      endSeconds += intervalInSeconds\n      if (endSeconds >= 60) {\n        endSeconds -= 60\n        endMinutes += 1\n      }\n      if (endMinutes >= 60) {\n        endMinutes -= 60\n        endHours += 1\n      }\n      // x coordinate can only be smaller than the width of one subimage * the number of subimages per row\n      xCoord = (xCoord + storyboard.thumbnail_width) % (storyboard.thumbnail_width * storyboard.columns)\n      // only if the x coordinate is , so in a new row, we have to update the y coordinate\n      if (xCoord === 0) {\n        yCoord += storyboard.thumbnail_height\n      }\n    }\n  }\n  return vttString\n}\n\nexport const ToastEventBus = new EventTarget()\n\n/**\n * @param {string | (({elapsedMs: number, remainingMs: number}) => string)} message\n * @param {number} time\n * @param {Function} action\n * @param {AbortSignal} abortSignal\n */\nexport function showToast(message, time = null, action = null, abortSignal = null) {\n  // Sometimes caller just pass user setting based value in and it can be zero\n  if (time === 0) {\n    console.warn('showToast called with time: 0', { message, time, action, abortSignal })\n    return\n  }\n\n  ToastEventBus.dispatchEvent(new CustomEvent('toast-open', {\n    detail: {\n      message,\n      time,\n      action,\n      abortSignal,\n    }\n  }))\n}\n\n/**\n * This writes to the clipboard. If an error occurs during the copy,\n * a toast with the error is shown. If the copy is successful and\n * there is a success message, a toast with that message is shown.\n * @param {string} content the content to be copied to the clipboard\n * @param {object} [options] - Optional settings for the copy operation.\n * @param {null|string} options.messageOnSuccess the message to be displayed as a toast when the copy succeeds (optional)\n * @param {null|string} options.messageOnError the message to be displayed as a toast when the copy fails (optional)\n */\nexport async function copyToClipboard(content, { messageOnSuccess = null, messageOnError = null } = {}) {\n  if (navigator.clipboard !== undefined && window.isSecureContext) {\n    try {\n      await navigator.clipboard.writeText(content)\n      if (messageOnSuccess !== null) {\n        showToast(messageOnSuccess)\n      }\n    } catch (error) {\n      console.error(`Failed to copy ${content} to clipboard`, error)\n      if (messageOnError !== null) {\n        showToast(`${messageOnError}: ${error}`, 5000)\n      } else {\n        showToast(`${i18n.global.t('Clipboard.Copy failed')}: ${error}`, 5000)\n      }\n    }\n  } else {\n    showToast(i18n.global.t('Clipboard.Cannot access clipboard without a secure connection'), 5000)\n  }\n}\n\n/**\n * Opens a link in the default web browser or a new tab in the web builds\n * @param {string} url the URL to open\n */\nexport async function openExternalLink(url) {\n  window.open(url, '_blank', 'noreferrer')\n}\n\n/**\n * Opens an internal path in the same or a new window.\n * Optionally with query params and setting the contents of the search bar in the new window.\n * @param {object} params\n * @param {string} params.path the internal path to open\n * @param {boolean} params.doCreateNewWindow set to true to open a new window\n * @param {object} params.query the query params to use (optional)\n * @param {string} params.searchQueryText the text to show in the search bar in the new window (optional)\n */\nexport function openInternalPath({ path, query = undefined, doCreateNewWindow, searchQueryText = null }) {\n  if (process.env.IS_ELECTRON && doCreateNewWindow) {\n    window.ftElectron.openInNewWindow(path, query, searchQueryText)\n  } else {\n    router.push({\n      path,\n      query\n    })\n  }\n}\n\n/**\n * @param {string} fileTypeDescription\n * @param {{[key: string]: string | string[]}} acceptedTypes\n * @param {string} [rememberDirectoryId]\n * @param {'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos'} [startInDirectory]\n * @returns {Promise<{ content: string, filename: string } | null>}\n */\nexport async function readFileWithPicker(\n  fileTypeDescription,\n  acceptedTypes,\n  rememberDirectoryId,\n  startInDirectory\n) {\n  let file\n\n  // Only supported in Electron and desktop Chromium browsers\n  // https://developer.mozilla.org/en-US/docs/Web/API/Window/showOpenFilePicker#browser_compatibility\n  // As we know it is supported in Electron, adding the build flag means we can skip the runtime check in Electron\n  // and allow terser to remove the unused else block\n  if (process.env.IS_ELECTRON || 'showOpenFilePicker' in window) {\n    try {\n      /** @type {FileSystemFileHandle[]} */\n      const [handle] = await window.showOpenFilePicker({\n        excludeAcceptAllOption: true,\n        multiple: false,\n        id: rememberDirectoryId,\n        startIn: startInDirectory,\n        types: [{\n          description: fileTypeDescription,\n          accept: acceptedTypes\n        }],\n      })\n\n      file = await handle.getFile()\n    } catch (error) {\n      // user pressed cancel in the file picker\n      if (error.name === 'AbortError') {\n        return null\n      }\n\n      throw error\n    }\n  } else {\n    /** @type {File|null} */\n    const fallbackFile = await new Promise((resolve) => {\n      const joinedExtensions = Object.values(acceptedTypes)\n        .flat()\n        .join(',')\n\n      const fileInput = document.createElement('input')\n      fileInput.type = 'file'\n      fileInput.accept = joinedExtensions\n      fileInput.onchange = () => {\n        resolve(fileInput.files[0])\n        fileInput.onchange = null\n      }\n\n      const listenForEnd = () => {\n        // 1 second timeout on the response from the file picker to prevent awaiting forever\n        setTimeout(() => {\n          if (fileInput.files.length === 0 && typeof fileInput.onchange === 'function') {\n            // if there are no files and the onchange has not been triggered, the file-picker was canceled\n            resolve(null)\n            fileInput.onchange = null\n          }\n        }, 1000)\n      }\n      window.addEventListener('focus', listenForEnd, { once: true })\n      fileInput.click()\n    })\n\n    if (fallbackFile === null) {\n      return null\n    }\n\n    file = fallbackFile\n  }\n\n  return {\n    content: await file.text(),\n    filename: file.name\n  }\n}\n\n/**\n * @param {string} fileName\n * @param {string | Blob} content\n * @param {string} fileTypeDescription\n * @param {string} mimeType\n * @param {string} fileExtension\n * @param {string} [rememberDirectoryId]\n * @param {'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos'} [startInDirectory]\n * @returns {Promise<boolean>}\n */\nexport async function writeFileWithPicker(\n  fileName,\n  content,\n  fileTypeDescription,\n  mimeType,\n  fileExtension,\n  rememberDirectoryId,\n  startInDirectory\n) {\n  // Only supported in Electron and desktop Chromium browsers\n  // https://developer.mozilla.org/en-US/docs/Web/API/Window/showOpenFilePicker#browser_compatibility\n  // As we know it is supported in Electron, adding the build flag means we can skip the runtime check in Electron\n  // and allow terser to remove the unused else block\n  if (process.env.IS_ELECTRON || 'showSaveFilePicker' in window) {\n    let writableFileStream\n\n    try {\n      /** @type {FileSystemFileHandle} */\n      const handle = await window.showSaveFilePicker({\n        suggestedName: fileName,\n        excludeAcceptAllOption: true,\n        multiple: false,\n        id: rememberDirectoryId,\n        startIn: startInDirectory,\n        types: [{\n          description: fileTypeDescription,\n          accept: {\n            [mimeType]: [fileExtension]\n          }\n        }],\n      })\n\n      writableFileStream = await handle.createWritable()\n      await writableFileStream.write(content)\n    } catch (error) {\n      // user pressed cancel in the file picker\n      if (error.name === 'AbortError') {\n        return false\n      }\n\n      throw error\n    } finally {\n      if (writableFileStream) {\n        await writableFileStream.close()\n      }\n    }\n\n    return true\n  } else {\n    if (typeof content === 'string') {\n      content = new Blob([content], { type: mimeType })\n    }\n\n    const url = URL.createObjectURL(content)\n\n    const downloadLink = document.createElement('a')\n    downloadLink.download = encodeURIComponent(fileName)\n    downloadLink.href = url\n    downloadLink.click()\n\n    // Small timeout to give the browser time to react to the click on the link\n    setTimeout(() => {\n      URL.revokeObjectURL(url)\n    }, 1000)\n\n    return true\n  }\n}\n\n/**\n * This creates an absolute web url from a given path.\n * It will assume all given paths are relative to the current window location.\n * @param {string} path relative path to resource\n * @returns {string} absolute web path\n */\nexport function createWebURL(path) {\n  const url = new URL(window.location.href)\n  const { origin } = url\n  let windowPath = url.pathname\n  // Remove the html file name from the path\n  if (windowPath.endsWith('.html')) {\n    windowPath = windowPath.replace(/[^./]*\\.html$/, '')\n  }\n  // Remove proceeding slash in given path if there is one\n  if (path.startsWith('/')) {\n    path = path.substring(1, path.length)\n  }\n  // Remove trailing slash if there is one\n  if (windowPath.endsWith('/')) {\n    windowPath = windowPath.substring(0, windowPath.length - 1)\n  }\n  return `${origin}${windowPath}/${path}`\n}\n\n/**\n * This formats the duration of a video in seconds into a user friendly timestamp.\n * It will return strings like LIVE or UPCOMING, without making any changes\n * @param {string|number} lengthSeconds the video duration in seconds or the strings LIVE or UPCOMING\n * @returns {string} timestamp or LIVE or UPCOMING\n */\nexport function formatDurationAsTimestamp(lengthSeconds) {\n  if (typeof lengthSeconds === 'string') {\n    return lengthSeconds\n  }\n\n  if (lengthSeconds === 0) {\n    return '0:00'\n  }\n\n  let hours = 0\n\n  if (lengthSeconds >= 3600) {\n    hours = Math.floor(lengthSeconds / 3600)\n    lengthSeconds = lengthSeconds - hours * 3600\n  }\n\n  let minutes = Math.floor(lengthSeconds / 60)\n  if (minutes < 10 && hours > 0) {\n    minutes = '0' + minutes\n  }\n\n  let seconds = lengthSeconds - minutes * 60\n  if (seconds < 10) {\n    seconds = '0' + seconds\n  }\n\n  let timestamp\n  if (hours > 0) {\n    timestamp = hours + ':' + minutes + ':' + seconds\n  } else {\n    timestamp = minutes + ':' + seconds\n  }\n\n  return timestamp\n}\n\n/**\n * @param {{sortBy? : string, time?: string, duration?: string, features: string[]}?} filtersA\n * @param {{sortBy? : string, time?: string, duration?: string, features: string[]}?} filtersB\n * @returns {boolean}\n */\nexport function searchFiltersMatch(filtersA, filtersB) {\n  return filtersA?.sortBy === filtersB?.sortBy &&\n    filtersA?.time === filtersB?.time &&\n    filtersA?.type === filtersB?.type &&\n    filtersA?.duration === filtersB?.duration &&\n    filtersA?.features?.length === filtersB?.features?.length && filtersA?.features?.every((val, index) => val === filtersB?.features[index])\n}\n\n/**\n * @param {string} filenameOriginal\n * @returns {string}\n */\nexport function replaceFilenameForbiddenChars(filenameOriginal) {\n  let filenameNew = filenameOriginal\n  let forbiddenChars = {}\n  switch (process.platform) {\n    case 'win32':\n      forbiddenChars = {\n        '<': '＜', // U+FF1C\n        '>': '＞', // U+FF1E\n        ':': '：', // U+FF1A\n        '\"': '＂', // U+FF02\n        '/': '／', // U+FF0F\n        '\\\\': '＼', // U+FF3C\n        '|': '｜', // U+FF5C\n        '?': '？', // U+FF1F\n        '*': '＊' // U+FF0A\n      }\n      break\n    case 'darwin':\n      forbiddenChars = { '/': '／', ':': '：' }\n      break\n    case 'linux':\n      forbiddenChars = { '/': '／' }\n      break\n    default:\n      break\n  }\n\n  for (const forbiddenChar in forbiddenChars) {\n    filenameNew = filenameNew.replaceAll(forbiddenChar, forbiddenChars[forbiddenChar])\n  }\n  return filenameNew\n}\n\n/**\n * @returns {Promise<string>}\n */\nexport async function getSystemLocale() {\n  let locale\n  if (process.env.IS_ELECTRON) {\n    locale = await window.ftElectron.getSystemLocale()\n  } else {\n    if (navigator && navigator.language) {\n      locale = navigator.language\n    }\n  }\n\n  return locale || 'en-US'\n}\n\nexport function extractNumberFromString(str) {\n  if (typeof str === 'string') {\n    return parseInt(str.replaceAll(/\\D+/g, ''))\n  } else {\n    return NaN\n  }\n}\n\n/**\n * @param {string} externalPlayer\n * @param {import('../../constants').UnsupportedPlayerAction} action\n */\nexport function showExternalPlayerUnsupportedActionToast(externalPlayer, action) {\n  let actionString = ''\n\n  switch (action) {\n    case UnsupportedPlayerActions.STARTING_VIDEO_AT_OFFSET:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.starting video at offset')\n      break\n    case UnsupportedPlayerActions.PLAYBACK_RATE:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.setting a playback rate')\n      break\n    case UnsupportedPlayerActions.OPENING_PLAYLISTS:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.opening playlists')\n      break\n    case UnsupportedPlayerActions.PLAYLIST_SPECIFIC_VIDEO:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.opening specific video in a playlist (falling back to opening the video)')\n      break\n    case UnsupportedPlayerActions.PLAYLIST_REVERSE:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.reversing playlists')\n      break\n    case UnsupportedPlayerActions.PLAYLIST_SHUFFLE:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.shuffling playlists')\n      break\n    case UnsupportedPlayerActions.PLAYLIST_LOOP:\n      actionString = i18n.global.t('Video.External Player.Unsupported Actions.looping playlists')\n      break\n  }\n\n  const message = i18n.global.t('Video.External Player.UnsupportedActionTemplate', {\n    externalPlayer, action: actionString\n  })\n  showToast(message)\n}\n\nexport function getVideoParamsFromUrl(url) {\n  /** @type {URL} */\n  let urlObject\n  const paramsObject = { videoId: null, timestamp: null, playlistId: null }\n  try {\n    urlObject = new URL(url)\n  } catch {\n    return paramsObject\n  }\n\n  function extractParams(videoId) {\n    paramsObject.videoId = videoId\n    let timestamp = urlObject.searchParams.get('t')\n    if (timestamp && (timestamp.includes('h') || timestamp.includes('m') || timestamp.includes('s'))) {\n      const { seconds, minutes, hours } = timestamp.match(/(?:(?<hours>(\\d+))h)?(?:(?<minutes>(\\d+))m)?(?:(?<seconds>(\\d+))s)?/).groups\n      let time = 0\n\n      if (seconds) {\n        time += Number(seconds)\n      }\n\n      if (minutes) {\n        time += 60 * Number(minutes)\n      }\n\n      if (hours) {\n        time += 3600 * Number(hours)\n      }\n\n      timestamp = time\n    }\n    paramsObject.timestamp = timestamp\n  }\n\n  const extractors = [\n    // anything with /watch?v=\n    function () {\n      if (urlObject.pathname === '/watch' && urlObject.searchParams.has('v')) {\n        extractParams(urlObject.searchParams.get('v').slice(0, 11))\n        paramsObject.playlistId = urlObject.searchParams.get('list')\n        return paramsObject\n      }\n    },\n    // youtu.be\n    function () {\n      if (urlObject.host === 'youtu.be' && /^\\/[\\w-]{11,}/.test(urlObject.pathname)) {\n        extractParams(urlObject.pathname.slice(1, 12))\n        paramsObject.playlistId = urlObject.searchParams.get('list')\n        return paramsObject\n      }\n    },\n    // youtube.com/embed\n    function () {\n      if (/^\\/embed\\/[\\w-]+$/.test(urlObject.pathname)) {\n        const urlTail = urlObject.pathname.replace('/embed/', '')\n        if (urlTail === 'videoseries') {\n          paramsObject.playlistId = urlObject.searchParams.get('list')\n        } else {\n          extractParams(urlTail)\n        }\n        return paramsObject\n      }\n    },\n    // youtube.com/shorts\n    function () {\n      if (/^\\/shorts\\/[\\w-]+$/.test(urlObject.pathname)) {\n        extractParams(urlObject.pathname.replace('/shorts/', ''))\n        return paramsObject\n      }\n    },\n    // youtube.com/live\n    function () {\n      if (/^\\/live\\/[\\w-]+$/.test(urlObject.pathname)) {\n        extractParams(urlObject.pathname.replace('/live/', ''))\n        return paramsObject\n      }\n    },\n    // cloudtube\n    function () {\n      if (/^cadence\\.(gq|moe)$/.test(urlObject.host) && /^\\/cloudtube\\/video\\/[\\w-]+$/.test(urlObject.pathname)) {\n        extractParams(urlObject.pathname.slice('/cloudtube/video/'.length))\n        return paramsObject\n      }\n    }\n  ]\n\n  return extractors.reduce((a, c) => a || c(), null) || paramsObject\n}\n\n/**\n * This will match sequences of upper case characters and convert them into title cased words.\n * This will also match excessive strings of punctionation and convert them to one representative character\n * @param {string} title the title to process\n * @param {number} minUpperCase the minimum number of consecutive upper case characters to match\n * @returns {string} the title with upper case characters removed and punctuation normalized\n */\nexport function toDistractionFreeTitle(title, minUpperCase = 3) {\n  const firstValidCharIndex = (word) => {\n    const reg = /[\\p{L}]/u\n    return word.search(reg)\n  }\n\n  const capitalizedWord = (word) => {\n    const chars = word.split('')\n    const index = firstValidCharIndex(word)\n    chars[index] = chars[index].toUpperCase()\n    return chars.join('')\n  }\n\n  const reg = RegExp(`[\\\\p{Lu}|']{${minUpperCase},}`, 'ug')\n  return title\n    .replaceAll(/!{2,}/g, '!')\n    .replaceAll(/[!?]{2,}/g, '?')\n    .replace(reg, x => capitalizedWord(x.toLowerCase()))\n}\n\n/**\n * @param {number} number\n * @param {Intl.NumberFormatOptions?} options\n * @returns {string}\n */\nexport function formatNumber(number, options = undefined) {\n  return Intl.NumberFormat([i18n.global.locale, 'en'], options).format(number)\n}\n\nexport function getTodayDateStrLocalTimezone() {\n  const timeNow = new Date()\n  // `Date#getTimezoneOffset` returns the difference, in minutes\n  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset\n  const timeNowStr = new Date(timeNow.getTime() - (timeNow.getTimezoneOffset() * 60000)).toISOString()\n  // `Date#toISOString` returns string with `T` as date/time separator (ISO 8601 format)\n  // e.g. 2011-10-05T14:48:00.000Z\n  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString\n  return timeNowStr.split('T')[0]\n}\n\n/**\n *\n * @param {number} date\n * @param {boolean} hideSeconds\n * @param {boolean} useThirtyDayMonths\n * @returns {string}\n */\nexport function getRelativeTimeFromDate(date, hideSeconds = false, useThirtyDayMonths = true) {\n  if (!date) {\n    return ''\n  }\n\n  const now = Date.now()\n  // Convert from ms to second\n  // For easier code interpretation the value is made to be positive\n  let timeDiffFromNow = ((now - date) / 1000)\n  let timeUnit = 'second'\n\n  if (timeDiffFromNow < 60 && hideSeconds) {\n    return i18n.global.t('Moments Ago')\n  }\n\n  if (timeDiffFromNow >= 60) {\n    timeDiffFromNow /= 60\n    timeUnit = 'minute'\n  }\n\n  if (timeUnit === 'minute' && timeDiffFromNow >= 60) {\n    timeDiffFromNow /= 60\n    timeUnit = 'hour'\n  }\n\n  if (timeUnit === 'hour' && timeDiffFromNow >= 24) {\n    timeDiffFromNow /= 24\n    timeUnit = 'day'\n  }\n\n  const timeDiffFromNowDays = timeDiffFromNow\n  if (timeUnit === 'day' && timeDiffFromNow >= 7) {\n    timeDiffFromNow /= 7\n    timeUnit = 'week'\n  }\n\n  /* Different months might have a different number of days.\n    In some contexts, to ensure the display is fine, we use 31.\n    In other contexts, like when working with calculatePublishedDate, we use 30. */\n  const daysInMonth = useThirtyDayMonths ? 30 : 31\n  if (timeUnit === 'week' && timeDiffFromNowDays >= daysInMonth) {\n    timeDiffFromNow = timeDiffFromNowDays / daysInMonth\n    timeUnit = 'month'\n  }\n\n  if (timeUnit === 'month' && timeDiffFromNow >= 12) {\n    timeDiffFromNow /= 12\n    timeUnit = 'year'\n  }\n\n  // Using `Math.ceil` so that -1.x days ago displayed as 1 day ago\n  // Notice that the value is turned to negative to be displayed as \"ago\"\n  return new Intl.RelativeTimeFormat([i18n.global.locale, 'en']).format(Math.ceil(-timeDiffFromNow), timeUnit)\n}\n\n/**\n * Escapes HTML tags to avoid XSS\n * @param {string} untrusted\n * @returns {string}\n */\nexport function escapeHTML(untrusted) {\n  return untrusted.replaceAll('&', '&amp;')\n    .replaceAll('<', '&lt;')\n    .replaceAll('>', '&gt;')\n    .replaceAll('\"', '&quot;')\n    .replaceAll('\\'', '&apos;')\n}\n\n/**\n * Performs a deep copy of a javascript object\n * @template T\n * @param {T} obj\n * @returns {T}\n */\nexport function deepCopy(obj) {\n  return JSON.parse(JSON.stringify(obj))\n}\n\n/**\n * Check if the `name` of the error is `TimeoutError` to know if the error was caused by a timeout or something else.\n * @param {number} timeoutMs\n * @param {RequestInfo|URL} input\n * @param {RequestInit?} init\n * @returns {Promise<Response>}\n */\nexport async function fetchWithTimeout(timeoutMs, input, init) {\n  const timeoutSignal = AbortSignal.timeout(timeoutMs)\n\n  if (typeof init !== 'undefined') {\n    init.signal = timeoutSignal\n  } else {\n    init = {\n      signal: timeoutSignal\n    }\n  }\n\n  try {\n    return await fetch(input, init)\n  } catch (err) {\n    if (err.name === 'AbortError' && timeoutSignal.aborted) {\n      // According to the spec, fetch should use the original abort reason.\n      // Unfortunately chromium browsers always throw an AbortError, even when it was caused by a TimeoutError,\n      // so we need manually throw the original abort reason\n      // https://bugs.chromium.org/p/chromium/issues/detail?id=1431720\n      throw timeoutSignal.reason\n    } else {\n      throw err\n    }\n  }\n}\n\n/**\n * @param {KeyboardEvent} event\n * @param {HTMLInputElement} inputElement\n */\nexport function ctrlFHandler(event, inputElement) {\n  switch (event.key) {\n    case 'F':\n    case 'f':\n      if (((process.platform !== 'darwin' && event.ctrlKey) || (process.platform === 'darwin' && event.metaKey))) {\n        nextTick(() => inputElement?.focus())\n      }\n  }\n}\n\n/**\n * @template T\n * @param {T[]} array\n * @returns {T}\n */\nexport function randomArrayItem(array) {\n  return array[Math.floor(Math.random() * array.length)]\n}\n\n/**\n * @template T\n * @param {T[]} array\n * @param {T} entry\n */\nexport function removeFromArrayIfExists(array, entry) {\n  const index = array.indexOf(entry)\n\n  if (index !== -1) {\n    array.splice(index, 1)\n  }\n}\n\n/**\n * @param {string} text\n */\nexport function base64EncodeUtf8(text) {\n  const bytes = new TextEncoder().encode(text)\n\n  const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('')\n  return btoa(binString)\n}\n\n/**\n * @overload\n * @param {string} channelId\n * @param {'videos' | 'live' | 'shorts'} type\n * @param {'newest' | 'popular'} sortBy\n * @returns {string}\n *\n * @overload\n * @param {string} channelId\n * @param {'all'} type\n * @returns {string}\n *\n * @param {string} channelId\n * @param {'all' | 'videos' | 'live' | 'shorts'} type\n * @param {('newest' | 'popular')?} [sortBy]\n * @returns {string}\n */\n\nexport function getChannelPlaylistId(channelId, type, sortBy) {\n  switch (type) {\n    case 'videos':\n      if (sortBy === 'popular') {\n        return channelId.replace(/^UC/, 'UULP')\n      } else {\n        return channelId.replace(/^UC/, 'UULF')\n      }\n    case 'live':\n      if (sortBy === 'popular') {\n        return channelId.replace(/^UC/, 'UUPV')\n      } else {\n        return channelId.replace(/^UC/, 'UULV')\n      }\n    case 'shorts':\n      if (sortBy === 'popular') {\n        return channelId.replace(/^UC/, 'UUPS')\n      } else {\n        return channelId.replace(/^UC/, 'UUSH')\n      }\n    case 'all':\n      return channelId.replace(/^UC/, 'UU')\n  }\n}\n\nfunction getIndividualLocalizedShortcut(shortcut) {\n  switch (shortcut) {\n    case 'alt':\n      return i18n.global.t('Keys.alt')\n    case 'ctrl':\n      return i18n.global.t('Keys.ctrl')\n    case 'shift':\n      return i18n.global.t('Keys.shift')\n    case 'enter':\n      return i18n.global.t('Keys.enter')\n    case 'plus':\n      return i18n.global.t('Keys.plus')\n    case 'arrowleft':\n      return i18n.global.t('Keys.arrowleft')\n    case 'arrowright':\n      return i18n.global.t('Keys.arrowright')\n    case 'arrowup':\n      return i18n.global.t('Keys.arrowup')\n    case 'arrowdown':\n      return i18n.global.t('Keys.arrowdown')\n    default:\n      return shortcut\n  }\n}\n\nfunction getMacIconForShortcut(shortcut) {\n  switch (shortcut) {\n    case 'option':\n    case 'alt':\n      return '⌥'\n    case 'cmd':\n    case 'ctrl':\n      return '⌘'\n    case 'shift':\n      return '⇧'\n    case 'enter':\n      return '⌤'\n    case 'plus':\n      return '+'\n    case 'arrowleft':\n      return '←'\n    case 'arrowright':\n      return '→'\n    case 'arrowup':\n      return '↑'\n    case 'arrowdown':\n      return '↓'\n    default:\n      return shortcut\n  }\n}\n\n/**\n * @param {string} shortcut\n * @returns {string} the localized and recombined shortcut\n */\nexport function getLocalizedShortcut(shortcut) {\n  const shortcuts = shortcut.split('+')\n\n  if (process.platform === 'darwin') {\n    const shortcutsAsIcons = shortcuts.map(shortcut => getMacIconForShortcut(shortcut))\n    return shortcutsAsIcons.join('')\n  } else {\n    const localizedShortcuts = shortcuts.map((shortcut) => getIndividualLocalizedShortcut(shortcut))\n    const shortcutJoinOperator = i18n.global.t('shortcutJoinOperator')\n    return localizedShortcuts.join(shortcutJoinOperator)\n  }\n}\n\n/**\n * @param {string} actionTitle\n * @param {string} shortcut\n * @returns {string} the localized action title with keyboard shortcut\n */\nexport function addKeyboardShortcutToActionTitle(actionTitle, shortcut) {\n  return i18n.global.t('KeyboardShortcutTemplate', {\n    label: actionTitle,\n    shortcut\n  })\n}\n\n/**\n * @param {string} localizedActionTitle\n * @param {string|string[]} sometimesManyUnlocalizedShortcuts\n * @returns {string} the localized action title with keyboard shortcut\n */\nexport function localizeAndAddKeyboardShortcutToActionTitle(localizedActionTitle, sometimesManyUnlocalizedShortcuts) {\n  let unlocalizedShortcuts = sometimesManyUnlocalizedShortcuts\n  if (!Array.isArray(sometimesManyUnlocalizedShortcuts)) {\n    unlocalizedShortcuts = [unlocalizedShortcuts]\n  }\n  const localizedShortcuts = unlocalizedShortcuts.map((s) => getLocalizedShortcut(s))\n  const shortcutLabelSeparator = i18n.global.t('shortcutLabelSeparator')\n  return addKeyboardShortcutToActionTitle(localizedActionTitle, localizedShortcuts.join(shortcutLabelSeparator))\n}\n\n/**\n * @template {Function} T\n * @param {T} func\n * @param {number} wait\n * @returns {T}\n */\nexport function debounce(func, wait) {\n  let timeout\n\n  // Using a fully fledged function here instead of an arrow function\n  // so that we can get `this` and pass it onto the original function.\n  // Vue components using the options API use `this` alot.\n  return function (...args) {\n    const context = this\n\n    clearTimeout(timeout)\n\n    timeout = setTimeout(() => {\n      timeout = null\n      func.apply(context, args)\n    }, wait)\n  }\n}\n\n/**\n * @template {Function} T\n * @param {T} func\n * @param {number} wait\n * @returns {T}\n */\nexport function throttle(func, wait) {\n  let isWaiting\n\n  // Using a fully fledged function here instead of an arrow function\n  // so that we can get `this` and pass it onto the original function.\n  // Vue components using the options API use `this` alot.\n  return function (...args) {\n    const context = this\n    if (!isWaiting) {\n      func.apply(context, args)\n\n      isWaiting = true\n      setTimeout(() => {\n        isWaiting = false\n      }, wait)\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/i18n/index.js",
    "content": "import { createI18n } from 'vue-i18n'\nimport { createWebURL } from '../helpers/utils'\n// List of locales approved for use\nimport activeLocales from '../../../static/locales/activeLocales.json'\n\nconst i18n = createI18n({\n  locale: 'en-US',\n  legacy: true,\n  fallbackLocale: {\n    // https://vue-i18n.intlify.dev/guide/essentials/fallback.html\n\n    // es-AR -> es -> en-US\n    'es-AR': ['es'],\n    // es-MX -> es -> en-US\n    'es-MX': ['es'],\n    // pt-BR -> pt -> en-US\n    'pt-BR': ['pt'],\n    // pt-PT -> pt -> en-US\n    'pt-PT': ['pt'],\n    // any -> en-US\n    default: ['en-US'],\n  }\n})\n\nexport async function loadLocale(locale) {\n  // don't need to load it if it's already loaded\n  if (i18n.global.availableLocales.includes(locale) &&\n    Object.keys(i18n.global.messages[locale]).length > 0) {\n    return\n  }\n  if (!activeLocales.includes(locale)) {\n    console.error(`Unable to load unknown locale: \"${locale}\"`)\n    return\n  }\n\n  let path\n\n  // locales are only compressed in our production Electron builds\n  if (process.env.IS_ELECTRON && process.env.NODE_ENV !== 'development') {\n    path = `/static/locales/${locale}.json.br`\n  } else {\n    path = `/static/locales/${locale}.json`\n  }\n\n  const url = createWebURL(path)\n\n  const response = await fetch(url)\n  const data = await response.json()\n  i18n.global.setLocaleMessage(locale, data)\n}\n\n// Set by _scripts/ProcessLocalesPlugin.js\nif (process.env.HOT_RELOAD_LOCALES) {\n  const websocket = new WebSocket('ws://localhost:9080/ws')\n\n  websocket.onmessage = (event) => {\n    const message = JSON.parse(event.data)\n\n    if (message.type === 'freetube-locale-update') {\n      for (const [locale, data] of message.data) {\n        // Only update locale data if it was already loaded\n        if (i18n.global.availableLocales.includes(locale) &&\n          Object.keys(i18n.global.messages[locale]).length > 0) {\n          const localeData = JSON.parse(data)\n\n          i18n.global.setLocaleMessage(locale, localeData)\n        }\n      }\n    }\n  }\n}\n\nexport default i18n\n"
  },
  {
    "path": "src/renderer/main.js",
    "content": "import { createApp } from 'vue'\nimport i18n from './i18n/index'\nimport router from './router/index'\nimport store from './store/index'\nimport App from './App.vue'\nimport { showExternalPlayerUnsupportedActionToast, showToast } from './helpers/utils'\nimport { library } from './fontawesome-minimal'\n// import the styles\nimport '@fortawesome/fontawesome-svg-core/styles.css'\n\nimport { register as registerSwiper } from 'swiper/element'\n\nimport { ObserveVisibility } from 'vue-observe-visibility'\n\n// Please keep the list of constants sorted by name\n// to avoid code conflict and duplicate entries\nimport {\n  faAngleDown,\n  faAngleLeft,\n  faAngleUp,\n  faArrowDown,\n  faArrowDownShortWide,\n  faArrowDownWideShort,\n  faArrowLeft,\n  faArrowRight,\n  faArrowUp,\n  faArrowUpRightFromSquare,\n  faBars,\n  faBarsProgress,\n  faBorderAll,\n  faBookmark,\n  faCheck,\n  faChevronRight,\n  faCircleExclamation,\n  faCirclePlay,\n  faCircleUser,\n  faClapperboard,\n  faClock,\n  faClockRotateLeft,\n  faClone,\n  faComment,\n  faCommentDots,\n  faCopy,\n  faDatabase,\n  faDisplay,\n  faDownload,\n  faEdit,\n  faEllipsisH,\n  faEllipsisV,\n  faEnvelope,\n  faExchangeAlt,\n  faExclamationCircle,\n  faExpand,\n  faExternalLinkAlt,\n  faEye,\n  faEyeSlash,\n  faFileDownload,\n  faFileImage,\n  faFileVideo,\n  faFilm,\n  faFilter,\n  faFilterCircleXmark,\n  faFlask,\n  faFire,\n  faForward,\n  faGamepad,\n  faGauge,\n  faGlobe,\n  faGrip,\n  faHashtag,\n  faHeart,\n  faHistory,\n  faImages,\n  faInfoCircle,\n  faKey,\n  faKeyboard,\n  faLanguage,\n  faLink,\n  faLinkSlash,\n  faList,\n  faLocationDot,\n  faLock,\n  faMessage,\n  faMoneyCheckDollar,\n  faNetworkWired,\n  faNewspaper,\n  faPalette,\n  faPhotoFilm,\n  faPlay,\n  faPlus,\n  faPodcast,\n  faQuestionCircle,\n  faRandom,\n  faRetweet,\n  faRss,\n  faSatelliteDish,\n  faSave,\n  faSearch,\n  faServer,\n  faShareAlt,\n  faShield,\n  faSlash,\n  faSlidersH,\n  faSortAlphaDown,\n  faSortAlphaDownAlt,\n  faSortDown,\n  faStepBackward,\n  faStepForward,\n  faSync,\n  faThumbsDown,\n  faThumbsUp,\n  faThumbtack,\n  faTimes,\n  faTimesCircle,\n  faTowerBroadcast,\n  faTrash,\n  faTrophy,\n  faUserCheck,\n  faUserLock,\n  faUsers,\n  faUsersSlash,\n  faVideo,\n  faVolumeHigh,\n  faVolumeLow,\n  faVolumeMute,\n  faWifi,\n  faXmark\n} from '@fortawesome/free-solid-svg-icons'\nimport {\n  faBookmark as farBookmark,\n  faDotCircle as farDotCircle\n} from '@fortawesome/free-regular-svg-icons'\nimport {\n  faBitcoin,\n  faGithub,\n  faMastodon,\n} from '@fortawesome/free-brands-svg-icons'\nimport { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'\n\n// Please keep the list of constants sorted by name\n// to avoid code conflict and duplicate entries\nlibrary.add(\n  // solid icons\n  faAngleDown,\n  faAngleLeft,\n  faAngleUp,\n  faArrowDown,\n  faArrowDownShortWide,\n  faArrowDownWideShort,\n  faArrowLeft,\n  faArrowRight,\n  faArrowUp,\n  faArrowUpRightFromSquare,\n  faBars,\n  faBarsProgress,\n  faBorderAll,\n  faBookmark,\n  faCheck,\n  faChevronRight,\n  faCircleExclamation,\n  faCirclePlay,\n  faCircleUser,\n  faClapperboard,\n  faClock,\n  faClockRotateLeft,\n  faClone,\n  faComment,\n  faCommentDots,\n  faCopy,\n  faDatabase,\n  faDisplay,\n  faDownload,\n  faEdit,\n  faEllipsisH,\n  faEllipsisV,\n  faEnvelope,\n  faExchangeAlt,\n  faExclamationCircle,\n  faExpand,\n  faExternalLinkAlt,\n  faEye,\n  faEyeSlash,\n  faFileDownload,\n  faFileImage,\n  faFileVideo,\n  faFilm,\n  faFilter,\n  faFilterCircleXmark,\n  faFlask,\n  faFire,\n  faForward,\n  faGamepad,\n  faGauge,\n  faGlobe,\n  faGrip,\n  faHashtag,\n  faHeart,\n  faHistory,\n  faImages,\n  faInfoCircle,\n  faKey,\n  faKeyboard,\n  faLanguage,\n  faLink,\n  faLinkSlash,\n  faList,\n  faLocationDot,\n  faLock,\n  faMessage,\n  faMoneyCheckDollar,\n  faNetworkWired,\n  faNewspaper,\n  faPalette,\n  faPhotoFilm,\n  faPlay,\n  faPlus,\n  faPodcast,\n  faQuestionCircle,\n  faRandom,\n  faRetweet,\n  faRss,\n  faSatelliteDish,\n  faSave,\n  faSearch,\n  faServer,\n  faShareAlt,\n  faShield,\n  faSlash,\n  faSlidersH,\n  faSortAlphaDown,\n  faSortAlphaDownAlt,\n  faSortDown,\n  faStepBackward,\n  faStepForward,\n  faSync,\n  faThumbsDown,\n  faThumbsUp,\n  faThumbtack,\n  faTimes,\n  faTimesCircle,\n  faTowerBroadcast,\n  faTrash,\n  faTrophy,\n  faUserCheck,\n  faUserLock,\n  faUsers,\n  faUsersSlash,\n  faVideo,\n  faVolumeHigh,\n  faVolumeLow,\n  faVolumeMute,\n  faWifi,\n  faXmark,\n\n  // solid icons\n  farBookmark,\n  farDotCircle,\n\n  // brand icons\n  faGithub,\n  faBitcoin,\n  faMastodon,\n)\n\nregisterSwiper()\n\nconst app = createApp(App)\n\napp.config.performance = process.env.NODE_ENV === 'development'\n\napp\n  .component('FontAwesomeIcon', FontAwesomeIcon)\n  .component('FontAwesomeLayers', FontAwesomeLayers)\n  .directive('observe-visibility', ObserveVisibility)\n\n  .use(router)\n  .use(store)\n  .use(i18n)\n\nrouter.isReady().then(() => {\n  app.mount('#app')\n})\n\n// to avoid accessing electron api from web app build\nif (process.env.IS_ELECTRON) {\n  window.ftElectron.handleChangeView((route) => {\n    router.push(route)\n  })\n\n  window.ftElectron.handleOpenInExternalPlayerResult(\n    (externalPlayer, unsupportedActions, isPlaylist) => {\n      for (const action of unsupportedActions) {\n        showExternalPlayerUnsupportedActionToast(externalPlayer, action)\n      }\n\n      const videoOrPlaylist = isPlaylist\n        ? i18n.global.t('Video.External Player.playlist')\n        : i18n.global.t('Video.External Player.video')\n\n      showToast(i18n.global.t('Video.External Player.OpeningTemplate', { videoOrPlaylist, externalPlayer }))\n    }\n  )\n}\n"
  },
  {
    "path": "src/renderer/router/index.js",
    "content": "import { createRouter, createWebHashHistory } from 'vue-router'\nimport Subscriptions from '../views/Subscriptions/Subscriptions.vue'\nimport SubscribedChannels from '../views/SubscribedChannels/SubscribedChannels.vue'\nimport ProfileSettings from '../views/ProfileSettings/ProfileSettings.vue'\nimport Trending from '../views/Trending/Trending.vue'\nimport Popular from '../views/Popular/Popular.vue'\nimport UserPlaylists from '../views/UserPlaylists/UserPlaylists.vue'\nimport History from '../views/History/History.vue'\nimport Settings from '../views/Settings/Settings.vue'\nimport About from '../views/About/About.vue'\nimport SearchPage from '../views/SearchPage/SearchPage.vue'\nimport Playlist from '../views/Playlist/Playlist.vue'\nimport Channel from '../views/Channel/Channel.vue'\nimport Watch from '../views/Watch/Watch.vue'\nimport Hashtag from '../views/Hashtag/Hashtag.vue'\nimport Post from '../views/Post.vue'\n\nconst router = createRouter({\n  history: createWebHashHistory(),\n  routes: [\n    {\n      path: '/',\n      name: 'default',\n      meta: {\n        title: 'Subscriptions'\n      },\n      component: Subscriptions\n    },\n    {\n      path: '/subscriptions',\n      name: 'subscriptions',\n      meta: {\n        title: 'Subscriptions'\n      },\n      component: Subscriptions\n    },\n    {\n      path: '/subscribedchannels',\n      name: 'subscribedChannels',\n      meta: {\n        title: 'Channels'\n      },\n      component: SubscribedChannels\n    },\n    ...(process.env.SUPPORTS_LOCAL_API\n      ? [{\n          path: '/trending',\n          name: 'trending',\n          meta: {\n            title: 'Trending'\n          },\n          component: Trending\n        }]\n      : []),\n    {\n      path: '/popular',\n      name: 'popular',\n      meta: {\n        title: 'Most Popular'\n      },\n      component: Popular\n    },\n    {\n      path: '/userplaylists',\n      name: 'userPlaylists',\n      meta: {\n        title: 'Your Playlists'\n      },\n      component: UserPlaylists\n    },\n    {\n      path: '/history',\n      name: 'history',\n      meta: {\n        title: 'History'\n      },\n      component: History\n    },\n    {\n      path: '/settings',\n      name: 'settings',\n      meta: {\n        title: 'Settings'\n      },\n      component: Settings\n    },\n    {\n      path: '/about',\n      name: 'about',\n      meta: {\n        title: 'About'\n      },\n      component: About\n    },\n    {\n      path: '/settings/profile',\n      name: 'profileSettings',\n      meta: {\n        title: 'Profile Settings'\n      },\n      component: ProfileSettings\n    },\n    {\n      path: '/search/:query',\n      meta: {\n        title: 'Search Results'\n      },\n      component: SearchPage\n    },\n    {\n      path: '/playlist/:id',\n      meta: {\n        title: 'Playlist'\n      },\n      component: Playlist\n    },\n    {\n      path: '/channel/:id/:currentTab?',\n      meta: {\n        title: 'Channel'\n      },\n      component: Channel\n    },\n    {\n      path: '/watch/:id',\n      meta: {\n        title: 'Watch'\n      },\n      component: Watch\n    },\n    {\n      path: '/hashtag/:hashtag',\n      meta: {\n        title: 'Hashtag'\n      },\n      component: Hashtag\n    },\n    {\n      path: '/post/:id',\n      meta: {\n        title: 'Post',\n      },\n      component: Post\n    }\n  ],\n  scrollBehavior(to, from, savedPosition) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        if (savedPosition !== null) {\n          resolve(savedPosition)\n        } else {\n          resolve({ left: 0, top: 0 })\n        }\n      }, 500)\n    })\n  }\n})\n\nexport default router\n"
  },
  {
    "path": "src/renderer/scss-partials/_ft-list-item.scss",
    "content": "/* stylelint-disable no-descending-specificity */\n$thumbnail-overlay-opacity: 0.85;\n$watched-transition-duration: 0.5s;\n\n@mixin is-result {\n  @at-root {\n    .result#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin is-watch-playlist-item {\n  @at-root {\n    .watchPlaylistItem#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin is-recommendation {\n  @at-root {\n    .recommendation#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin is-sidebar-item {\n  @at-root {\n    .watchPlaylistItem#{&},\n    .recommendation#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin low-contrast-when-watched($col) {\n  color: $col;\n\n  @at-root {\n    .watched &,\n    .watched#{&} {\n      color: var(--tertiary-text-color);\n      transition-duration: $watched-transition-duration;\n    }\n    .watched:hover &,\n    .watched:hover#{&} {\n      color: $col;\n      transition-duration: $watched-transition-duration;\n    }\n  }\n}\n\n.ft-list-item {\n  padding: 6px;\n\n  &.watched {\n    background-color: var(--bg-color);\n\n    @include low-contrast-when-watched(var(--primary-text-color));\n\n    .thumbnailImage {\n      opacity: 0.3;\n      /* stylelint-disable-next-line declaration-property-value-no-unknown */\n      transition: opacity $watched-transition-duration;\n    }\n\n    &:hover .thumbnailImage,\n    &:focus .thumbnailImage {\n      opacity: 1;\n      transition-duration: $watched-transition-duration;\n    }\n  }\n\n  .videoThumbnail {\n    display: grid;\n\n    .thumbnailLink,\n    .videoWatched,\n    .videoDuration,\n    .externalPlayerIcon,\n    .playlistIcons,\n    .watchedProgressBar,\n    .videoCountContainer,\n    .background,\n    .inner {\n      grid-column: 1;\n      grid-row: 1;\n      user-select: none;\n    }\n\n    .thumbnailLink {\n      display: flex;\n      overflow: hidden;\n    }\n\n    .thumbnailImage {\n      @include is-sidebar-item {\n        block-size: 75px;\n      }\n\n      @include is-recommendation {\n        block-size: auto;\n        inline-size: 163px;\n      }\n    }\n\n    .videoWatched {\n      place-self: flex-start start;\n      background-color: var(--bg-color);\n      color: var(--primary-text-color);\n      opacity: $thumbnail-overlay-opacity;\n      padding: 2px;\n      pointer-events: none;\n    }\n\n    .videoDuration {\n      place-self: flex-end end;\n      background-color: var(--card-bg-color);\n      border-radius: 5px;\n      color: var(--primary-text-color);\n      font-size: 15px;\n      line-height: 1.2;\n      margin-block: 0 4px;\n      margin-inline: 0 4px;\n      opacity: $thumbnail-overlay-opacity;\n      padding-block: 3px;\n      padding-inline: 4px;\n      pointer-events: none;\n\n      @include is-watch-playlist-item {\n        font-size: 12px;\n      }\n\n      &.live {\n        background-color: #f22;\n        color: #fff;\n      }\n    }\n\n    .externalPlayerIcon {\n      place-self: flex-end start;\n      font-size: 17px;\n      margin-block-end: 4px;\n      margin-inline-start: 4px;\n    }\n\n    .playlistIcons {\n      justify-self: end;\n      margin-inline-end: 3px;\n      margin-block-start: 3px;\n      display: grid;\n      grid-auto-flow: column;\n      justify-content: flex-end;\n      block-size: fit-content;\n    }\n\n    .quickBookmarkVideoIcon,\n    .addToPlaylistIcon,\n    .trashIcon,\n    .upArrowIcon,\n    .downArrowIcon {\n      font-size: 17px;\n    }\n\n    .watchedProgressBar {\n      place-self: flex-end stretch;\n      background-color: var(--primary-color);\n      block-size: 2px;\n      z-index: 2;\n    }\n\n    .videoCountContainer {\n      place-self: stretch end;\n      display: grid;\n      font-size: 20px;\n      inline-size: 60px;\n      pointer-events: none;\n\n      .background {\n        background-color: var(--bg-color);\n        opacity: 0.9;\n      }\n\n      .inner {\n        align-items: center;\n        color: var(--primary-text-color);\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        z-index: 1;\n      }\n    }\n  }\n\n  .channelThumbnail {\n    display: flex;\n    justify-content: center;\n\n    .channelThumbnailLink {\n      inline-size: 100%;\n      text-align: center;\n\n      .channelImage {\n        border-radius: 50%;\n        block-size: 130px;\n      }\n\n      .gameImage {\n        block-size: 130px;\n      }\n    }\n  }\n\n  .info {\n    align-content: flex-start;\n    display: grid;\n    flex: 1;\n    min-inline-size: 10em;\n    grid-template:\n      'title optionsExternalButton' auto\n      'infoLine optionsExternalButton' auto\n      'description optionsExternalButton' auto / 1fr auto;\n\n    .buttonStack {\n      grid-area: optionsExternalButton;\n    }\n\n    .optionsButton {\n      grid-area: optionsExternalButton;\n    }\n\n    .externalPlayerButton {\n      grid-area: optionsExternalButton;\n    }\n\n    .title {\n      font-size: 20px;\n      grid-area: title;\n      text-decoration: none;\n      overflow-wrap: break-word;\n      overflow-wrap: anywhere;\n\n      @include low-contrast-when-watched(var(--primary-text-color));\n\n      @include is-sidebar-item {\n        font-size: 15px;\n      }\n    }\n\n    .infoLine {\n      font-size: 14px;\n      grid-area: infoLine;\n      margin-block-start: 5px;\n      overflow-wrap: anywhere;\n      text-align: start;\n\n      @include low-contrast-when-watched(var(--secondary-text-color));\n\n      @include is-sidebar-item {\n        font-size: 12px;\n      }\n\n      .channelName {\n        @include low-contrast-when-watched(var(--secondary-text-color));\n      }\n    }\n\n    .description {\n      font-size: 14px;\n      grid-area: description;\n      max-block-size: 50px;\n      overflow-y: hidden;\n\n      @include low-contrast-when-watched(var(--secondary-text-color));\n    }\n  }\n\n  &.list {\n    align-items: flex-start;\n    display: flex;\n\n    @include is-sidebar-item {\n      .videoThumbnail {\n        margin-inline-end: 10px;\n      }\n    }\n\n    &.result {\n      .videoThumbnail,\n      .channelThumbnailLink,\n      .thumbnailLink,\n      .thumbnailImage {\n        inline-size: 336px;\n        max-inline-size: 25vw;\n\n        @media only screen and (width <= 680px) {\n          max-inline-size: 30vw;\n        }\n      }\n\n      .channelImage {\n        max-inline-size: 25vw;\n        max-block-size: 25vw;\n\n        @media only screen and (width <= 680px) {\n          max-inline-size: 30vw;\n          max-block-size: 30vw;\n        }\n      }\n    }\n\n\n    .videoThumbnail,\n    .channelThumbnail {\n      margin-inline-end: 20px;\n    }\n\n    .info .description {\n      margin-inline-end: 10px;\n    }\n  }\n\n  &.grid {\n    display: flex;\n    flex-direction: column;\n    min-block-size: 230px;\n    padding-block-end: 20px;\n    box-sizing: border-box;\n    block-size: 100%;\n\n    .videoThumbnail,\n    .channelThumbnail {\n      margin-block-end: 12px;\n\n      .thumbnailImage {\n        // Ensure placeholder image displayed at same aspect ratio as most other images\n        aspect-ratio: 16/9;\n        // DeArrrow thumbnails are vertical for shorts.\n        // Set the object-fit so they don't get stretched to 16:9\n        object-fit: contain;\n      }\n    }\n\n    .thumbnailImage,\n    .channelThumbnail {\n      inline-size: 100%;\n    }\n\n    .title {\n      font-size: 18px;\n    }\n\n    .infoLine {\n      font-size: 13px;\n      margin-block-start: 8px;\n    }\n  }\n\n  .playlistIcons,\n  .externalPlayerIcon {\n    opacity: $thumbnail-overlay-opacity;\n  }\n\n  @media (hover: hover) {\n    &:hover .quickBookmarkVideoIcon:not(.alwaysVisible),\n    .quickBookmarkVideoIcon.bookmarked:not(.alwaysVisible),\n    &:hover .addToPlaylistIcon:not(.alwaysVisible),\n    &:hover .externalPlayerIcon,\n    &:has(:focus-visible) .addToPlaylistIcon:not(.alwaysVisible),\n    &:has(:focus-visible) .quickBookmarkVideoIcon:not(.alwaysVisible),\n    &:has(:focus-visible) .externalPlayerIcon {\n      opacity: 1;\n    }\n\n    &:hover .optionsButton,\n    &:has(:focus-visible) .optionsButton,\n    // Keep visible when the drop down is open\n    :deep(.optionsButton:has(> .iconDropdown:focus-within)) {\n      opacity: 1;\n    }\n\n    .quickBookmarkVideoIcon:not(.alwaysVisible),\n    .addToPlaylistIcon:not(.alwaysVisible),\n    .externalPlayerIcon,\n    .optionsButton {\n      opacity: 0;\n      transition: visibility 0s, opacity 0.2s linear;\n    }\n  }\n}\n\n.videoWatched,\n.live,\n.upcoming {\n  user-select: none;\n}\n\n.live {\n  text-transform: uppercase;\n}\n\n// we use h3 for semantic reasons but don't want to keep the h3 style\n.h3Title {\n  margin-block-start: inherit;\n  margin-block-end: inherit;\n  font-size: inherit;\n  font-weight: inherit;\n}\n"
  },
  {
    "path": "src/renderer/scss-partials/_utils.scss",
    "content": "@mixin is-side-nav-open {\n  @at-root {\n    .isSideNavOpen &,\n    .isSideNavOpen#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin are-side-bar-labels-hidden {\n  @at-root {\n    .hideLabelsSideBar &,\n    .hideLabelsSideBar#{&} {\n      @content;\n    }\n  }\n}\n\n@mixin fixed-top-bar {\n  position: fixed;\n  inset-block-start: 60px;\n  inset-inline-end: 0;\n  inline-size: calc(100% - 80px);\n  margin-inline: 0;\n  z-index: 3;\n\n  @include is-side-nav-open {\n    inline-size: calc(100% - 200px);\n  }\n\n  @include are-side-bar-labels-hidden {\n    inline-size: calc(100% - 60px);\n  }\n\n  @media only screen and (width <= 680px) {\n    /* stylelint-disable-next-line no-invalid-position-declaration */\n    inline-size: 100%;\n\n    @include is-side-nav-open {\n      inline-size: 100%;\n    }\n\n    @include are-side-bar-labels-hidden {\n      inline-size: 100%;\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/sigFrameScript.js",
    "content": "// This is injected into the sigFrame iframe\n// See index.ejs and webpack.renderer.config.js\nwindow.addEventListener('message', (event) => {\n  const data = JSON.parse(event.data)\n\n  try {\n    window.parent.postMessage(JSON.stringify({\n      id: data.id,\n      // eslint-disable-next-line no-new-func\n      result: new Function(data.code)()\n    }), '*')\n  } catch (error) {\n    window.parent.postMessage(JSON.stringify({\n      id: data.id,\n      error: error.toString()\n    }), '*')\n  }\n})\n"
  },
  {
    "path": "src/renderer/store/index.js",
    "content": "import { createStore } from 'vuex'\n// import createPersistedState from 'vuex-persistedstate'\n\nimport history from './modules/history'\nimport invidious from './modules/invidious'\nimport playlists from './modules/playlists'\nimport profiles from './modules/profiles'\nimport settings from './modules/settings'\nimport searchHistory from './modules/search-history'\nimport subscriptionCache from './modules/subscription-cache'\nimport utils from './modules/utils'\nimport player from './modules/player'\n\nexport default createStore({\n  modules: {\n    history,\n    invidious,\n    playlists,\n    profiles,\n    settings,\n    searchHistory,\n    subscriptionCache,\n    utils,\n    player,\n  },\n\n  // Detects unsafe changes to the store state e.g. outside of mutations\n  // but we have to turn it off despite its usefulness as we have so much data in the store\n  // that it causes a noticable slow-down :(\n  strict: false\n\n  // TODO: Enable when deploy\n  // plugins: [createPersistedState()]\n})\n"
  },
  {
    "path": "src/renderer/store/modules/history.js",
    "content": "import { DBHistoryHandlers } from '../../../datastores/handlers/index'\n\nconst state = {\n  historyCacheSorted: [],\n\n  // Vuex doesn't support Maps, so we have to use an object here instead\n  // TODO: switch to a Map during the Pinia migration\n  historyCacheById: {}\n}\n\nconst getters = {\n  getHistoryCacheSorted(state) {\n    return state.historyCacheSorted\n  },\n\n  getHistoryCacheById(state) {\n    return state.historyCacheById\n  }\n}\n\nconst actions = {\n  async grabHistory({ commit }) {\n    try {\n      const results = await DBHistoryHandlers.find()\n\n      const resultsById = {}\n      results.forEach(video => {\n        resultsById[video.videoId] = video\n      })\n\n      commit('setHistoryCacheSorted', results)\n      commit('setHistoryCacheById', resultsById)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateHistory({ commit }, record) {\n    try {\n      await DBHistoryHandlers.upsert(record)\n      commit('upsertToHistoryCache', record)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  /**\n   * @param {any} param0\n   * @param {Map<string, any>} historyItems\n   */\n  async overwriteHistory({ commit }, historyItems) {\n    try {\n      const sortedRecords = Array.from(historyItems.values())\n\n      // sort before sending saving to the database and passing to other windows\n      // so that the other windows can use it as is, without having to sort the array themselves\n      sortedRecords.sort((a, b) => b.timeWatched - a.timeWatched)\n\n      await DBHistoryHandlers.overwrite(sortedRecords)\n\n      commit('setHistoryCacheSorted', sortedRecords)\n      commit('setHistoryCacheById', Object.fromEntries(historyItems))\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeFromHistory({ commit }, videoId) {\n    try {\n      await DBHistoryHandlers.delete(videoId)\n      commit('removeFromHistoryCacheById', videoId)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeAllHistory({ commit }) {\n    try {\n      await DBHistoryHandlers.deleteAll()\n      commit('setHistoryCacheSorted', [])\n      commit('setHistoryCacheById', {})\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateWatchProgress({ commit }, { videoId, watchProgress }) {\n    try {\n      await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)\n      commit('updateRecordWatchProgressInHistoryCache', { videoId, watchProgress })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateLastViewedPlaylist({ commit }, { videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId }) {\n    try {\n      await DBHistoryHandlers.updateLastViewedPlaylist(videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId)\n      commit('updateRecordLastViewedPlaylistIdInHistoryCache', { videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n}\n\nconst mutations = {\n  setHistoryCacheSorted(state, historyCacheSorted) {\n    state.historyCacheSorted = historyCacheSorted\n  },\n\n  setHistoryCacheById(state, historyCacheById) {\n    state.historyCacheById = historyCacheById\n  },\n\n  upsertToHistoryCache(state, record) {\n    const i = state.historyCacheSorted.findIndex((currentRecord) => {\n      return record.videoId === currentRecord.videoId\n    })\n\n    if (i !== -1) {\n      // Already in cache\n      // Must be hoisted to top, remove it and then unshift it\n      state.historyCacheSorted.splice(i, 1)\n    }\n\n    state.historyCacheSorted.unshift(record)\n    state.historyCacheById[record.videoId] = record\n  },\n\n  updateRecordWatchProgressInHistoryCache(state, { videoId, watchProgress }) {\n    // historyCacheById and historyCacheSorted reference the same object instances,\n    // so modifying an existing object in one of them will update both.\n\n    const record = state.historyCacheById[videoId]\n\n    // Don't set, if the item was removed from the watch history, as we don't have any video details\n    if (record) {\n      record.watchProgress = watchProgress\n    }\n  },\n\n  updateRecordLastViewedPlaylistIdInHistoryCache(state, { videoId, lastViewedPlaylistId, lastViewedPlaylistType, lastViewedPlaylistItemId }) {\n    // historyCacheById and historyCacheSorted reference the same object instances,\n    // so modifying an existing object in one of them will update both.\n\n    const record = state.historyCacheById[videoId]\n\n    // Don't set, if the item was removed from the watch history, as we don't have any video details\n    if (record) {\n      record.lastViewedPlaylistId = lastViewedPlaylistId\n      record.lastViewedPlaylistType = lastViewedPlaylistType\n      record.lastViewedPlaylistItemId = lastViewedPlaylistItemId\n    }\n  },\n\n  removeFromHistoryCacheById(state, videoId) {\n    for (let i = 0; i < state.historyCacheSorted.length; i++) {\n      if (state.historyCacheSorted[i].videoId === videoId) {\n        state.historyCacheSorted.splice(i, 1)\n        break\n      }\n    }\n\n    delete state.historyCacheById[videoId]\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/invidious.js",
    "content": "import { base64EncodeUtf8, createWebURL, fetchWithTimeout, randomArrayItem } from '../../helpers/utils'\n\nconst state = {\n  currentInvidiousInstance: '',\n  currentInvidiousInstanceAuthorization: null,\n  currentInvidiousInstanceUrl: '',\n  invidiousInstancesList: null\n}\n\nconst getters = {\n  getCurrentInvidiousInstance(state) {\n    return state.currentInvidiousInstance\n  },\n\n  getCurrentInvidiousInstanceUrl(state) {\n    return state.currentInvidiousInstanceUrl\n  },\n\n  getCurrentInvidiousInstanceAuthorization(state) {\n    return state.currentInvidiousInstanceAuthorization\n  },\n\n  getInvidiousInstancesList(state) {\n    return state.invidiousInstancesList\n  }\n}\n\nconst actions = {\n  async fetchInvidiousInstancesFromFile({ commit }) {\n    const url = createWebURL('/static/invidious-instances.json')\n\n    const fileData = await (await fetch(url)).json()\n    const instances = fileData.filter(e => {\n      return process.env.SUPPORTS_LOCAL_API || e.cors\n    }).map(e => {\n      return e.url\n    })\n\n    commit('setInvidiousInstancesList', instances)\n  },\n\n  /// fetch invidious instances from site and overwrite static file.\n  async fetchInvidiousInstances({ commit }) {\n    const requestUrl = 'https://api.invidious.io/instances.json'\n    try {\n      const response = await fetchWithTimeout(15_000, requestUrl)\n      const json = await response.json()\n      const instances = json.filter((instance) => {\n        return !(instance[0].includes('.onion') ||\n          instance[0].includes('.i2p') ||\n          !instance[1].api ||\n          (!process.env.SUPPORTS_LOCAL_API && !instance[1].cors))\n      }).map((instance) => {\n        return instance[1].uri.replace(/\\/$/, '')\n      })\n\n      if (instances.length !== 0) {\n        commit('setInvidiousInstancesList', instances)\n      } else {\n        console.warn('using static file for invidious instances')\n      }\n    } catch (err) {\n      if (err.name === 'TimeoutError') {\n        console.error('Fetching the Invidious instance list timed out after 15 seconds. Falling back to local copy.')\n      } else {\n        console.error(err)\n      }\n    }\n  },\n\n  setRandomCurrentInvidiousInstance({ commit, state }) {\n    const instanceList = state.invidiousInstancesList\n    commit('setCurrentInvidiousInstance', randomArrayItem(instanceList))\n  }\n}\n\nconst mutations = {\n  setCurrentInvidiousInstance(state, value) {\n    state.currentInvidiousInstance = value\n\n    let url\n    try {\n      url = new URL(value)\n    } catch { }\n\n    let authorization = null\n\n    if (url && (url.username.length > 0 || url.password.length > 0)) {\n      authorization = `Basic ${base64EncodeUtf8(`${url.username}:${url.password}`)}`\n    }\n\n    state.currentInvidiousInstanceAuthorization = authorization\n\n    let instanceUrl\n\n    if (url && authorization) {\n      url.username = ''\n      url.password = ''\n\n      instanceUrl = url.toString().replace(/\\/$/, '')\n    } else {\n      instanceUrl = value\n    }\n\n    state.currentInvidiousInstanceUrl = instanceUrl\n\n    if (process.env.IS_ELECTRON) {\n      if (authorization) {\n        window.ftElectron.setInvidiousAuthorization(authorization, instanceUrl)\n      } else {\n        window.ftElectron.clearInvidiousAuthorization()\n      }\n    }\n  },\n\n  setInvidiousInstancesList(state, value) {\n    state.invidiousInstancesList = value\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/player.js",
    "content": "import { createWebURL } from '../../helpers/utils'\n\n// replace with a Map after the Vue 3 and Pinia migrations\nconst state = {\n  cachedPlayerLocales: {}\n}\n\nconst getters = {}\n\nconst actions = {\n  async cachePlayerLocale({ commit }, locale) {\n    const url = createWebURL(`/static/shaka-player-locales/${locale}.json`)\n\n    const response = await fetch(url)\n    const data = await response.json()\n\n    Object.freeze(data)\n\n    commit('addPlayerLocaleToCache', { locale, data })\n  }\n}\n\nconst mutations = {\n  addPlayerLocaleToCache(state, { locale, data }) {\n    state.cachedPlayerLocales[locale] = data\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/playlists.js",
    "content": "import { DBPlaylistHandlers } from '../../../datastores/handlers/index'\nimport { generateRandomUniqueId, processToBeAddedPlaylistVideo } from '../../helpers/playlists'\n\nfunction generateRandomPlaylistId() {\n  return `ft-playlist--${generateRandomUniqueId()}`\n}\n\nfunction generateRandomPlaylistName() {\n  return `Playlist ${new Date().toISOString()}-${Math.floor(Math.random() * 10000)}`\n}\n\n/*\n*  Function to find the first playlist with 0 videos, or otherwise the most recently accessed.\n*  This is a good default quick bookmark target if one needs to be set.\n*/\nfunction findEmptyOrLatestPlayedPlaylist(playlists) {\n  const emptyPlaylist = playlists.find((playlist) => playlist.videos.length === 0)\n  if (emptyPlaylist) return emptyPlaylist\n\n  let max = -1\n  let maxIndex = 0\n  for (let i = 0; i < playlists.length; i++) {\n    if (playlists[i].lastPlayedAt != null && playlists[i].lastPlayedAt > max) {\n      maxIndex = i\n      max = playlists[i].lastPlayedAt\n    }\n  }\n\n  return playlists[maxIndex]\n}\n\n/**\n * @param {any} playlist\n */\nfunction processNewPlayist(playlist) {\n  // In case internal id is forgotten, generate one (instead of relying on caller and there being a chance of data corruption)\n  if (playlist._id == null) {\n    // {Time now in unix time}-{0-9999}\n    playlist._id = generateRandomPlaylistId()\n  }\n\n  // Ensure playlist name trimmed\n  if (typeof playlist.playlistName === 'string') {\n    playlist.playlistName = playlist.playlistName.trim()\n  }\n\n  // Ensure playlist description trimmed\n  if (typeof playlist.description === 'string') {\n    playlist.description = playlist.description.trim()\n  }\n\n  const now = Date.now()\n  playlist.createdAt = now\n  playlist.lastUpdatedAt = now\n\n  // Ensure all videos have required attributes\n  if (Array.isArray(playlist.videos)) {\n    playlist.videos.forEach(processToBeAddedPlaylistVideo)\n  }\n}\n\nconst state = {\n  // Playlist loading takes time on app load (new windows)\n  // This is necessary to let components to know when to start data loading\n  // which depends on playlist data being ready\n  playlistsReady: false,\n  playlists: [],\n  defaultPlaylists: [\n    {\n      playlistName: 'Favorites',\n      protected: false,\n      description: 'Your favorite videos',\n      videos: [],\n      _id: 'favorites',\n    },\n    {\n      playlistName: 'Watch Later',\n      protected: false,\n      description: 'Videos to watch later',\n      videos: [],\n      _id: 'watchLater',\n    },\n  ],\n}\n\nconst getters = {\n  getPlaylistsReady: (state) => state.playlistsReady,\n  getAllPlaylists: (state) => state.playlists,\n  getPlaylist: (state) => (playlistId) => {\n    return state.playlists.find(playlist => playlist._id === playlistId)\n  },\n  getQuickBookmarkPlaylist(state, getters) {\n    const playlistId = getters.getQuickBookmarkTargetPlaylistId\n\n    if (!playlistId) {\n      return undefined\n    }\n\n    return state.playlists.find((playlist) => playlist._id === playlistId)\n  }\n}\n\nconst actions = {\n  async addPlaylist({ state, commit, rootState, dispatch }, payload) {\n    processNewPlayist(payload)\n\n    try {\n      await DBPlaylistHandlers.create([payload])\n\n      const noQuickBookmarkSet = !rootState.settings.quickBookmarkTargetPlaylistId || !state.playlists.some((playlist) => playlist._id === rootState.settings.quickBookmarkTargetPlaylistId)\n      if (noQuickBookmarkSet) {\n        dispatch('updateQuickBookmarkTargetPlaylistId', payload._id, { root: true })\n      }\n\n      commit('addPlaylist', payload)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async addPlaylists({ state, commit, rootState, dispatch }, payload) {\n    payload.forEach(processNewPlayist)\n\n    try {\n      await DBPlaylistHandlers.create(payload)\n\n      const noQuickBookmarkSet = !rootState.settings.quickBookmarkTargetPlaylistId || !state.playlists.some((playlist) => playlist._id === rootState.settings.quickBookmarkTargetPlaylistId)\n      if (noQuickBookmarkSet) {\n        const chosenPlaylist = findEmptyOrLatestPlayedPlaylist(payload)\n        dispatch('updateQuickBookmarkTargetPlaylistId', chosenPlaylist._id, { root: true })\n      }\n\n      commit('addPlaylists', payload)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updatePlaylist({ commit }, playlist) {\n    // Ensure playlist name trimmed\n    if (typeof playlist.playlistName === 'string') {\n      playlist.playlistName = playlist.playlistName.trim()\n    }\n    // Ensure playlist description trimmed\n    if (typeof playlist.description === 'string') {\n      playlist.description = playlist.description.trim()\n    }\n    // Caller no need to assign last updated time\n    playlist.lastUpdatedAt = Date.now()\n\n    try {\n      await DBPlaylistHandlers.upsert(playlist)\n      commit('upsertPlaylistToList', playlist)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updatePlaylistLastPlayedAt({ commit }, playlist) {\n    // This action does NOT update `lastUpdatedAt` on purpose\n    // Only `lastPlayedAt` should be updated\n    playlist.lastPlayedAt = Date.now()\n\n    try {\n      await DBPlaylistHandlers.upsert(playlist)\n      commit('upsertPlaylistToList', playlist)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async addVideo({ commit }, payload) {\n    try {\n      const { _id, videoData } = payload\n\n      processToBeAddedPlaylistVideo(videoData)\n\n      const lastUpdatedAt = Date.now()\n\n      await DBPlaylistHandlers.upsertVideoByPlaylistId(_id, lastUpdatedAt, videoData)\n\n      payload.lastUpdatedAt = lastUpdatedAt\n      commit('addVideo', payload)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async addVideos({ commit }, payload) {\n    // Assumes videos are added NOT from export\n    // Since this action will ensure uniqueness of `playlistItemId` of added video entries\n    try {\n      const { _id, videos } = payload\n\n      const currentTime = Date.now()\n\n      const newVideoObjects = videos.map((video) => {\n        // Create a new object to prevent changing existing values outside\n        const videoData = Object.assign({}, video)\n        if (videoData.timeAdded == null) {\n          videoData.timeAdded = currentTime\n        }\n        videoData.playlistItemId = generateRandomUniqueId()\n        // For backward compatibility\n        if (videoData.type == null) {\n          videoData.type = 'video'\n        }\n        // Undesired attributes, even with `null` values\n        [\n          'authorUrl',\n          'description',\n          'index',\n          'liveNow',\n          'videoThumbnails',\n          'viewCount',\n        ].forEach(attrName => {\n          if (typeof videoData[attrName] !== 'undefined') {\n            delete videoData[attrName]\n          }\n        })\n\n        return videoData\n      })\n\n      const lastUpdatedAt = Date.now()\n\n      await DBPlaylistHandlers.upsertVideosByPlaylistId(_id, lastUpdatedAt, newVideoObjects)\n      commit('addVideos', { _id, lastUpdatedAt, videos: newVideoObjects })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async grabAllPlaylists({ rootState, commit, dispatch, state }) {\n    try {\n      const payload = (await DBPlaylistHandlers.find()).filter((e) => e != null)\n      if (payload.length === 0) {\n        // Not using `addPlaylists` to ensure required attributes with dynamic values added\n        state.defaultPlaylists.forEach(playlist => {\n          dispatch('addPlaylist', playlist)\n        })\n      } else {\n        const dateNow = Date.now()\n        const currentTime = Date.now()\n\n        payload.forEach((playlist) => {\n          let anythingUpdated = false\n          // Assign generated playlist ID in case DB data corrupted\n          if (playlist._id == null) {\n            // {Time now in unix time}-{0-9999}\n            playlist._id = generateRandomPlaylistId()\n            anythingUpdated = true\n          }\n          // Ensure all videos has `playlistName` property\n          if (playlist.playlistName == null) {\n            // Time now in unix time, in ms\n            playlist.playlistName = generateRandomPlaylistName()\n            anythingUpdated = true\n          }\n          // Assign current time as created time in case DB data corrupted\n          if (playlist.createdAt == null) {\n            // Time now in unix time, in ms\n            playlist.createdAt = dateNow\n            anythingUpdated = true\n          }\n          // Assign current time as last updated time in case DB data corrupted\n          if (playlist.lastUpdatedAt == null) {\n            // Time now in unix time, in ms\n            playlist.lastUpdatedAt = dateNow\n            anythingUpdated = true\n          }\n          playlist.videos.forEach((v) => {\n            // Ensure all videos has `timeAdded` property\n            if (v.timeAdded == null) {\n              v.timeAdded = currentTime\n              anythingUpdated = true\n            }\n\n            // Ensure all videos has `playlistItemId` property\n            if (v.playlistItemId == null) {\n              v.playlistItemId = generateRandomUniqueId()\n              anythingUpdated = true\n            }\n\n            // For backward compatibility\n            if (v.type == null) {\n              v.type = 'video'\n              anythingUpdated = true\n            }\n\n            // Undesired attributes, even with `null` values\n            [\n              'description',\n              'viewCount',\n            ].forEach(attrName => {\n              if (typeof v[attrName] !== 'undefined') {\n                delete v[attrName]\n                anythingUpdated = true\n              }\n            })\n          })\n          // Save updated playlist object\n          if (anythingUpdated) {\n            DBPlaylistHandlers.upsert(playlist)\n          }\n        })\n\n        const favoritesPlaylist = payload.find((playlist) => {\n          return playlist.playlistName === 'Favorites' || playlist._id === 'favorites'\n        })\n        const watchLaterPlaylist = payload.find((playlist) => {\n          return playlist.playlistName === 'Watch Later' || playlist._id === 'watchLater'\n        })\n\n        if (favoritesPlaylist != null) {\n          const defaultFavoritesPlaylist = state.defaultPlaylists.find((e) => e._id === 'favorites')\n\n          // Update existing matching playlist only if it exists\n          if (favoritesPlaylist._id !== defaultFavoritesPlaylist._id || favoritesPlaylist.protected !== defaultFavoritesPlaylist.protected) {\n            const oldId = favoritesPlaylist._id\n            favoritesPlaylist._id = defaultFavoritesPlaylist._id\n            favoritesPlaylist.protected = defaultFavoritesPlaylist.protected\n            if (oldId === defaultFavoritesPlaylist._id) {\n              // Update playlist if ID already the same\n              DBPlaylistHandlers.upsert(favoritesPlaylist)\n            } else {\n              dispatch('removePlaylist', oldId)\n              // DO NOT use dispatch('addPlaylist', ...)\n              // Which causes duplicate displayed playlist in window (But DB is fine)\n              // Due to the object is already in `payload`\n              DBPlaylistHandlers.create(favoritesPlaylist)\n            }\n          }\n        }\n\n        if (watchLaterPlaylist != null) {\n          const defaultWatchLaterPlaylist = state.defaultPlaylists.find((e) => e._id === 'watchLater')\n\n          // Update existing matching playlist only if it exists\n          if (watchLaterPlaylist._id !== defaultWatchLaterPlaylist._id || watchLaterPlaylist.protected !== defaultWatchLaterPlaylist.protected) {\n            const oldId = watchLaterPlaylist._id\n            watchLaterPlaylist._id = defaultWatchLaterPlaylist._id\n            watchLaterPlaylist.protected = defaultWatchLaterPlaylist.protected\n            if (oldId === defaultWatchLaterPlaylist._id) {\n              // Update playlist if ID already the same\n              DBPlaylistHandlers.upsert(watchLaterPlaylist)\n            } else {\n              dispatch('removePlaylist', oldId)\n              // DO NOT use dispatch('addPlaylist', ...)\n              // Which causes duplicate displayed playlist in window (But DB is fine)\n              // Due to the object is already in `payload`\n              DBPlaylistHandlers.create(watchLaterPlaylist)\n            }\n          }\n        }\n\n        // if no quick bookmark is set, try to find another playlist\n        const noQuickBookmarkSet = !rootState.settings.quickBookmarkTargetPlaylistId || !payload.some((playlist) => playlist._id === rootState.settings.quickBookmarkTargetPlaylistId)\n        if (noQuickBookmarkSet && payload.length > 0) {\n          const chosenPlaylist = findEmptyOrLatestPlayedPlaylist(payload)\n          dispatch('updateQuickBookmarkTargetPlaylistId', chosenPlaylist._id, { root: true })\n        }\n\n        commit('setAllPlaylists', payload)\n      }\n      commit('setPlaylistsReady', true)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeAllPlaylists({ commit }) {\n    try {\n      await DBPlaylistHandlers.deleteAll()\n      commit('removeAllPlaylists')\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeAllVideos({ commit }, _id) {\n    try {\n      await DBPlaylistHandlers.deleteAllVideosByPlaylistId(_id)\n      commit('removeAllVideos', _id)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removePlaylist({ commit }, playlistId) {\n    try {\n      await DBPlaylistHandlers.delete(playlistId)\n      commit('removePlaylist', playlistId)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removePlaylists({ commit }, playlistIds) {\n    try {\n      await DBPlaylistHandlers.deleteMultiple(playlistIds)\n      commit('removePlaylists', playlistIds)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeVideo({ commit }, payload) {\n    try {\n      const { _id, videoId, playlistItemId } = payload\n\n      const lastUpdatedAt = Date.now()\n\n      await DBPlaylistHandlers.deleteVideoIdByPlaylistId(_id, lastUpdatedAt, videoId, playlistItemId)\n\n      payload.lastUpdatedAt = lastUpdatedAt\n\n      commit('removeVideo', payload)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeVideos({ commit }, payload) {\n    try {\n      const { _id, playlistItemIds } = payload\n\n      const lastUpdatedAt = Date.now()\n\n      await DBPlaylistHandlers.deleteVideoIdsByPlaylistId(_id, lastUpdatedAt, playlistItemIds)\n\n      payload.lastUpdatedAt = lastUpdatedAt\n\n      commit('removeVideos', payload)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n}\n\nconst mutations = {\n  addPlaylist(state, payload) {\n    state.playlists.push(payload)\n  },\n\n  addPlaylists(state, payload) {\n    state.playlists.push(...payload)\n  },\n\n  upsertPlaylistToList(state, updatedPlaylist) {\n    const i = state.playlists.findIndex((p) => {\n      return p._id === updatedPlaylist._id\n    })\n\n    if (i === -1) {\n      state.playlists.push(updatedPlaylist)\n    } else {\n      const foundPlaylist = state.playlists[i]\n      state.playlists.splice(i, 1, Object.assign(foundPlaylist, updatedPlaylist))\n    }\n  },\n\n  addVideo(state, payload) {\n    const playlist = state.playlists.find(playlist => playlist._id === payload._id)\n    if (playlist) {\n      playlist.videos.push(payload.videoData)\n      playlist.lastUpdatedAt = payload.lastUpdatedAt\n    }\n  },\n\n  addVideos(state, payload) {\n    const playlist = state.playlists.find(playlist => playlist._id === payload._id)\n    if (playlist) {\n      playlist.videos = [].concat(playlist.videos, payload.videos)\n      playlist.lastUpdatedAt = payload.lastUpdatedAt\n    }\n  },\n\n  removeAllPlaylists(state) {\n    state.playlists = []\n  },\n\n  removeAllVideos(state, playlistId) {\n    const playlist = state.playlists.find(playlist => playlist._id === playlistId)\n    if (playlist) {\n      playlist.videos = []\n    }\n  },\n\n  removeVideo(state, { _id, lastUpdatedAt, videoId, playlistItemId }) {\n    const playlist = state.playlists.find(playlist => playlist._id === _id)\n    if (playlist) {\n      if (playlistItemId != null) {\n        playlist.videos = playlist.videos.filter(video => video.playlistItemId !== playlistItemId)\n        playlist.lastUpdatedAt = lastUpdatedAt\n      } else if (videoId != null) {\n        playlist.videos = playlist.videos.filter(video => video.videoId !== videoId)\n        playlist.lastUpdatedAt = lastUpdatedAt\n      }\n    }\n  },\n\n  removeVideos(state, { _id, lastUpdatedAt, playlistItemIds }) {\n    const playlist = state.playlists.find(playlist => playlist._id === _id)\n    if (playlist) {\n      playlist.videos = playlist.videos.filter(video => {\n        const playlistItemIdMatches = playlistItemIds.includes(video.playlistItemId)\n        return !playlistItemIdMatches\n      })\n      playlist.lastUpdatedAt = lastUpdatedAt\n    }\n  },\n\n  removePlaylist(state, playlistId) {\n    state.playlists = state.playlists.filter(playlist => playlist._id !== playlistId || playlist.protected)\n  },\n\n  setAllPlaylists(state, payload) {\n    state.playlists = payload\n  },\n\n  setPlaylistsReady(state, payload) {\n    state.playlistsReady = payload\n  },\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/profiles.js",
    "content": "import { MAIN_PROFILE_ID } from '../../../constants'\nimport { DBProfileHandlers } from '../../../datastores/handlers/index'\nimport { calculateColorLuminance, getRandomColor } from '../../helpers/colors'\nimport { deepCopy } from '../../helpers/utils'\n\nconst state = {\n  profileList: [{\n    _id: MAIN_PROFILE_ID,\n    name: 'All Channels',\n    bgColor: '#000000',\n    textColor: '#FFFFFF',\n    subscriptions: []\n  }],\n  activeProfile: MAIN_PROFILE_ID\n}\n\nconst getters = {\n  getProfileList: (state) => {\n    return state.profileList\n  },\n\n  getActiveProfile: (state) => {\n    const activeProfileId = state.activeProfile\n    return state.profileList.find((profile) => {\n      return profile._id === activeProfileId\n    })\n  },\n\n  profileById: (state) => (id) => {\n    return state.profileList.find(p => p._id === id)\n  },\n\n  getSubscribedChannelIdSet: (state) => {\n    // The all channels profile is always the first profile in the array\n    const mainProfile = state.profileList[0]\n\n    return mainProfile.subscriptions.reduce((set, channel) => set.add(channel.id), new Set())\n  },\n}\n\nfunction profileSort(a, b) {\n  if (a._id === MAIN_PROFILE_ID) return -1\n  if (b._id === MAIN_PROFILE_ID) return 1\n  if (a.name < b.name) return -1\n  if (a.name > b.name) return 1\n  return 0\n}\n\nconst actions = {\n  async grabAllProfiles({ rootState, commit, state }, defaultName = null) {\n    let profiles\n    try {\n      profiles = await DBProfileHandlers.find()\n    } catch (errMessage) {\n      console.error(errMessage)\n      return\n    }\n\n    if (!Array.isArray(profiles)) return\n\n    if (profiles.length === 0) {\n      // Create a default profile and persist it\n      const randomColor = getRandomColor().value\n      const textColor = calculateColorLuminance(randomColor)\n      const defaultProfile = {\n        _id: MAIN_PROFILE_ID,\n        name: defaultName,\n        bgColor: randomColor,\n        textColor: textColor,\n        subscriptions: []\n      }\n\n      try {\n        await DBProfileHandlers.create(defaultProfile)\n        commit('setProfileList', [defaultProfile])\n      } catch (errMessage) {\n        console.error(errMessage)\n      }\n\n      return\n    }\n\n    // We want the primary profile to always be first\n    // So sort with that then sort alphabetically by profile name\n    profiles = profiles.sort(profileSort)\n\n    if (state.profileList.length < profiles.length) {\n      const profile = profiles.find((profile) => {\n        return profile._id === rootState.settings.defaultProfile\n      })\n\n      if (profile) {\n        commit('setActiveProfile', profile._id)\n      }\n    }\n\n    commit('setProfileList', profiles)\n  },\n\n  async batchUpdateSubscriptionDetails({ dispatch, state }, channels) {\n    if (channels.length === 0) { return }\n\n    const profileList = state.profileList\n\n    for (const profile of profileList) {\n      const currentProfileCopy = deepCopy(profile)\n      let profileUpdated = false\n\n      for (const { channelThumbnailUrl, channelName, channelId } of channels) {\n        const channel = currentProfileCopy.subscriptions.find((channel) => {\n          return channel.id === channelId\n        }) ?? null\n\n        if (channel === null) { continue }\n\n        if (channel.name !== channelName && channelName != null) {\n          channel.name = channelName\n          profileUpdated = true\n        }\n\n        if (channelThumbnailUrl) {\n          const thumbnail = channelThumbnailUrl\n            // change thumbnail size if different\n            .replace(/=s\\d*/, '=s176')\n            // If this is an Invidious URL, convert it to a YouTube one\n            .replace(/^https?:\\/\\/[^/]+\\/ggpht/, 'https://yt3.googleusercontent.com')\n\n          if (channel.thumbnail !== thumbnail) {\n            channel.thumbnail = thumbnail\n            profileUpdated = true\n          }\n        }\n      }\n\n      if (profileUpdated) {\n        await dispatch('updateProfile', currentProfileCopy)\n      }\n    }\n  },\n\n  async updateSubscriptionDetails({ dispatch, state }, { channelThumbnailUrl, channelName, channelId }) {\n    const thumbnail = channelThumbnailUrl\n      // change thumbnail size if different\n      ?.replace(/=s\\d*/, '=s176')\n      // If this is an Invidious URL, convert it to a YouTube one\n      .replace(/^https?:\\/\\/[^/]+\\/ggpht/, 'https://yt3.googleusercontent.com') ??\n      null\n    const profileList = state.profileList\n    for (const profile of profileList) {\n      const currentProfileCopy = deepCopy(profile)\n      const channel = currentProfileCopy.subscriptions.find((channel) => {\n        return channel.id === channelId\n      }) ?? null\n      if (channel === null) { continue }\n      let updated = false\n      if (channel.name !== channelName && channelName != null) {\n        channel.name = channelName\n        updated = true\n      }\n      if (channel.thumbnail !== thumbnail && thumbnail != null) {\n        channel.thumbnail = thumbnail\n        updated = true\n      }\n      if (updated) {\n        await dispatch('updateProfile', currentProfileCopy)\n      } else { // channel has not been updated, stop iterating through profiles\n        break\n      }\n    }\n  },\n\n  async createProfile({ commit }, profile) {\n    try {\n      const newProfile = await DBProfileHandlers.create(profile)\n      commit('addProfileToList', newProfile)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateProfile({ commit }, profile) {\n    try {\n      await DBProfileHandlers.upsert(profile)\n      commit('upsertProfileToList', profile)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async addChannelToProfiles({ commit }, { channel, profileIds }) {\n    // If this is an Invidious URL, convert it to a YouTube one\n    if (!channel.thumbnail.startsWith('https://yt3.googleusercontent.com/')) {\n      channel.thumbnail = channel.thumbnail.replace(/^https?:\\/\\/[^/]+\\/ggpht/, 'https://yt3.googleusercontent.com')\n    }\n\n    try {\n      await DBProfileHandlers.addChannelToProfiles(channel, profileIds)\n      commit('addChannelToProfiles', { channel, profileIds })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeChannelFromProfiles({ commit }, { channelId, profileIds }) {\n    try {\n      await DBProfileHandlers.removeChannelFromProfiles(channelId, profileIds)\n      commit('removeChannelFromProfiles', { channelId, profileIds })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeProfile({ commit }, profileId) {\n    try {\n      await DBProfileHandlers.delete(profileId)\n      commit('removeProfileFromList', profileId)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  updateActiveProfile({ commit }, id) {\n    commit('setActiveProfile', id)\n  }\n}\n\nconst mutations = {\n  setProfileList(state, profileList) {\n    state.profileList = profileList\n  },\n\n  setActiveProfile(state, activeProfile) {\n    state.activeProfile = activeProfile\n  },\n\n  addProfileToList(state, profile) {\n    state.profileList.push(profile)\n    state.profileList.sort(profileSort)\n  },\n\n  upsertProfileToList(state, updatedProfile) {\n    const i = state.profileList.findIndex((p) => {\n      return p._id === updatedProfile._id\n    })\n\n    if (i === -1) {\n      state.profileList.push(updatedProfile)\n    } else {\n      state.profileList.splice(i, 1, updatedProfile)\n    }\n\n    state.profileList.sort(profileSort)\n  },\n\n  addChannelToProfiles(state, { channel, profileIds }) {\n    for (const id of profileIds) {\n      state.profileList.find(profile => profile._id === id).subscriptions.push(channel)\n    }\n  },\n\n  removeChannelFromProfiles(state, { channelId, profileIds }) {\n    for (const id of profileIds) {\n      const profile = state.profileList.find(profile => profile._id === id)\n\n      // use filter instead of splice in case the subscription appears multiple times\n      // https://github.com/FreeTubeApp/FreeTube/pull/3468#discussion_r1179290877\n      profile.subscriptions = profile.subscriptions.filter(channel => channel.id !== channelId)\n    }\n  },\n\n  removeProfileFromList(state, profileId) {\n    const i = state.profileList.findIndex((profile) => {\n      return profile._id === profileId\n    })\n\n    state.profileList.splice(i, 1)\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/search-history.js",
    "content": "import { MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT, SEARCH_RESULTS_DISPLAY_LIMIT } from '../../../constants'\nimport { DBSearchHistoryHandlers } from '../../../datastores/handlers/index'\n\nconst state = {\n  searchHistoryEntries: []\n}\n\nconst getters = {\n  getSearchHistoryEntries: (state) => {\n    return state.searchHistoryEntries\n  },\n\n  getLatestSearchHistoryNames: (state) => {\n    return state.searchHistoryEntries.slice(0, SEARCH_RESULTS_DISPLAY_LIMIT).map((entry) => entry._id)\n  },\n\n  getLatestMatchingSearchHistoryNames: (state) => (id) => {\n    const matches = []\n    let counter = 0\n\n    for (const entry of state.searchHistoryEntries) {\n      if (entry._id.startsWith(id)) {\n        matches.push(entry._id)\n\n        counter++\n\n        if (counter === MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT) {\n          break\n        }\n      }\n    }\n\n    // prioritize more concise matches\n    return matches.sort((a, b) => a.length - b.length)\n  },\n\n  getSearchHistoryEntryWithId: (state) => (id) => {\n    return state.searchHistoryEntries.find(p => p._id === id)\n  },\n}\nconst actions = {\n  async grabSearchHistoryEntries({ commit }) {\n    try {\n      const results = await DBSearchHistoryHandlers.find()\n      commit('setSearchHistoryEntries', results)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSearchHistoryEntry({ commit }, searchHistoryEntry) {\n    try {\n      await DBSearchHistoryHandlers.upsert(searchHistoryEntry)\n      commit('upsertSearchHistoryEntryToList', searchHistoryEntry)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  /**\n   * @param {any} param0\n   * @param {{ _id: string, lastUpdatedAt: number }[]} historyItems\n   */\n  async overwriteSearchHistory({ commit }, historyItems) {\n    try {\n      // sort before sending saving to the database and passing to other windows\n      // so that the other windows can use it as is, without having to sort the array themselves\n      historyItems.sort((a, b) => b.timeWatched - a.timeWatched)\n\n      await DBSearchHistoryHandlers.overwrite(historyItems)\n      commit('setSearchHistoryEntries', historyItems)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeSearchHistoryEntry({ commit }, _id) {\n    try {\n      await DBSearchHistoryHandlers.delete(_id)\n      commit('removeSearchHistoryEntryFromList', _id)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async removeAllSearchHistoryEntries({ commit }) {\n    try {\n      await DBSearchHistoryHandlers.deleteAll()\n      commit('setSearchHistoryEntries', [])\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n}\n\nconst mutations = {\n  setSearchHistoryEntries(state, searchHistoryEntries) {\n    state.searchHistoryEntries = searchHistoryEntries\n  },\n\n  upsertSearchHistoryEntryToList(state, updatedSearchHistoryEntry) {\n    state.searchHistoryEntries = state.searchHistoryEntries.filter((p) => {\n      return p._id !== updatedSearchHistoryEntry._id\n    })\n\n    state.searchHistoryEntries.unshift(updatedSearchHistoryEntry)\n  },\n\n  removeSearchHistoryEntryFromList(state, _id) {\n    state.searchHistoryEntries = state.searchHistoryEntries.filter((searchHistoryEntry) => searchHistoryEntry._id !== _id)\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/settings.js",
    "content": "import i18n, { loadLocale } from '../../i18n/index'\nimport allLocales from '../../../../static/locales/activeLocales.json'\nimport { MAIN_PROFILE_ID, SyncEvents } from '../../../constants'\nimport { DBSettingHandlers } from '../../../datastores/handlers/index'\nimport { getSystemLocale, showToast } from '../../helpers/utils'\n\n/*\n * Due to the complexity of the settings module in FreeTube, a more\n * in-depth explanation for adding new settings is required.\n *\n * The explanation will be written with the assumption that\n * the reader knows how Vuex works.\n *\n * And no, there's no need to read the entire wall of text.\n * We'll direct you where you need to go as we walk you through it.\n * Additionally, the text actually looks bigger than it truly is.\n * Each line has, at most, 72 characters.\n *\n ****\n * Introduction\n *\n * You can add a new setting in two different methods.\n *\n * The first method benefits from the auto-generation of\n * a getter, a mutation and a few actions related to the setting.\n * This method should be preferred whenever possible:\n * - `state`\n *\n * The last one DOES NOT feature any kind of auto-generation and should\n * only be used in scenarios that don't fall under the other 2 options:\n * - `customState`\n *\n ****\n * ASIDE:\n * The aforementioned \"side effects\" cover a large area\n * of interactions with other modules\n * A good example would be a setting that utilizes the Electron API\n * when its value changes.\n *\n ****\n * First and foremost, you have to understand what type of setting\n * you intend to add to the app.\n *\n * You'll have to select one of these three scenarios:\n *\n * 1) You just want to add a simple setting that does not actively\n *    interact with the Electron API, `localStorage` or\n *    other parts outside of the settings module.\n * -> Please consult the `state` section.\n *\n * 2) You want to add a more complex setting that interacts\n *    with other parts of the app and tech stack.\n * -> Please consult the `state` and `sideEffectHandlers` sections.\n *\n * 3) You want to add a completely custom state based setting\n *    that does not work like the usual settings.\n * -> Please consult the `state` and `customState` sections.\n *\n ****\n * `state`\n * This object contains settings that have NO SIDE EFFECTS.\n *\n * A getter, mutation and an action function is auto-generated\n * for every setting present in the `state` object.\n * They have the following format (exemplified with setting 'example'):\n *\n * Getter: `getExample` (gets the value from current state)\n * Mutation:\n *   `setExample`\n *     (takes a value\n *      and uses it to update the current state)\n * Action:\n *   `updateExample`\n *     (takes a value,\n *      saves it to the database\n *      and calls `setExample` with it)\n *\n ***\n * `sideEffectHandlers`\n * This object contains the side-effect handlers for settings that have SIDE EFFECTS.\n *\n * Each one of these settings must specify a handler,\n *   which should essentially be a callback of type\n *   `(store, value) => void` (the same as you would use for an `action`)\n *   that deals with the side effects for that setting\n *\n * NOTE: Example implementations of such handlers can be found\n * in the `sideEffectHandlers` object in case\n * the explanation isn't clear enough.\n *\n * All functions auto-generated for settings in `state`\n * (if you haven't read the `state` section, do it now),\n * are also auto-generated for settings in `sideEffectHandlers,\n * with a few key differences (exemplified with setting 'example'):\n *\n * - an additional action is auto-generated:\n *   - `triggerExampleSideEffects`\n *       (triggers the `handler` for that setting;\n *        you'll most likely never call this directly)\n *\n * - the behavior of `updateExample` changes a bit:\n *   - `updateExample`\n *       (saves value to the database,\n *        calls `triggerExampleSideEffects` and calls `setExample`)\n *\n ***\n * `customState`\n * This object contains settings that\n * don't linearly fall under the other two options.\n *\n * No auto-generation of any kind is performed\n * when a setting is added to `customState`\n *\n * You must manually add any getters, mutations and actions to\n * `customGetters`, `customMutations` and `customActions` respectively\n * that you find appropriate for that setting.\n *\n * NOTE:\n * When adding a setting to the `customState`,\n * additional consultation with the FreeTube team is preferred\n * to evaluate if it is truly necessary\n * and to ensure that the implementation works as intended.\n *\n ****\n * ENDING NOTES\n *\n * Only two more things that need mentioning.\n *\n * 1) It's perfectly fine to add extra functionality\n *    to the `customGetters`, `customMutations` and `customActions`,\n *    whether it's related to a setting or just serving as\n *    standalone functionality for the module\n *    (e.g. `grabUserSettings` (standalone action))\n *\n * 2) It's also possible to OVERRIDE auto-generated functionality by\n *    adding functions with the same identifier to\n *    the respective `custom__` object,\n *    but you must have an acceptable reason for doing so.\n ****\n */\n\n// HELPERS\nconst capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)\nconst defaultGetterId = settingId => 'get' + capitalize(settingId)\nconst defaultMutationId = settingId => 'set' + capitalize(settingId)\nconst defaultUpdaterId = settingId => 'update' + capitalize(settingId)\nconst defaultSideEffectsTriggerId = settingId =>\n  'trigger' + capitalize(settingId) + 'SideEffects'\n/*****/\n\nconst state = {\n  autoplayPlaylists: true,\n  autoplayVideos: true,\n  backendFallback: false,\n  backendPreference: !process.env.SUPPORTS_LOCAL_API ? 'invidious' : 'local',\n  barColor: false,\n  checkForBlogPosts: false,\n  checkForUpdates: true,\n  baseTheme: 'system',\n  mainColor: 'Red',\n  secColor: 'Blue',\n  defaultAutoplayInterruptionIntervalHours: 3,\n  defaultCaptionSettings: '{}',\n  defaultInterval: 5,\n  defaultPlayback: 1,\n  defaultProfile: MAIN_PROFILE_ID,\n  defaultQuality: '720',\n  defaultSkipInterval: 5,\n  defaultViewingMode: 'default',\n  defaultVideoFormat: 'dash',\n  disableSmoothScrolling: false,\n  displayVideoPlayButton: false,\n  enableSearchSuggestions: true,\n  enableSubtitlesByDefault: false,\n  enterFullscreenOnDisplayRotate: false,\n  externalLinkHandling: '',\n  externalPlayer: '',\n  externalPlayerExecutable: '',\n  externalPlayerIgnoreWarnings: false,\n  externalPlayerIgnoreDefaultArgs: false,\n  externalPlayerCustomArgs: '[]',\n  showAddedExternalPlayerCustomArgs: true,\n  expandSideBar: false,\n  hideActiveSubscriptions: false,\n  hideChannelCommunity: false,\n  hideChannelHome: false,\n  hideChannelPlaylists: false,\n  hideChannelReleases: false,\n  hideChannelPodcasts: false,\n  hideChannelCourses: false,\n  hideChannelShorts: false,\n  hideChannelSubscriptions: false,\n  hideCommentLikes: false,\n  hideCommentPhotos: false,\n  hideComments: false,\n  hideFeaturedChannels: false,\n  channelsHidden: '[]',\n  forbiddenTitles: '[]',\n  showAddedChannelsHidden: true,\n  showAddedForbiddenTitles: true,\n  hideVideoDescription: false,\n  hideLiveChat: false,\n  hideLiveStreams: false,\n  hideHeaderLogo: false,\n  hidePlaylists: false,\n  hidePopularVideos: false,\n  hideRecommendedVideos: false,\n  hideSearchBar: false,\n  hideSharingActions: false,\n  hideSubscriptionsVideos: false,\n  hideSubscriptionsShorts: false,\n  hideSubscriptionsLive: false,\n  hideSubscriptionsCommunity: false,\n  hideTrendingVideos: false,\n  hideUnsubscribeButton: false,\n  hideUpcomingPremieres: false,\n  hideVideoLikesAndDislikes: false,\n  hideVideoViews: false,\n  hideWatchedSubs: false,\n  hideUploader: false,\n  unsubscriptionPopupStatus: false,\n  hideLabelsSideBar: false,\n  hideChapters: false,\n  showDistractionFreeTitles: false,\n  landingPage: 'subscriptions',\n  listType: 'grid',\n  maxVideoPlaybackRate: 3,\n  onlyShowLatestFromChannel: false,\n  onlyShowLatestFromChannelNumber: 1,\n  openDeepLinksInNewWindow: false,\n  playNextVideo: false,\n  proxyHostname: '127.0.0.1',\n  proxyPort: '9050',\n  proxyUsername: '',\n  proxyPassword: '',\n  proxyProtocol: 'socks5',\n  proxyVideos: !process.env.SUPPORTS_LOCAL_API,\n  region: 'US',\n  rememberHistory: true,\n  rememberSearchHistory: true,\n  // 'auto', 'semi-auto', 'never'\n  watchedProgressSavingMode: 'auto',\n  saveVideoHistoryWithLastViewedPlaylist: true,\n  showFamilyFriendlyOnly: false,\n  sponsorBlockShowSkippedToast: true,\n  sponsorBlockUrl: 'https://sponsor.ajay.app',\n  sponsorBlockSponsor: {\n    color: 'Green',\n    skip: 'autoSkip'\n  },\n  sponsorBlockSelfPromo: {\n    color: 'Yellow',\n    skip: 'showInSeekBar'\n  },\n  sponsorBlockInteraction: {\n    color: 'Pink',\n    skip: 'showInSeekBar'\n  },\n  sponsorBlockIntro: {\n    color: 'Cyan',\n    skip: 'doNothing'\n  },\n  sponsorBlockOutro: {\n    color: 'Blue',\n    skip: 'doNothing'\n  },\n  sponsorBlockRecap: {\n    color: 'Indigo',\n    skip: 'doNothing'\n  },\n  sponsorBlockMusicOffTopic: {\n    color: 'Orange',\n    skip: 'doNothing'\n  },\n  sponsorBlockFiller: {\n    color: 'Purple',\n    skip: 'doNothing'\n  },\n  thumbnailPreference: '',\n  blurThumbnails: false,\n  useProxy: false,\n  userPlaylistSortOrder: 'date_added_descending',\n  useRssFeeds: false,\n  useSponsorBlock: false,\n  videoVolumeMouseScroll: false,\n  videoPlaybackRateMouseScroll: false,\n  videoSkipMouseScroll: false,\n  videoPlaybackRateInterval: 0.25,\n  enableScreenshot: false,\n  screenshotFormat: 'png',\n  screenshotQuality: 95,\n  screenshotAskPath: !process.env.IS_ELECTRON,\n  screenshotFolderPath: '',\n  screenshotFilenamePattern: '%Y%M%D-%H%N%S',\n  settingsSectionSortEnabled: false,\n  fetchSubscriptionsAutomatically: true,\n  settingsPassword: '',\n  useDeArrowTitles: false,\n  useDeArrowThumbnails: false,\n  deArrowThumbnailGeneratorUrl: 'https://dearrow-thumb.ajay.app',\n  // This makes the `favorites` playlist uses as quick bookmark target\n  // If the playlist is removed quick bookmark is disabled\n  quickBookmarkTargetPlaylistId: 'favorites',\n  generalAutoLoadMorePaginatedItemsEnabled: false,\n  hideToTrayOnMinimize: false,\n\n  // The settings below have side effects\n  currentLocale: 'system',\n  defaultInvidiousInstance: '',\n  defaultVolume: 1,\n  uiScale: 100,\n  userPlaylistsSortBy: 'latest_played_first',\n  userHistorySortBy: 'latest_played_first',\n}\n\nconst sideEffectHandlers = {\n  currentLocale: async ({ dispatch }, value) => {\n    const fallbackLocale = 'en-US'\n\n    let targetLocale = value\n    if (value === 'system') {\n      const systemLocaleName = (await getSystemLocale()).replace('_', '-') // ex: en-US\n      const systemLocaleSplit = systemLocaleName.split('-') // ex: en\n      const targetLocaleOptions = allLocales.filter((locale) => {\n        // filter out other languages\n        const localeLang = locale.split('-')[0]\n        return localeLang.includes(systemLocaleSplit[0])\n      }).sort((aLocaleName, bLocaleName) => {\n        const aLocale = aLocaleName.split('-') // ex: [en, US]\n        const bLocale = bLocaleName.split('-')\n\n        if (aLocaleName === systemLocaleName) { // country & language match, prefer a\n          return -1\n        } else if (bLocaleName === systemLocaleName) { // country & language match, prefer b\n          return 1\n        } else if (aLocale.length === 1) { // no country code for a, prefer a\n          return -1\n        } else if (bLocale.length === 1) { // no country code for b, prefer b\n          return 1\n        } else { // a & b have different country code from system, sort alphabetically\n          return aLocaleName.localeCompare(bLocaleName)\n        }\n      })\n\n      if (targetLocaleOptions.length > 0) {\n        targetLocale = targetLocaleOptions[0]\n      } else {\n        // Go back to default value if locale is unavailable\n        targetLocale = fallbackLocale\n        // Translating this string isn't necessary\n        // because the user will always see it in the default locale\n        // (in this case, English (US))\n        showToast(`Locale not found, defaulting to ${fallbackLocale}`)\n      }\n    }\n\n    const loadPromises = []\n\n    // \"es\" is used as a fallback for \"es-AR\" and \"es-MX\"\n    if (targetLocale === 'es-AR' || targetLocale === 'es-MX') {\n      loadPromises.push(\n        loadLocale('es')\n      )\n    }\n\n    // \"pt\" is used as a fallback for \"pt-PT\" and \"pt-BR\"\n    if (targetLocale === 'pt-PT' || targetLocale === 'pt-BR') {\n      loadPromises.push(\n        loadLocale('pt')\n      )\n    }\n\n    loadPromises.push(\n      loadLocale(targetLocale)\n    )\n\n    await Promise.allSettled(loadPromises)\n\n    i18n.global.locale = targetLocale\n    await dispatch('getRegionData', targetLocale)\n  },\n\n  defaultInvidiousInstance: ({ commit, rootState }, value) => {\n    if (value !== '' && rootState.invidious.currentInvidiousInstance !== value) {\n      commit('setCurrentInvidiousInstance', value)\n    }\n  },\n\n  defaultVolume: (_, value) => {\n    sessionStorage.setItem('volume', value)\n    value === 0 ? sessionStorage.setItem('muted', 'true') : sessionStorage.setItem('muted', 'false')\n    sessionStorage.setItem('defaultVolume', value)\n  },\n\n  uiScale: (_, value) => {\n    if (process.env.IS_ELECTRON) {\n      window.ftElectron.setZoomFactor(value / 100)\n    }\n  },\n\n  maxVideoPlaybackRate: ({ dispatch, state }, value) => {\n    if (state.defaultPlayback > value) {\n      dispatch('updateDefaultPlayback', value)\n    }\n  },\n\n  videoPlaybackRateInterval: ({ dispatch, state }, value) => {\n    const correctedDefaultPlaybackRate = value * Math.round(state.defaultPlayback / value)\n\n    if (state.defaultPlayback !== correctedDefaultPlaybackRate) {\n      dispatch('updateDefaultPlayback', correctedDefaultPlaybackRate)\n    }\n  },\n}\n\nconst settingsWithSideEffects = Object.keys(sideEffectHandlers)\n\nconst customState = {\n}\n\nconst customGetters = {\n}\n\nconst customMutations = {}\n\nconst customActions = {\n  grabUserSettings: async ({ commit, dispatch, state }) => {\n    try {\n      const userSettings = await DBSettingHandlers.find()\n\n      const mutationIds = Object.keys(mutations)\n\n      const alreadyTriggeredSideEffects = []\n\n      for (const { _id, value } of userSettings) {\n        if (settingsWithSideEffects.includes(_id)) {\n          dispatch(defaultSideEffectsTriggerId(_id), value)\n          alreadyTriggeredSideEffects.push(_id)\n        }\n\n        if (mutationIds.includes(defaultMutationId(_id))) {\n          commit(defaultMutationId(_id), value)\n        }\n      }\n\n      for (const _id of settingsWithSideEffects) {\n        if (!alreadyTriggeredSideEffects.includes(_id)) {\n          dispatch(defaultSideEffectsTriggerId(_id), state[_id])\n        }\n      }\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  // Should be a root action, but we'll tolerate\n  setupListenersToSyncWindows: ({ commit, dispatch }) => {\n    if (process.env.IS_ELECTRON) {\n      window.ftElectron.handleSyncSettings((event, data) => {\n        switch (event) {\n          case SyncEvents.GENERAL.UPSERT:\n            if (settingsWithSideEffects.includes(data._id)) {\n              dispatch(defaultSideEffectsTriggerId(data._id), data.value)\n            }\n\n            commit(defaultMutationId(data._id), data.value)\n            break\n\n          default:\n            console.error('settings: invalid sync event received')\n        }\n      })\n\n      window.ftElectron.handleSyncHistory((event, data) => {\n        switch (event) {\n          case SyncEvents.GENERAL.UPSERT:\n            commit('upsertToHistoryCache', data)\n            break\n\n          case SyncEvents.GENERAL.OVERWRITE: {\n            const byId = {}\n            data.forEach(video => {\n              byId[video.videoId] = video\n            })\n\n            // It comes pre-sorted, so we don't have to sort it here\n            commit('setHistoryCacheSorted', data)\n            commit('setHistoryCacheById', byId)\n            break\n          }\n\n          case SyncEvents.HISTORY.UPDATE_WATCH_PROGRESS:\n            commit('updateRecordWatchProgressInHistoryCache', data)\n            break\n\n          case SyncEvents.HISTORY.UPDATE_PLAYLIST:\n            commit('updateRecordLastViewedPlaylistIdInHistoryCache', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE:\n            commit('removeFromHistoryCacheById', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE_ALL:\n            commit('setHistoryCacheSorted', [])\n            commit('setHistoryCacheById', {})\n            break\n\n          default:\n            console.error('history: invalid sync event received')\n        }\n      })\n\n      window.ftElectron.handleSyncSearchHistory((event, data) => {\n        switch (event) {\n          case SyncEvents.GENERAL.UPSERT:\n            commit('upsertSearchHistoryEntryToList', data)\n            break\n\n          case SyncEvents.GENERAL.OVERWRITE:\n            // It comes pre-sorted, so we don't have to sort it here\n            commit('setSearchHistoryEntries', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE:\n            commit('removeSearchHistoryEntryFromList', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE_ALL:\n            commit('setSearchHistoryEntries', [])\n            break\n\n          default:\n            console.error('search history: invalid sync event received')\n        }\n      })\n\n      window.ftElectron.handleSyncProfiles((event, data) => {\n        switch (event) {\n          case SyncEvents.GENERAL.CREATE:\n            commit('addProfileToList', data)\n            break\n\n          case SyncEvents.GENERAL.UPSERT:\n            commit('upsertProfileToList', data)\n            break\n\n          case SyncEvents.PROFILES.ADD_CHANNEL:\n            commit('addChannelToProfiles', data)\n            break\n\n          case SyncEvents.PROFILES.REMOVE_CHANNEL:\n            commit('removeChannelFromProfiles', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE:\n            commit('removeProfileFromList', data)\n            break\n\n          default:\n            console.error('profiles: invalid sync event received')\n        }\n      })\n\n      window.ftElectron.handleSyncPlaylists((event, data) => {\n        switch (event) {\n          case SyncEvents.GENERAL.CREATE:\n            commit('addPlaylists', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE:\n            commit('removePlaylist', data)\n            break\n\n          case SyncEvents.GENERAL.UPSERT:\n            commit('upsertPlaylistToList', data)\n            break\n\n          case SyncEvents.PLAYLISTS.UPSERT_VIDEO:\n            commit('addVideo', data)\n            break\n\n          case SyncEvents.PLAYLISTS.UPSERT_VIDEOS:\n            commit('addVideos', data)\n            break\n\n          case SyncEvents.PLAYLISTS.DELETE_VIDEO:\n            commit('removeVideo', data)\n            break\n\n          case SyncEvents.PLAYLISTS.DELETE_VIDEOS:\n            commit('removeVideos', data)\n            break\n\n          default:\n            console.error('playlists: invalid sync event received')\n        }\n      })\n\n      window.ftElectron.handleSyncSubscriptionCache((event, data) => {\n        switch (event) {\n          case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL:\n            commit('updateVideoCacheByChannel', data)\n            break\n\n          case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL:\n            commit('updateLiveCacheByChannel', data)\n            break\n\n          case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL:\n            commit('updateShortsCacheByChannel', data)\n            break\n\n          case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL:\n            commit('updateShortsCacheWithChannelPageShorts', data)\n            break\n\n          case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL:\n            commit('updatePostsCacheByChannel', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE_MULTIPLE:\n            commit('clearCachesForManyChannels', data)\n            break\n\n          case SyncEvents.GENERAL.DELETE_ALL:\n            commit('clearCaches', data)\n            break\n\n          default:\n            console.error('subscription-cache: invalid sync event received')\n        }\n      })\n    }\n  }\n}\n\n/**********************/\n/*\n * DO NOT TOUCH ANYTHING BELOW\n * (unless you plan to change the architecture of this module)\n */\n\nconst getters = {}\nconst mutations = {}\nconst actions = {}\n\n// Build default getters, mutations and actions for every setting id\nfor (const settingId of Object.keys(state)) {\n  const getterId = defaultGetterId(settingId)\n  const mutationId = defaultMutationId(settingId)\n  const updaterId = defaultUpdaterId(settingId)\n\n  getters[getterId] = (state) => state[settingId]\n  mutations[mutationId] = (state, value) => { state[settingId] = value }\n\n  if (settingsWithSideEffects.includes(settingId)) {\n    const triggerId = defaultSideEffectsTriggerId(settingId)\n\n    // If setting has side effects, generate action to handle them\n    actions[triggerId] = sideEffectHandlers[settingId]\n\n    actions[updaterId] = async ({ commit, dispatch }, value) => {\n      try {\n        await DBSettingHandlers.upsert(settingId, value)\n\n        dispatch(triggerId, value)\n\n        commit(mutationId, value)\n      } catch (errMessage) {\n        console.error(errMessage)\n      }\n    }\n  } else {\n    actions[updaterId] = async ({ commit }, value) => {\n      try {\n        await DBSettingHandlers.upsert(settingId, value)\n\n        commit(mutationId, value)\n      } catch (errMessage) {\n        console.error(errMessage)\n      }\n    }\n  }\n}\n\n// Add all custom data/logic to their respective objects\nObject.assign(state, customState)\nObject.assign(getters, customGetters)\nObject.assign(mutations, customMutations)\nObject.assign(actions, customActions)\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/subscription-cache.js",
    "content": "import {\n  DBSubscriptionCacheHandlers,\n} from '../../../datastores/handlers/index'\n\nconst state = {\n  videoCache: {},\n  liveCache: {},\n  shortsCache: {},\n  postsCache: {},\n\n  subscriptionCacheReady: false,\n}\n\nconst getters = {\n  getSubscriptionCacheReady: (state) => state.subscriptionCacheReady,\n\n  getVideoCache: (state) => state.videoCache,\n\n  getShortsCache: (state) => state.shortsCache,\n\n  getLiveCache: (state) => state.liveCache,\n\n  getPostsCache: (state) => state.postsCache,\n}\n\nconst actions = {\n  async grabAllSubscriptions({ commit, dispatch, rootGetters }) {\n    try {\n      const payload = await DBSubscriptionCacheHandlers.find()\n\n      const videos = {}\n      const liveStreams = {}\n      const shorts = {}\n      const communityPosts = {}\n\n      const toBeRemovedChannelIds = []\n      const subscribedChannelIdSet = rootGetters.getSubscribedChannelIdSet\n\n      for (const dataEntry of payload) {\n        const channelId = dataEntry._id\n        if (!subscribedChannelIdSet.has(channelId)) {\n          // Clean up cache data for unsubscribed channels\n          toBeRemovedChannelIds.push(channelId)\n          // No need to load data for unsubscribed channels\n          continue\n        }\n\n        let hasData = false\n\n        if (Array.isArray(dataEntry.videos)) {\n          videos[channelId] = { videos: dataEntry.videos, timestamp: dataEntry.videosTimestamp }\n          hasData = true\n        }\n        if (Array.isArray(dataEntry.liveStreams)) {\n          liveStreams[channelId] = { videos: dataEntry.liveStreams, timestamp: dataEntry.liveStreamsTimestamp }\n          hasData = true\n        }\n        if (Array.isArray(dataEntry.shorts)) {\n          shorts[channelId] = { videos: dataEntry.shorts, timestamp: dataEntry.shortsTimestamp }\n          hasData = true\n        }\n        if (Array.isArray(dataEntry.communityPosts)) {\n          communityPosts[channelId] = { posts: dataEntry.communityPosts, timestamp: dataEntry.communityPostsTimestamp }\n          hasData = true\n        }\n\n        if (!hasData) { toBeRemovedChannelIds.push(channelId) }\n      }\n\n      if (toBeRemovedChannelIds.length > 0) {\n        // Delete channels with no data\n        dispatch('clearSubscriptionsCacheForManyChannels', toBeRemovedChannelIds)\n      }\n      commit('setCaches', { videos, liveStreams, shorts, communityPosts })\n      commit('setSubscriptionCacheReady', true)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSubscriptionVideosCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) {\n    try {\n      await DBSubscriptionCacheHandlers.updateVideosByChannelId(channelId, videos, timestamp)\n      commit('updateVideoCacheByChannel', { channelId, entries: videos, timestamp })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSubscriptionShortsCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) {\n    try {\n      await DBSubscriptionCacheHandlers.updateShortsByChannelId(channelId, videos, timestamp)\n      commit('updateShortsCacheByChannel', { channelId, entries: videos, timestamp })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSubscriptionShortsCacheWithChannelPageShorts({ commit }, { channelId, videos }) {\n    try {\n      await DBSubscriptionCacheHandlers.updateShortsWithChannelPageShortsByChannelId(channelId, videos)\n      commit('updateShortsCacheWithChannelPageShorts', { channelId, entries: videos })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSubscriptionLiveCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) {\n    try {\n      await DBSubscriptionCacheHandlers.updateLiveStreamsByChannelId(channelId, videos, timestamp)\n      commit('updateLiveCacheByChannel', { channelId, entries: videos, timestamp })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async updateSubscriptionPostsCacheByChannel({ commit }, { channelId, posts, timestamp = new Date() }) {\n    try {\n      await DBSubscriptionCacheHandlers.updateCommunityPostsByChannelId(channelId, posts, timestamp)\n      commit('updatePostsCacheByChannel', { channelId, entries: posts, timestamp })\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async clearSubscriptionsCacheForManyChannels({ commit }, channelIds) {\n    try {\n      await DBSubscriptionCacheHandlers.deleteMultipleChannels(channelIds)\n      commit('clearCachesForManyChannels', channelIds)\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n\n  async clearSubscriptionsCache({ commit }) {\n    try {\n      await DBSubscriptionCacheHandlers.deleteAll()\n      commit('clearCaches')\n    } catch (errMessage) {\n      console.error(errMessage)\n    }\n  },\n}\n\nconst mutations = {\n  updateVideoCacheByChannel(state, { channelId, entries, timestamp = new Date() }) {\n    const existingObject = state.videoCache[channelId]\n    const newObject = existingObject ?? { videos: null }\n    if (entries != null) { newObject.videos = entries }\n    newObject.timestamp = timestamp\n    state.videoCache[channelId] = newObject\n  },\n  updateShortsCacheByChannel(state, { channelId, entries, timestamp = new Date() }) {\n    const existingObject = state.shortsCache[channelId]\n    const newObject = existingObject ?? { videos: null }\n    if (entries != null) { newObject.videos = entries }\n    newObject.timestamp = timestamp\n    state.shortsCache[channelId] = newObject\n  },\n  updateShortsCacheWithChannelPageShorts(state, { channelId, entries }) {\n    const cachedObject = state.shortsCache[channelId]\n\n    if (cachedObject && cachedObject.videos.length > 0) {\n      cachedObject.videos.forEach(cachedVideo => {\n        const channelVideo = entries.find(short => cachedVideo.videoId === short.videoId)\n\n        if (channelVideo) {\n          // authorId probably never changes, so we don't need to update that\n\n          cachedVideo.title = channelVideo.title\n          cachedVideo.author = channelVideo.author\n\n          // as the channel shorts page only has compact view counts for numbers above 1000 e.g. 12k\n          // and the RSS feeds include an exact value, we only want to overwrite it when the number is larger than the cached value\n          // 12345 vs 12000 => 12345\n          // 12345 vs 15000 => 15000\n\n          if (channelVideo.viewCount > cachedVideo.viewCount) {\n            cachedVideo.viewCount = channelVideo.viewCount\n          }\n        }\n      })\n    }\n  },\n  updateLiveCacheByChannel(state, { channelId, entries, timestamp = new Date() }) {\n    const existingObject = state.liveCache[channelId]\n    const newObject = existingObject ?? { videos: null }\n    if (entries != null) { newObject.videos = entries }\n    newObject.timestamp = timestamp\n    state.liveCache[channelId] = newObject\n  },\n  updatePostsCacheByChannel(state, { channelId, entries, timestamp = new Date() }) {\n    const existingObject = state.postsCache[channelId]\n    const newObject = existingObject ?? { posts: null }\n    if (entries != null) { newObject.posts = entries }\n    newObject.timestamp = timestamp\n    state.postsCache[channelId] = newObject\n  },\n\n  clearCaches(state) {\n    state.videoCache = {}\n    state.shortsCache = {}\n    state.liveCache = {}\n    state.postsCache = {}\n  },\n\n  clearCachesForManyChannels(state, channelIds) {\n    channelIds.forEach((channelId) => {\n      state.videoCache[channelId] = null\n      state.liveCache[channelId] = null\n      state.shortsCache[channelId] = null\n      state.postsCache[channelId] = null\n    })\n  },\n\n  setCaches(state, { videos, liveStreams, shorts, communityPosts }) {\n    state.videoCache = videos\n    state.liveCache = liveStreams\n    state.shortsCache = shorts\n    state.postsCache = communityPosts\n  },\n\n  setSubscriptionCacheReady(state, payload) {\n    state.subscriptionCacheReady = payload\n  },\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/store/modules/utils.js",
    "content": "import i18n from '../../i18n/index'\n\nimport {\n  CHANNEL_HANDLE_REGEX,\n  createWebURL,\n  getVideoParamsFromUrl,\n  replaceFilenameForbiddenChars,\n  searchFiltersMatch,\n} from '../../helpers/utils'\n\nconst state = {\n  isSideNavOpen: false,\n  outlinesHidden: true,\n  sessionSearchHistory: [],\n  popularCache: null,\n  trendingCache: {\n    gaming: null,\n    sports: null,\n    podcasts: null\n  },\n  cachedPlaylist: null,\n  deArrowCache: {},\n  showProgressBar: false,\n  showAddToPlaylistPrompt: false,\n  showCreatePlaylistPrompt: false,\n  isKeyboardShortcutPromptShown: false,\n  showSearchFilters: false,\n  searchFilterValueChanged: false,\n  progressBarPercentage: 0,\n  toBeAddedToPlaylistVideoList: [],\n  newPlaylistDefaultProperties: {},\n  newPlaylistVideoObject: [],\n  regionNames: [],\n  regionValues: [],\n  recentBlogPosts: [],\n  searchSettings: {\n    sortBy: 'relevance',\n    time: '',\n    type: 'all',\n    duration: '',\n    features: [],\n  },\n  externalPlayerNames: [],\n  externalPlayerValues: [],\n  externalPlayerCmdArguments: {},\n  lastPopularRefreshTimestamp: '',\n  lastTrendingRefreshTimestamp: {\n    gaming: '',\n    sports: '',\n    podcasts: ''\n  },\n  subscriptionFirstAutoFetchRunData: {\n    videos: false,\n    liveStreams: false,\n    shorts: false,\n    posts: false,\n  },\n  appTitle: '',\n  openPrompts: new Set()\n}\n\nconst getters = {\n  getIsSideNavOpen(state) {\n    return state.isSideNavOpen\n  },\n\n  getOutlinesHidden(state) {\n    return state.outlinesHidden\n  },\n\n  getSessionSearchHistory(state) {\n    return state.sessionSearchHistory\n  },\n\n  getDeArrowCache: (state) => {\n    return state.deArrowCache\n  },\n\n  getPopularCache(state) {\n    return state.popularCache\n  },\n\n  getTrendingCache(state) {\n    return state.trendingCache\n  },\n\n  getCachedPlaylist(state) {\n    return state.cachedPlaylist\n  },\n\n  getSearchSettings(state) {\n    return state.searchSettings\n  },\n\n  getSearchFilterValueChanged(state) {\n    return state.searchFilterValueChanged\n  },\n\n  getIsKeyboardShortcutPromptShown(state) {\n    return state.isKeyboardShortcutPromptShown\n  },\n\n  getShowAddToPlaylistPrompt(state) {\n    return state.showAddToPlaylistPrompt\n  },\n\n  getShowCreatePlaylistPrompt(state) {\n    return state.showCreatePlaylistPrompt\n  },\n\n  getShowSearchFilters(state) {\n    return state.showSearchFilters\n  },\n\n  getToBeAddedToPlaylistVideoList(state) {\n    return state.toBeAddedToPlaylistVideoList\n  },\n\n  getNewPlaylistDefaultProperties(state) {\n    return state.newPlaylistDefaultProperties\n  },\n\n  getNewPlaylistVideoObject(state) {\n    return state.newPlaylistVideoObject\n  },\n\n  getShowProgressBar(state) {\n    return state.showProgressBar\n  },\n\n  getProgressBarPercentage(state) {\n    return state.progressBarPercentage\n  },\n\n  getRegionNames(state) {\n    return state.regionNames\n  },\n\n  getRegionValues(state) {\n    return state.regionValues\n  },\n\n  getRecentBlogPosts(state) {\n    return state.recentBlogPosts\n  },\n\n  getExternalPlayerNames(state) {\n    return state.externalPlayerNames\n  },\n\n  getExternalPlayerValues(state) {\n    return state.externalPlayerValues\n  },\n\n  getExternalPlayerCmdArguments (state) {\n    return state.externalPlayerCmdArguments\n  },\n\n  getLastTrendingRefreshTimestamp(state) {\n    return state.lastTrendingRefreshTimestamp\n  },\n\n  getLastPopularRefreshTimestamp(state) {\n    return state.lastPopularRefreshTimestamp\n  },\n\n  getSubscriptionForVideosFirstAutoFetchRun(state) {\n    return state.subscriptionFirstAutoFetchRunData.videos === true\n  },\n  getSubscriptionForLiveStreamsFirstAutoFetchRun (state) {\n    return state.subscriptionFirstAutoFetchRunData.liveStreams === true\n  },\n  getSubscriptionForShortsFirstAutoFetchRun (state) {\n    return state.subscriptionFirstAutoFetchRunData.shorts === true\n  },\n  getSubscriptionForPostsFirstAutoFetchRun (state) {\n    return state.subscriptionFirstAutoFetchRunData.posts === true\n  },\n  getAppTitle (state) {\n    return state.appTitle\n  },\n  isAnyPromptOpen(state) {\n    return state.openPrompts.size > 0\n  }\n}\n\nconst actions = {\n  showOutlines({ commit }) {\n    commit('setOutlinesHidden', false)\n  },\n\n  hideOutlines({ commit }) {\n    commit('setOutlinesHidden', true)\n  },\n\n  parseScreenshotCustomFileName: function({ rootState }, payload) {\n    const { pattern = rootState.settings.screenshotFilenamePattern, date, playerTime, videoId } = payload\n    const keywords = [\n      ['%Y', date.getFullYear()], // year 4 digits\n      ['%M', (date.getMonth() + 1).toString().padStart(2, '0')], // month 2 digits\n      ['%D', date.getDate().toString().padStart(2, '0')], // day 2 digits\n      ['%H', date.getHours().toString().padStart(2, '0')], // hour 2 digits\n      ['%N', date.getMinutes().toString().padStart(2, '0')], // minute 2 digits\n      ['%S', date.getSeconds().toString().padStart(2, '0')], // second 2 digits\n      ['%T', date.getMilliseconds().toString().padStart(3, '0')], // millisecond 3 digits\n      ['%s', parseInt(playerTime)], // video position second n digits\n      ['%t', (playerTime % 1).toString().slice(2, 5) || '000'], // video position millisecond 3 digits\n      ['%i', videoId] // video id\n    ]\n\n    let parsedString = pattern\n    for (const [key, value] of keywords) {\n      parsedString = parsedString.replaceAll(key, value)\n    }\n\n    if (parsedString !== replaceFilenameForbiddenChars(parsedString)) {\n      throw new Error(i18n.global.t('Settings.Player Settings.Screenshot.Error.Forbidden Characters'))\n    }\n\n    if (!parsedString) {\n      throw new Error(i18n.global.t('Settings.Player Settings.Screenshot.Error.Empty File Name'))\n    }\n\n    return parsedString\n  },\n\n  showAddToPlaylistPromptForManyVideos ({ commit }, { videos: videoObjectArray, newPlaylistDefaultProperties }) {\n    let videoDataValid = true\n    if (!Array.isArray(videoObjectArray)) {\n      videoDataValid = false\n    }\n    let missingKeys = []\n\n    if (videoDataValid) {\n      const requiredVideoKeys = [\n        'videoId',\n        'title',\n        'lengthSeconds',\n\n        // These two properties will be missing for shorts added to a playlist from anywhere but the watch page\n        // 'author',\n        // 'authorId',\n\n        // `timeAdded` should be generated when videos are added\n        // Not when a prompt is displayed\n        // 'timeAdded',\n\n        // `playlistItemId` should be generated anyway\n        // 'playlistItemId',\n\n        // `type` should be added in action anyway\n        // 'type',\n      ]\n      // Using `every` to loop and `return false` to break\n      videoObjectArray.every((video) => {\n        const videoPropertyKeys = Object.keys(video)\n        const missingKeysHere = requiredVideoKeys.filter(x => !videoPropertyKeys.includes(x))\n        if (missingKeysHere.length > 0) {\n          videoDataValid = false\n          missingKeys = missingKeysHere\n          return false\n        }\n        // Return true to continue loop\n        return true\n      })\n    }\n\n    if (!videoDataValid) {\n      // Print error and abort\n      const errorMsgText = 'Incorrect videos data passed when opening playlist prompt'\n      console.error(errorMsgText)\n      console.error({\n        videoObjectArray,\n        missingKeys,\n      })\n      throw new Error(errorMsgText)\n    }\n\n    commit('setShowAddToPlaylistPrompt', true)\n    commit('setToBeAddedToPlaylistVideoList', videoObjectArray)\n    if (newPlaylistDefaultProperties != null) {\n      commit('setNewPlaylistDefaultProperties', newPlaylistDefaultProperties)\n    }\n  },\n\n  hideAddToPlaylistPrompt ({ commit }) {\n    commit('setShowAddToPlaylistPrompt', false)\n    // The default value properties are only valid until prompt is closed\n    commit('resetNewPlaylistDefaultProperties')\n  },\n\n  showCreatePlaylistPrompt ({ commit }, data) {\n    commit('setShowCreatePlaylistPrompt', true)\n    commit('setNewPlaylistVideoObject', data)\n  },\n\n  showKeyboardShortcutPrompt ({ commit }) {\n    commit('setIsKeyboardShortcutPromptShown', true)\n  },\n\n  hideKeyboardShortcutPrompt ({ commit }) {\n    commit('setIsKeyboardShortcutPromptShown', false)\n  },\n\n  showSearchFilters ({ commit }) {\n    commit('setShowSearchFilters', true)\n  },\n\n  hideSearchFilters ({ commit }) {\n    commit('setShowSearchFilters', false)\n  },\n\n  updateShowProgressBar ({ commit }, value) {\n    commit('setShowProgressBar', value)\n  },\n\n  async getRegionData ({ commit }, locale) {\n    const localePathExists = process.env.GEOLOCATION_NAMES.includes(locale)\n\n    const url = createWebURL(`/static/geolocations/${localePathExists ? locale : 'en-US'}.json`)\n\n    const countries = await (await fetch(url)).json()\n\n    commit('setRegionNames', countries.names)\n    commit('setRegionValues', countries.codes)\n  },\n\n  async getYoutubeUrlInfo({ rootState, state }, urlStr) {\n    // Returns\n    // - urlType [String] `video`, `playlist`\n    //\n    // If `urlType` is \"video\"\n    // - videoId [String]\n    // - timestamp [String]\n    //\n    // If `urlType` is \"playlist\"\n    // - playlistId [String]\n    // - query [Object]\n    //\n    // If `urlType` is \"search\"\n    // - searchQuery [String]\n    // - query [Object]\n    //\n    // If `urlType` is \"hashtag\"\n    // Nothing else\n    //\n    // If `urlType` is \"channel\"\n    // - channelId [String]\n    //\n    // If `urlType` is \"unknown\"\n    // Nothing else\n    //\n    // If `urlType` is \"invalid_url\"\n    // Nothing else\n\n    if (CHANNEL_HANDLE_REGEX.test(urlStr)) {\n      urlStr = `https://www.youtube.com/${urlStr}`\n    }\n\n    const { videoId, timestamp, playlistId } = getVideoParamsFromUrl(urlStr)\n    if (videoId) {\n      return {\n        urlType: 'video',\n        videoId,\n        playlistId,\n        timestamp\n      }\n    }\n\n    let url\n    try {\n      url = new URL(urlStr)\n    } catch {\n      return {\n        urlType: 'invalid_url'\n      }\n    }\n    let urlType = 'unknown'\n\n    const channelPattern =\n      /^\\/(?:(?:channel|user|c)\\/)?(?<channelId>[^/]+)(?:\\/(?<tab>join|featured|videos|shorts|live|streams|podcasts|releases|courses|playlists|about|community|channels))?\\/?$/\n\n    const hashtagPattern = /^\\/hashtag\\/(?<tag>[^#&/?]+)$/\n\n    const postPattern = /^\\/post\\/(?<postId>.+)/\n    const feedPattern = /^\\/feed\\/(?<type>trending|subscriptions|history|playlists|you|library)/\n    const typePatterns = new Map([\n      ['playlist', /^(\\/playlist\\/?|\\/embed(\\/?videoseries)?)$/],\n      ['search', /^\\/results|search\\/?$/],\n      ['hashtag', hashtagPattern],\n      ['post', postPattern],\n      ['feed', feedPattern],\n      ['channel', channelPattern],\n    ])\n\n    for (const [type, pattern] of typePatterns) {\n      const matchFound = pattern.test(url.pathname)\n      if (matchFound) {\n        urlType = type\n        break\n      }\n    }\n\n    switch (urlType) {\n      case 'playlist': {\n        if (!url.searchParams.has('list')) {\n          throw new Error('Playlist: \"list\" field not found')\n        }\n\n        const playlistId = url.searchParams.get('list')\n        url.searchParams.delete('list')\n\n        const query = {}\n        for (const [param, value] of url.searchParams) {\n          query[param] = value\n        }\n\n        return {\n          urlType: 'playlist',\n          playlistId,\n          query\n        }\n      }\n\n      case 'search': {\n        let searchQuery = null\n        if (url.searchParams.has('search_query')) {\n          // https://www.youtube.com/results?search_query={QUERY}\n          searchQuery = url.searchParams.get('search_query')\n          url.searchParams.delete('search_query')\n        }\n        if (url.searchParams.has('q')) {\n          // https://redirect.invidious.io/search?q={QUERY}\n          searchQuery = url.searchParams.get('q')\n          url.searchParams.delete('q')\n        }\n        if (searchQuery == null) {\n          throw new Error('Search: \"search_query\" field not found')\n        }\n\n        const searchSettings = state.searchSettings\n        const query = {\n          sortBy: searchSettings.sortBy,\n          time: searchSettings.time,\n          type: searchSettings.type,\n          duration: searchSettings.duration,\n          features: searchSettings.features\n        }\n\n        for (const [param, value] of url.searchParams) {\n          query[param] = value\n        }\n\n        return {\n          urlType: 'search',\n          searchQuery,\n          query\n        }\n      }\n\n      case 'hashtag': {\n        const match = url.pathname.match(hashtagPattern)\n        const hashtag = match.groups.tag\n\n        return {\n          urlType: 'hashtag',\n          hashtag\n        }\n      }\n\n      case 'post': {\n        const match = url.pathname.match(postPattern)\n        const postId = match.groups.postId\n        const query = { authorId: url.searchParams.get('ucid') }\n        return {\n          urlType: 'post',\n          postId,\n          query\n        }\n      }\n      /*\n      Using RegExp named capture groups from ES2018\n      To avoid access to specific captured value broken\n\n      Channel URL (ID-based)\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/about\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/channels\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/community\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/featured\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/join\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/playlists\n      https://www.youtube.com/channel/UCfMJ2MchTSW2kWaT0kK94Yw/videos\n\n      Custom URL\n\n      https://www.youtube.com/c/YouTubeCreators\n      https://www.youtube.com/c/YouTubeCreators/about\n      etc.\n\n      Legacy Username URL\n\n      https://www.youtube.com/user/ufoludek\n      https://www.youtube.com/user/ufoludek/about\n      etc.\n\n      */\n      case 'channel': {\n        const match = url.pathname.match(channelPattern)\n        const channelId = match.groups.channelId\n        if (!channelId) {\n          throw new Error('Channel: could not extract id')\n        }\n\n        let subPath\n        switch (match.groups.tab) {\n          case 'shorts':\n            subPath = 'shorts'\n            break\n          case 'live':\n          case 'streams':\n            subPath = 'live'\n            break\n          case 'playlists':\n            subPath = 'playlists'\n            break\n          case 'podcasts':\n            subPath = 'podcasts'\n            break\n          case 'courses':\n            subPath = 'courses'\n            break\n          case 'releases':\n            subPath = 'releases'\n            break\n          case 'channels':\n          case 'about':\n            subPath = 'about'\n            break\n          case 'community':\n            if (url.searchParams.has('lb')) {\n              // if it has the lb search parameter then it is linking a specific community post\n              const postId = url.searchParams.get('lb')\n              const query = { authorId: channelId }\n              return {\n                urlType: 'post',\n                postId,\n                query\n              }\n            }\n            subPath = 'community'\n            break\n          case 'videos':\n            subPath = 'videos'\n            break\n          default:\n            subPath = rootState.settings.backendPreference === 'local' && !rootState.settings.hideChannelHome ? 'home' : 'videos'\n            break\n        }\n        return {\n          urlType: 'channel',\n          channelId,\n          subPath,\n          // The original URL could be from Invidious.\n          // We need to make sure it starts with youtube.com, so that YouTube's resolve endpoint can recognise it\n          url: `https://www.youtube.com${url.pathname}`\n        }\n      }\n      case 'feed': {\n        /** @type {'trending' | 'subscriptions' | 'history' | 'playlists' | 'you' | 'library'} */\n        const feedType = url.pathname.match(feedPattern).groups.type\n\n        if (feedType === 'playlists' || feedType === 'you' || feedType === 'library') {\n          return { urlType: 'userplaylists' }\n        } else if (process.env.SUPPORTS_LOCAL_API || feedType !== 'trending') {\n          return { urlType: feedType }\n        }\n        // Can fall through if a trending URL is detected in a build without the local API\n      }\n\n      default: {\n        // Unknown URL type\n        return {\n          urlType: 'unknown'\n        }\n      }\n    }\n  },\n\n  clearSessionSearchHistory ({ commit }) {\n    commit('setSessionSearchHistory', [])\n  },\n\n  async getExternalPlayerCmdArgumentsData ({ commit }) {\n    const url = createWebURL('/static/external-player-map.json')\n    const externalPlayerMap = await (await fetch(url)).json()\n    // Sort external players alphabetically & case-insensitive, keep default entry at the top\n    const playerNone = externalPlayerMap.shift()\n    externalPlayerMap.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }))\n    externalPlayerMap.unshift(playerNone)\n\n    const externalPlayerNames = externalPlayerMap.map((entry) => { return entry.name })\n    const externalPlayerValues = externalPlayerMap.map((entry) => { return entry.value })\n    const externalPlayerCmdArguments = externalPlayerMap.reduce((result, item) => {\n      result[item.value] = item.cmdArguments\n      return result\n    }, {})\n\n    commit('setExternalPlayerNames', externalPlayerNames)\n    commit('setExternalPlayerValues', externalPlayerValues)\n    commit('setExternalPlayerCmdArguments', externalPlayerCmdArguments)\n  },\n}\n\nconst mutations = {\n  toggleSideNav (state) {\n    state.isSideNavOpen = !state.isSideNavOpen\n  },\n\n  setOutlinesHidden(state, value) {\n    state.outlinesHidden = value\n  },\n\n  setShowProgressBar (state, value) {\n    state.showProgressBar = value\n  },\n\n  setProgressBarPercentage (state, value) {\n    state.progressBarPercentage = value\n  },\n\n  setSessionSearchHistory (state, history) {\n    state.sessionSearchHistory = history\n  },\n\n  setDeArrowCache (state, cache) {\n    state.deArrowCache = cache\n  },\n\n  addVideoToDeArrowCache (state, payload) {\n    const sameVideo = state.deArrowCache[payload.videoId]\n\n    if (!sameVideo) {\n      state.deArrowCache[payload.videoId] = payload\n    }\n  },\n\n  addThumbnailToDeArrowCache (state, payload) {\n    state.deArrowCache[payload.videoId] = payload\n  },\n\n  removeFromSessionSearchHistory (state, query) {\n    state.sessionSearchHistory = state.sessionSearchHistory.filter((search) => search.query !== query)\n  },\n\n  addToSessionSearchHistory (state, payload) {\n    const sameSearch = state.sessionSearchHistory.findIndex((search) => {\n      return search.query === payload.query && searchFiltersMatch(payload.searchSettings, search.searchSettings)\n    })\n\n    if (sameSearch !== -1) {\n      state.sessionSearchHistory[sameSearch].data = payload.data\n      if (payload.nextPageRef) {\n        // Local API\n        state.sessionSearchHistory[sameSearch].nextPageRef = payload.nextPageRef\n      } else if (payload.searchPage) {\n        // Invidious API\n        state.sessionSearchHistory[sameSearch].searchPage = payload.searchPage\n      }\n    } else {\n      state.sessionSearchHistory.push(payload)\n    }\n  },\n\n  setShowAddToPlaylistPrompt (state, payload) {\n    state.showAddToPlaylistPrompt = payload\n  },\n\n  setShowCreatePlaylistPrompt (state, payload) {\n    state.showCreatePlaylistPrompt = payload\n  },\n\n  setIsKeyboardShortcutPromptShown (state, payload) {\n    state.isKeyboardShortcutPromptShown = payload\n  },\n\n  setShowSearchFilters (state, payload) {\n    state.showSearchFilters = payload\n  },\n\n  setToBeAddedToPlaylistVideoList (state, payload) {\n    state.toBeAddedToPlaylistVideoList = payload\n  },\n\n  setNewPlaylistDefaultProperties (state, payload) {\n    state.newPlaylistDefaultProperties = payload\n  },\n  resetNewPlaylistDefaultProperties (state) {\n    state.newPlaylistDefaultProperties = {}\n  },\n\n  setNewPlaylistVideoObject (state, payload) {\n    state.newPlaylistVideoObject = payload\n  },\n\n  setPopularCache (state, value) {\n    state.popularCache = value\n  },\n\n  setTrendingCache (state, { value, page }) {\n    state.trendingCache[page] = value\n  },\n\n  /**\n   * @param {typeof state} state\n   * @param {{page: 'gaming' | 'sports' | 'podcasts', timestamp: Date}} param1\n   */\n  setLastTrendingRefreshTimestamp (state, { page, timestamp }) {\n    state.lastTrendingRefreshTimestamp[page] = timestamp\n  },\n\n  setLastPopularRefreshTimestamp (state, timestamp) {\n    state.lastPopularRefreshTimestamp = timestamp\n  },\n\n  /**\n   * @param {typeof state} state\n   * @param {'gaming' | 'sports' | 'podcasts'} page\n   */\n  clearTrendingCache(state, page) {\n    state.trendingCache[page] = null\n  },\n\n  setCachedPlaylist(state, value) {\n    state.cachedPlaylist = value\n  },\n\n  setSearchFilterValueChanged (state, value) {\n    state.searchFilterValueChanged = value\n  },\n\n  setSearchSortBy (state, value) {\n    state.searchSettings.sortBy = value\n  },\n\n  setSearchTime (state, value) {\n    state.searchSettings.time = value\n  },\n\n  setSearchType (state, value) {\n    state.searchSettings.type = value\n  },\n\n  setSearchDuration (state, value) {\n    state.searchSettings.duration = value\n  },\n\n  setSearchFeatures (state, value) {\n    state.searchSettings.features = value\n  },\n\n  setRegionNames (state, value) {\n    state.regionNames = value\n  },\n\n  setRegionValues (state, value) {\n    state.regionValues = value\n  },\n\n  setRecentBlogPosts (state, value) {\n    state.recentBlogPosts = value\n  },\n\n  setExternalPlayerNames (state, value) {\n    state.externalPlayerNames = value\n  },\n\n  setExternalPlayerValues (state, value) {\n    state.externalPlayerValues = value\n  },\n\n  setExternalPlayerCmdArguments (state, value) {\n    state.externalPlayerCmdArguments = value\n  },\n\n  // Use this to set the app title / document.title\n  setAppTitle (state, value) {\n    state.appTitle = value\n  },\n\n  addOpenPrompt(state, id) {\n    state.openPrompts.add(id)\n  },\n\n  removeOpenPrompt(state, id) {\n    state.openPrompts.delete(id)\n  },\n\n  setSubscriptionForVideosFirstAutoFetchRun (state) {\n    state.subscriptionFirstAutoFetchRunData.videos = true\n  },\n  setSubscriptionForLiveStreamsFirstAutoFetchRun (state) {\n    state.subscriptionFirstAutoFetchRunData.liveStreams = true\n  },\n  setSubscriptionForShortsFirstAutoFetchRun (state) {\n    state.subscriptionFirstAutoFetchRunData.shorts = true\n  },\n  setSubscriptionForPostsFirstAutoFetchRun (state) {\n    state.subscriptionFirstAutoFetchRunData.posts = true\n  }\n}\n\nexport default {\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "src/renderer/themes.css",
    "content": "body {\n  margin: 0;\n  min-block-size: 100vh;\n  color: var(--primary-text-color);\n  background-color: var(--bg-color);\n\n  /*\n    This works because CSS variables are just a find and replace and\n    are replaced before the expressions are evaluated\n  */\n  --accent-color: rgb(var(--accent-color-rgb));\n  --accent-color-opacity1: rgb(var(--accent-color-rgb) / 4%);\n  --accent-color-opacity2: rgb(var(--accent-color-rgb) / 12%);\n  --accent-color-opacity3: rgb(var(--accent-color-rgb) / 16%);\n  --accent-color-opacity4: rgb(var(--accent-color-rgb) / 24%);\n\n  /* divider */\n\n  --primary-input-color: rgb(0 0 0 / 50%);\n  --link-color: var(--accent-color);\n  --link-visited-color: var(--accent-color-visited);\n  --instance-menu-color: var(--search-bar-color);\n  --red-500: #f44336;\n  --top-bar-push-down-adjustment-default: -35px;\n\n  /* Value of 0 without 'px' does not work inside calc() */\n  /* stylelint-disable length-zero-no-unit */\n  --top-bar-push-down-adjustment-no-description: 0px;\n  --top-bar-push-down-adjustment-edit-mode: 0px;\n  --top-bar-push-down-adjustment-one-or-fewer: 0px;\n  /* stylelint-enable length-zero-no-unit */\n\n  --destructive-color: #f44336;\n  --destructive-text-color: #000;\n  --destructive-hover-color: #e53935;\n  --destructive-active-color: #c62828;\n\n  /* For the 'About' page, show the logo with the primary text color by default */\n  --logo-primary-color: var(--primary-text-color);\n  --logo-secondary-color: var(--primary-text-color);\n  --logo-tertiary-color: var(--primary-text-color);\n}\n\n/*************** RULE TWEAKS ***************/\n\n/* Default sidenav hover text color and primary input color not needed to be changed for most themes */\n/* stylelint-disable-next-line selector-no-qualifying-type */\nbody:not(.hotPink) {\n  --primary-input-color: rgb(0 0 0 / 50%);\n  --side-nav-hover-text-color: var(--primary-text-color);\n}\n\n/* Default side nav active text color and scrollbar text color hover not needed to be changed for most themes */\n/* stylelint-disable-next-line selector-no-qualifying-type */\nbody:not(.hotPink, .pastelPink) {\n  --side-nav-active-text-color: var(--primary-text-color);\n  --scrollbar-text-color-hover: var(--primary-text-color);\n}\n\n/* Themes that use the main FreeTube logo */\n.system[data-system-theme*='light'],\n.light,\n.system[data-system-theme*='dark'],\n.dark,\n.black {\n  --logo-icon: url('../../_icons/iconColorSmall.svg');\n  --logo-text: url('../../_icons/textColorSmall.svg');\n  --logo-primary-color: #f33;\n  --logo-secondary-color: #29abe1;\n  --logo-tertiary-color: #000;\n}\n\n/* Text \"app\" should be visible but retain FreeTube color logo */\n.system[data-system-theme*='dark'],\n.dark,\n.black {\n  --logo-tertiary-color: #fff;\n}\n\n/* Given that the Hot Pink theme does not need link underlining due to meeting\nWCAG 2 Level AA (https://webaim.org/resources/linkcontrastchecker/?fcolor=FFFFFF&bcolor=DE1C85&lcolor=000000),\nit can be safely elided. This looks quite pleasant on this theme. */\n.hotPink a:not(:hover, :focus),\n.hotPink .navOption:hover,\n.hotPink .navOption:focus,\n.hotPink *:not(:hover, :focus) {\n  text-decoration: none;\n}\n\n.hotPink a:hover,\n.hotPink a:focus {\n  text-decoration: underline;\n}\n\n.hotPink .shaka-range-container {\n  --primary-color: #fff;\n}\n\n\n/*************** DARK THEME ADJUSTMENTS ***************/\n\n/* stylelint-disable no-descending-specificity */\n\n/* Dark theme Youtube and Invidious logo styling (in FtShareButton) */\n.system[data-system-theme*='dark'],\n.dark,\n.dracula,\n.catppuccinMocha,\n.hotPink,\n.nordic,\n.solarizedDark,\n.gruvboxDark,\n.catppuccinFrappe,\n.everforestDarkHard,\n.everforestDarkMedium,\n.everforestDarkLow {\n  --primary-shadow-color: rgb(0 0 0 / 75%);\n\n  .invidiousLogo {\n    background-image: url('./assets/img/invidious-logo-dark.svg');\n  }\n\n  .youtubeLogo {\n    filter: brightness(0.868);\n  }\n}\n\n.black .youtubeLogo {\n  filter: brightness(0.933);\n}\n\n.black .invidiousLogo {\n  background-image: url('./assets/img/invidious-logo-dark.svg');\n}\n\n\n/*************** LIGHT THEME ADJUSTMENTS ***************/\n\n/* Light shadow color for themes where a dark shadow would not work */\n.pastelPink,\n.everforestLightHard,\n.everforestLightMedium,\n.everforestLightLow,\n.gruvboxLight,\n.solarizedLight,\n.catppuccinLatte {\n  --primary-shadow-color: rgb(255 255 255 / 75%);\n}\n\n/* Light theme Youtube and Invidious logo styling (in FtShareButton) */\n.invidiousLogo {\n  background-image: url('./assets/img/invidious-logo-light.svg');\n}\n\n.youtubeLogo {\n  filter: invert(0.87);\n}\n\n/* stylelint-enable no-descending-specificity */\n\n\n/*************** MAIN THEME DEFINITIONS ***************/\n\n/*\n  IMPLEMENTATION NOTE:\n  When adding a new base theme, add that --bg-color to src/main/index.js.\n*/\n\n.system[data-system-theme*='light'],\n.light {\n  --primary-text-color: #212121;\n  --secondary-text-color: #424242;\n  --tertiary-text-color: #757575;\n  --primary-shadow-color: rgb(200 200 200 / 75%);\n  --title-color: #3f7ac6;\n  --bg-color: #f1f1f1;\n  --favorite-icon-color: #0c0;\n  --card-bg-color: #fff;\n  --secondary-card-bg-color: #eee;\n  --scrollbar-color: #ccc;\n  --scrollbar-color-hover: #bdbdbd;\n  --side-nav-color: #fff;\n  --side-nav-hover-color: #e0e0e0;\n  --side-nav-active-color: #757575;\n  --search-bar-color: #f5f5f5;\n}\n\n.system[data-system-theme*='dark'],\n.dark {\n  --primary-text-color: #eee;\n  --secondary-text-color: #ddd;\n  --tertiary-text-color: #999;\n  --title-color: #eee;\n  --bg-color: #212121;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #303030;\n  --secondary-card-bg-color: rgb(0 0 0 / 75%);\n  --scrollbar-color: #414141;\n  --scrollbar-color-hover: #757575;\n  --side-nav-color: #262626;\n  --side-nav-hover-color: #212121;\n  --side-nav-active-color: #303030;\n  --search-bar-color: #262626;\n}\n\n.black {\n  --primary-text-color: #eee;\n  --secondary-text-color: #ddd;\n  --tertiary-text-color: #eee;\n  --title-color: #eee;\n  --bg-color: #000;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #000;\n  --secondary-card-bg-color: rgb(0 0 0 / 75%);\n  --scrollbar-color: #515151;\n  --scrollbar-color-hover: #424242;\n  --side-nav-color: #000;\n  --side-nav-hover-color: #212121;\n  --side-nav-active-color: #303030;\n  --search-bar-color: #262626;\n}\n\n.nordic {\n  --primary-text-color: #eee;\n  --secondary-text-color: #ddd;\n  --tertiary-text-color: #eee;\n  --title-color: #eee;\n  --bg-color: #2b2f3a;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #2e3440;\n  --secondary-card-bg-color: rgb(59 66 82 / 75%);\n  --scrollbar-color: #4b566a;\n  --scrollbar-color-hover: #4b566a;\n  --side-nav-color: #2e3440;\n  --side-nav-hover-color: #3b4252;\n  --side-nav-active-color: #3b4252;\n  --search-bar-color: #4b566a;\n  --logo-icon: url('../../_icons/iconNordicLightSmall.svg');\n  --logo-text: url('../../_icons/textNordicLightSmall.svg');\n}\n\n.hotPink {\n  --primary-text-color: #ffff;\n  --secondary-text-color: #ffff;\n  --tertiary-text-color: #ffff;\n  --title-color: #000;\n  --bg-color: #ff008a;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #de1c85;\n  --secondary-card-bg-color: rgb(0 0 0 / 75%);\n  --scrollbar-color: #fff;\n  --scrollbar-color-hover: #c0f6ff;\n  --scrollbar-text-color-hover: #000;\n  --side-nav-color: #ee1e90;\n  --side-nav-hover-color: #fff;\n  --side-nav-hover-text-color: #000;\n  --side-nav-active-color: #959595;\n  --side-nav-active-text-color: #000;\n  --search-bar-color: #9c2d5d;\n  --logo-icon: url('../../_icons/iconWhiteSmall.svg');\n  --logo-text: url('../../_icons/textWhiteSmall.svg');\n\n  /* The hot pink theme does not have a great color contrast with\n  many other colors than black and white. This means that the primary and\n  secondary theme colors are forced here to be black so as to avoid any\n  accessibility concerns. */\n  --primary-color: #000 !important;\n  --primary-color-hover: #000 !important;\n  --primary-color-active: #000 !important;\n  --text-with-main-color: #fff !important;\n  --text-with-accent-color: #fff !important;\n  --accent-color: #000 !important;\n  --accent-color-hover: #808080 !important;\n  --accent-color-active: #6a739a !important;\n  --accent-color-light: #000 !important;\n  --accent-color-visited: #000 !important;\n  --accent-color-opacity1: rgb(0 0 0 / 4%) !important;\n  --accent-color-opacity2: rgb(0 0 0 / 12%) !important;\n  --accent-color-opacity3: rgb(255 255 255 / 16%) !important;\n  --accent-color-opacity4: rgb(255 255 255 / 24%) !important;\n}\n\n.pastelPink {\n  --primary-text-color: #1f002b;\n  --secondary-text-color: #361836;\n  --tertiary-text-color: #5a285a;\n  --title-color: #185eb4;\n  --bg-color: #ffeadd;\n  --favorite-icon-color: #760278;\n  --card-bg-color: #ffd1dc;\n  --secondary-card-bg-color: #fff;\n  --scrollbar-color: #f5c8d3;\n  --scrollbar-color-hover: #760278;\n  --scrollbar-text-color-hover: var(--scrollbar-color);\n  --side-nav-color: #ffd1dc;\n  --side-nav-hover-color: #cef4f1;\n  --side-nav-active-color: #3124e7;\n  --side-nav-active-text-color: #ffff;\n  --search-bar-color: #fff0dd;\n  --logo-icon: url('../../_icons/iconBlackSmall.svg');\n  --logo-text: url('../../_icons/textBlackSmall.svg');\n}\n\n.catppuccinMocha {\n  --primary-text-color: #cdd6f4;\n  --secondary-text-color: #bac2de;\n  --tertiary-text-color: #a6adc8;\n  --title-color: #cdd6f4;\n  --bg-color: #1e1e2e;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #181825;\n  --secondary-card-bg-color: #1e1e2e;\n  --scrollbar-color: #313244;\n  --scrollbar-color-hover: #3d4051;\n  --side-nav-color: #181825;\n  --side-nav-hover-color: #11111b;\n  --side-nav-active-color: #11111b;\n  --search-bar-color: #313244;\n  --logo-icon: url('../../_icons/iconCatppuccinMochaLightSmall.svg');\n  --logo-text: url('../../_icons/textCatppuccinMochaLightSmall.svg');\n}\n\n.dracula {\n  --primary-text-color: #f8f8f2;\n  --secondary-text-color: #c6cee6;\n  --tertiary-text-color: #e5e8f3;\n  --title-color: #bd93f9;\n  --bg-color: #282a36;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #33353f;\n  --secondary-card-bg-color: #282a36;\n  --scrollbar-color: #44475a;\n  --scrollbar-color-hover: #3d4051;\n  --side-nav-color: #33353f;\n  --side-nav-hover-color: #57596b;\n  --side-nav-active-color: #3d4051;\n  --search-bar-color: #3e3f4a;\n  --logo-icon: url('../../_icons/iconDraculaLightSmall.svg');\n  --logo-text: url('../../_icons/textDraculaLightSmall.svg');\n}\n\n.solarizedDark {\n  --primary-text-color: #fdf6e3;\n  --secondary-text-color: #ddd6c3;\n  --tertiary-text-color: #ddd6c3;\n  --title-color: #fdf6e3;\n  --bg-color: #002b36;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #204b56;\n  --secondary-card-bg-color: #102b36;\n  --scrollbar-color: #608b96;\n  --scrollbar-color-hover: #406b76;\n  --side-nav-color: #204b56;\n  --side-nav-hover-color: #608b96;\n  --side-nav-active-color: #406b76;\n  --search-bar-color: #073642;\n  --logo-icon: url('../../_icons/iconSolarizedLightSmall.svg');\n  --logo-text: url('../../_icons/textSolarizedLightSmall.svg');\n}\n\n.solarizedLight {\n  --primary-text-color: #002b36;\n  --secondary-text-color: #204b56;\n  --tertiary-text-color: #204b56;\n  --title-color: #002b36;\n  --bg-color: #fdf6e3;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #eee8d5;\n  --secondary-card-bg-color: #fdf6e3;\n  --scrollbar-color: #a9a895;\n  --scrollbar-color-hover: #839496;\n  --side-nav-color: #eee8d5;\n  --side-nav-hover-color: #fdf6e3;\n  --side-nav-active-color: #839496;\n  --search-bar-color: #c9c8b5;\n  --logo-icon: url('../../_icons/iconSolarizedDarkSmall.svg');\n  --logo-text: url('../../_icons/textSolarizedDarkSmall.svg');\n}\n\n.gruvboxDark {\n  --primary-text-color: #ebdbb2;\n  --secondary-text-color: #d5c4a1;\n  --tertiary-text-color: #d5c4a1;\n  --title-color: #ebdbb2;\n  --bg-color: #282828;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #504945;\n  --secondary-card-bg-color: #3c3836;\n  --scrollbar-color: #665c54;\n  --scrollbar-color-hover: #282828;\n  --side-nav-color: #504945;\n  --side-nav-hover-color: #665c54;\n  --side-nav-active-color: #504945;\n  --search-bar-color: #1d2021;\n  --logo-icon: url('../../_icons/iconGruvboxLightSmall.svg');\n  --logo-text: url('../../_icons/textGruvboxLightSmall.svg');\n}\n\n.gruvboxLight {\n  --primary-text-color: #3c3836;\n  --secondary-text-color: #282828;\n  --tertiary-text-color: #282828;\n  --title-color: #3c3836;\n  --bg-color: #fbf1c7;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #ebdbb2;\n  --secondary-card-bg-color: #d5c4a1;\n  --scrollbar-color: #bdae93;\n  --scrollbar-color-hover: #fbf1c7;\n  --side-nav-color: #ebdbb2;\n  --side-nav-hover-color: #bdae93;\n  --side-nav-active-color: #ebdbb2;\n  --search-bar-color: #a89984;\n  --logo-icon: url('../../_icons/iconGruvboxDarkSmall.svg');\n  --logo-text: url('../../_icons/textGruvboxDarkSmall.svg');\n}\n\n.catppuccinFrappe {\n  --primary-text-color: #c6d0f5;\n  --secondary-text-color: #c6d0f5;\n  --tertiary-text-color: #a5adce;\n  --title-color: #c6d0f5;\n  --bg-color: #303446;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #292c3c;\n  --secondary-card-bg-color: #303446;\n  --scrollbar-color: #414559;\n  --scrollbar-color-hover: #515569;\n  --side-nav-color: #292c3c;\n  --side-nav-hover-color: #232634;\n  --side-nav-active-color: #232634;\n  --search-bar-color: #414559;\n  --logo-icon: url('../../_icons/iconCatppuccinFrappeLightSmall.svg');\n  --logo-text: url('../../_icons/textCatppuccinFrappeLightSmall.svg');\n}\n\n.everforestDarkHard {\n  --primary-text-color: #d3c6aa;\n  --secondary-text-color: #d3c6aa;\n  --tertiary-text-color: #d3c6aa;\n  --title-color: #d3c6aa;\n  --bg-color: #272e33;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #1e2326;\n  --secondary-card-bg-color: #272e33;\n  --scrollbar-color: #394146;\n  --scrollbar-color-hover: #3f4b48;\n  --side-nav-color: #1e2326;\n  --side-nav-hover-color: #0e1316;\n  --side-nav-active-color: #0e1316;\n  --search-bar-color: #2e383c;\n  --logo-icon: url('../../_icons/iconEverforestLightHardSmall.svg');\n  --logo-text: url('../../_icons/textEverforestLightHardSmall.svg');\n}\n\n.everforestDarkMedium {\n  --primary-text-color: #d3c6aa;\n  --secondary-text-color: #d3c6aa;\n  --tertiary-text-color: #d3c6aa;\n  --title-color: #d3c6aa;\n  --bg-color: #2d353b;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #232a2e;\n  --secondary-card-bg-color: #2d353b;\n  --scrollbar-color: #3f484e;\n  --scrollbar-color-hover: #46534f;\n  --side-nav-color: #232a2e;\n  --side-nav-hover-color: #131a1e;\n  --side-nav-active-color: #131a1e;\n  --search-bar-color: #343f44;\n  --logo-icon: url('../../_icons/iconEverforestLightMediumSmall.svg');\n  --logo-text: url('../../_icons/textEverforestLightMediumSmall.svg');\n}\n\n.everforestDarkLow {\n  --primary-text-color: #d3c6aa;\n  --secondary-text-color: #d3c6aa;\n  --tertiary-text-color: #d3c6aa;\n  --title-color: #d3c6aa;\n  --bg-color: #333c43;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #293136;\n  --secondary-card-bg-color: #333c43;\n  --scrollbar-color: #454f56;\n  --scrollbar-color-hover: #4d5b56;\n  --side-nav-color: #293136;\n  --side-nav-hover-color: #192126;\n  --side-nav-active-color: #192126;\n  --search-bar-color: #3a464c;\n  --logo-icon: url('../../_icons/iconEverforestLightLowSmall.svg');\n  --logo-text: url('../../_icons/textEverforestLightLowSmall.svg');\n}\n\n.everforestLightHard {\n  --primary-text-color: #3c4a52;\n  --secondary-text-color: #3c4a52;\n  --tertiary-text-color: #3c4a52;\n  --title-color: #3c4a52;\n  --bg-color: #fffbef;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #f2efdf;\n  --secondary-card-bg-color: #fffbef;\n  --scrollbar-color: #d8d5c5;\n  --scrollbar-color-hover: #aeb5a2;\n  --side-nav-color: #f2efdf;\n  --side-nav-hover-color: #e2dfcf;\n  --side-nav-active-color: #e2dfcf;\n  --search-bar-color: #f8f5e4;\n  --logo-icon: url('../../_icons/iconEverforestDarkHardSmall.svg');\n  --logo-text: url('../../_icons/textEverforestDarkHardSmall.svg');\n}\n\n.everforestLightMedium {\n  --primary-text-color: #3c4a52;\n  --secondary-text-color: #3c4a52;\n  --tertiary-text-color: #3c4a52;\n  --title-color: #3c4a52;\n  --bg-color: #fdf6e3;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #efe8d4;\n  --secondary-card-bg-color: #fdf6e3;\n  --scrollbar-color: #d0ccb7;\n  --scrollbar-color-hover: #adb39f;\n  --side-nav-color: #efe8d4;\n  --side-nav-hover-color: #dfd8c4;\n  --side-nav-active-color: #dfd8c4;\n  --search-bar-color: #f4f0d9;\n  --logo-icon: url('../../_icons/iconEverforestDarkMediumSmall.svg');\n  --logo-text: url('../../_icons/textEverforestDarkMediumSmall.svg');\n}\n\n.everforestLightLow {\n  --primary-text-color: #3c4a52;\n  --secondary-text-color: #3c4a52;\n  --tertiary-text-color: #3c4a52;\n  --title-color: #3c4a52;\n  --bg-color: #f3ead3;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #eee8ce;\n  --secondary-card-bg-color: #f3ead3;\n  --scrollbar-color: #c8c3aa;\n  --scrollbar-color-hover: #a9b09b;\n  --side-nav-color: #eee8ce;\n  --side-nav-hover-color: #d5cfb5;\n  --side-nav-active-color: #d5cfb5;\n  --search-bar-color: #eae4ca;\n  --logo-icon: url('../../_icons/iconEverforestDarkLowSmall.svg');\n  --logo-text: url('../../_icons/textEverforestDarkLowSmall.svg');\n}\n\n.catppuccinLatte {\n  --primary-text-color: #4c4f69;\n  --secondary-text-color: #4c4f69;\n  --tertiary-text-color: #6c6f85;\n  --title-color: #4c4f69;\n  --bg-color: #eff1f5;\n  --favorite-icon-color: #0f0;\n  --card-bg-color: #e6e9ef;\n  --secondary-card-bg-color: #eff1f5;\n  --scrollbar-color: #ccd0da;\n  --scrollbar-color-hover: #bdbdbd;\n  --side-nav-color: #e6e9ef;\n  --side-nav-hover-color: #dce0e8;\n  --side-nav-active-color: #dce0e8;\n  --search-bar-color: #ccd0da;\n  --logo-icon: url('../../_icons/iconCatppuccinLatteDarkSmall.svg');\n  --logo-text: url('../../_icons/textCatppuccinLatteDarkSmall.svg');\n}\n\n/*************** PRIMARY THEME COLOR DEFINTIONS ***************/\n\n.mainRed,\n.mainPink,\n.mainPurple,\n.mainDeepPurple,\n.mainIndigo,\n.mainBlue,\n.mainLightBlue,\n.mainCyan,\n.mainTeal,\n.mainGreen {\n  --text-with-main-color: #fff;\n  --logo-icon-bar-color: url('../../_icons/iconWhiteSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textWhiteSmall.svg');\n}\n\n/* light primary theme colors */\n.mainLightGreen,\n.mainLime,\n.mainYellow,\n.mainAmber,\n.mainOrange,\n.mainDeepOrange {\n  --text-with-main-color: #000;\n  --logo-icon-bar-color: url('../../_icons/iconBlackSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textBlackSmall.svg');\n}\n\n.mainRed {\n  --primary-color: #f44336;\n  --primary-color-hover: #e53935;\n  --primary-color-active: #c62828;\n}\n\n.mainPink {\n  --primary-color: #e91e63;\n  --primary-color-hover: #d81b60;\n  --primary-color-active: #ad1457;\n}\n\n.mainPurple {\n  --primary-color: #9c27b0;\n  --primary-color-hover: #8e24aa;\n  --primary-color-active: #6a1b9a;\n}\n\n.mainDeepPurple {\n  --primary-color: #673ab7;\n  --primary-color-hover: #5e35b1;\n  --primary-color-active: #4527a0;\n}\n\n.mainIndigo {\n  --primary-color: #3f51b5;\n  --primary-color-hover: #3949ab;\n  --primary-color-active: #283593;\n}\n\n.mainBlue {\n  --primary-color: #2196f3;\n  --primary-color-hover: #1e88e5;\n  --primary-color-active: #1565c0;\n}\n\n.mainLightBlue {\n  --primary-color: #03a9f4;\n  --primary-color-hover: #039be5;\n  --primary-color-active: #0277bd;\n}\n\n.mainCyan {\n  --primary-color: #00bcd4;\n  --primary-color-hover: #00acc1;\n  --primary-color-active: #00838f;\n}\n\n.mainTeal {\n  --primary-color: #009688;\n  --primary-color-hover: #00897b;\n  --primary-color-active: #00695c;\n}\n\n.mainGreen {\n  --primary-color: #4caf50;\n  --primary-color-hover: #43a047;\n  --primary-color-active: #2e7d32;\n}\n\n.mainLightGreen {\n  --primary-color: #8bc34a;\n  --primary-color-hover: #7cb342;\n  --primary-color-active: #558b2f;\n}\n\n.mainLime {\n  --primary-color: #cddc39;\n  --primary-color-hover: #c0ca33;\n  --primary-color-active: #9e9d24;\n}\n\n.mainYellow {\n  --primary-color: #ffeb3b;\n  --primary-color-hover: #fdd835;\n  --primary-color-active: #f9a825;\n}\n\n.mainAmber {\n  --primary-color: #ffc107;\n  --primary-color-hover: #ffb300;\n  --primary-color-active: #ff8f00;\n}\n\n.mainOrange {\n  --primary-color: #ff9800;\n  --primary-color-hover: #fb8c00;\n  --primary-color-active: #ef6c00;\n}\n\n.mainDeepOrange {\n  --primary-color: #ff5722;\n  --primary-color-hover: #f4511e;\n  --primary-color-active: #d84315;\n}\n\n\n/* PRIMARY THEME COLORS CORRESPONDING TO BASE THEMES */\n\n.mainCatppuccinMochaRosewater,\n.mainCatppuccinMochaFlamingo,\n.mainCatppuccinMochaPink,\n.mainCatppuccinMochaMauve,\n.mainCatppuccinMochaRed,\n.mainCatppuccinMochaMaroon,\n.mainCatppuccinMochaPeach,\n.mainCatppuccinMochaYellow,\n.mainCatppuccinMochaGreen,\n.mainCatppuccinMochaTeal,\n.mainCatppuccinMochaSky,\n.mainCatppuccinMochaSapphire,\n.mainCatppuccinMochaBlue,\n.mainCatppuccinMochaLavender {\n  --text-with-main-color: #1e1e2e;\n  --logo-icon-bar-color: url('../../_icons/iconCatppuccinMochaDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textCatppuccinMochaDarkSmall.svg');\n}\n\n.mainCatppuccinMochaRosewater {\n  --primary-color: #f5e0dc;\n  --primary-color-hover: #fceeec;\n  --primary-color-active: #e1c8c3;\n}\n\n.mainCatppuccinMochaFlamingo {\n  --primary-color: #f2cdcd;\n  --primary-color-hover: #f2e1e1;\n  --primary-color-active: #ddb7b7;\n}\n\n.mainCatppuccinMochaPink {\n  --primary-color: #f5c2e7;\n  --primary-color-hover: #f3d2ea;\n  --primary-color-active: #dca3cd;\n}\n\n.mainCatppuccinMochaMauve {\n  --primary-color: #cba6f7;\n  --primary-color-hover: #d4b7f8;\n  --primary-color-active: #b38fdf;\n}\n\n.mainCatppuccinMochaRed {\n  --primary-color: #f38ba8;\n  --primary-color-hover: #f0a4b9;\n  --primary-color-active: #de7693;\n}\n\n.mainCatppuccinMochaMaroon {\n  --primary-color: #eba0ac;\n  --primary-color-hover: #eabbc3;\n  --primary-color-active: #d68895;\n}\n\n.mainCatppuccinMochaPeach {\n  --primary-color: #fab387;\n  --primary-color-hover: #f7c7a9;\n  --primary-color-active: #e1996d;\n}\n\n.mainCatppuccinMochaYellow {\n  --primary-color: #f9e2af;\n  --primary-color-hover: #feeecd;\n  --primary-color-active: #dec48d;\n}\n\n.mainCatppuccinMochaGreen {\n  --primary-color: #a6e3a1;\n  --primary-color-hover: #bfebbb;\n  --primary-color-active: #86c780;\n}\n\n.mainCatppuccinMochaTeal {\n  --primary-color: #94e2d5;\n  --primary-color-hover: #aceae0;\n  --primary-color-active: #6fc5b7;\n}\n\n.mainCatppuccinMochaSky {\n  --primary-color: #89dceb;\n  --primary-color-hover: #a3e4f0;\n  --primary-color-active: #68bcca;\n}\n\n.mainCatppuccinMochaSapphire {\n  --primary-color: #74c7ec;\n  --primary-color-hover: #93d1ed;\n  --primary-color-active: #59a9cf;\n}\n\n.mainCatppuccinMochaBlue {\n  --primary-color: #89b4fa;\n  --primary-color-hover: #a6c8ff;\n  --primary-color-active: #6593df;\n}\n\n.mainCatppuccinMochaLavender {\n  --primary-color: #b4befe;\n  --primary-color-hover: #c9d0ff;\n  --primary-color-active: #8d98e4;\n}\n\n.mainDraculaCyan,\n.mainDraculaGreen,\n.mainDraculaOrange,\n.mainDraculaRed,\n.mainDraculaYellow {\n  --text-with-main-color: #282a36;\n  --logo-icon-bar-color: url('../../_icons/iconDraculaDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textDraculaDarkSmall.svg');\n}\n\n.mainDraculaPink,\n.mainDraculaPurple {\n  --text-with-main-color: #f8f8f2;\n  --logo-icon-bar-color: url('../../_icons/iconDraculaLightSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textDraculaLightSmall.svg');\n}\n\n.mainDraculaCyan {\n  --primary-color: #8be9fd;\n  --primary-color-hover: #97ebfd;\n  --primary-color-active: #7dd2e4;\n}\n\n.mainDraculaGreen {\n  --primary-color: #50fa7b;\n  --primary-color-hover: #62fb88;\n  --primary-color-active: #48e16f;\n}\n\n.mainDraculaOrange {\n  --primary-color: #ffb86c;\n  --primary-color-hover: #ffbf7b;\n  --primary-color-active: #e6a661;\n}\n\n.mainDraculaPink {\n  --primary-color: #ff79c6;\n  --primary-color-hover: #ff86cc;\n  --primary-color-active: #e66db2;\n}\n\n.mainDraculaPurple {\n  --primary-color: #bd93f9;\n  --primary-color-hover: #c49efa;\n  --primary-color-active: #aa84e0;\n}\n\n.mainDraculaRed {\n  --primary-color: #f55;\n  --primary-color-hover: #f66;\n  --primary-color-active: #e64d4d;\n}\n\n.mainDraculaYellow {\n  --primary-color: #f1fa8c;\n  --primary-color-hover: #f2fb98;\n  --primary-color-active: #d9e17e;\n}\n\n.mainSolarizedYellow,\n.mainSolarizedOrange,\n.mainSolarizedRed,\n.mainSolarizedMagenta,\n.mainSolarizedViolet,\n.mainSolarizedGreen {\n  --text-with-main-color: #fdf6e3;\n  --logo-icon-bar-color: url('../../_icons/iconDraculaLightSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textDraculaLightSmall.svg');\n}\n\n.mainSolarizedBlue,\n.mainSolarizedCyan {\n  --text-with-main-color: #000;\n  --logo-icon-bar-color: url('../../_icons/iconDraculaDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textDraculaDarkSmall.svg');\n}\n\n.mainSolarizedYellow {\n  --primary-color: #b58900;\n  --primary-color-hover: #d5a920;\n  --primary-color-active: #f5c940;\n}\n\n.mainSolarizedOrange {\n  --primary-color: #cb4b16;\n  --primary-color-hover: #eb6b36;\n  --primary-color-active: #fc8b56;\n}\n\n.mainSolarizedRed {\n  --primary-color: #dc322f;\n  --primary-color-hover: #fc524f;\n  --primary-color-active: #fe726f;\n}\n\n.mainSolarizedMagenta {\n  --primary-color: #d33682;\n  --primary-color-hover: #f356a2;\n  --primary-color-active: #f558c2;\n}\n\n.mainSolarizedViolet {\n  --primary-color: #6c71c4;\n  --primary-color-hover: #8c91e4;\n  --primary-color-active: #acb1f4;\n}\n\n.mainSolarizedBlue {\n  --primary-color: #268bd2;\n  --primary-color-hover: #46abf2;\n  --primary-color-active: #66cbf4;\n}\n\n.mainSolarizedCyan {\n  --primary-color: #2aa198;\n  --primary-color-hover: #4ac1b8;\n  --primary-color-active: #6ae1d8;\n}\n\n.mainSolarizedGreen {\n  --primary-color: #859900;\n  --primary-color-hover: #a5b920;\n  --primary-color-active: #c5d940;\n}\n\n.mainGruvboxDarkGreen {\n  --primary-color: #b8bb26;\n  --primary-color-hover: #d8db46;\n  --primary-color-active: #f8fb66;\n}\n\n.mainGruvboxDarkYellow {\n  --primary-color: #fabd2f;\n  --primary-color-hover: #fcd54f;\n  --primary-color-active: #fed76f;\n}\n\n.mainGruvboxDarkBlue {\n  --primary-color: #83a598;\n  --primary-color-hover: #a3c5b8;\n  --primary-color-active: #c3e2d8;\n}\n\n.mainGruvboxDarkPurple {\n  --primary-color: #d3869b;\n  --primary-color-hover: #f3a6b8;\n  --primary-color-active: #f3a6b8;\n}\n\n.mainGruvboxDarkAqua {\n  --primary-color: #8ec07c;\n  --primary-color-hover: #aec29c;\n  --primary-color-active: #cec59c;\n}\n\n.mainGruvboxDarkOrange {\n  --primary-color: #fe8019;\n  --primary-color-hover: #fe9a39;\n  --primary-color-active: #feb259;\n}\n\n.mainGruvboxLightRed {\n  --primary-color: #9d0006;\n  --primary-color-hover: #bd2026;\n  --primary-color-active: #dd4046;\n}\n\n.mainGruvboxLightBlue {\n  --primary-color: #076678;\n  --primary-color-hover: #276898;\n  --primary-color-active: #476ab8;\n}\n\n.mainGruvboxLightPurple {\n  --primary-color: #8f3f71;\n  --primary-color-hover: #af5f91;\n  --primary-color-active: #cf7fb1;\n}\n\n.mainGruvboxLightOrange {\n  --primary-color: #af3a03;\n  --primary-color-hover: #cf5a23;\n  --primary-color-active: #ef7a43;\n}\n\n.mainGruvboxLightOrange,\n.mainGruvboxLightRed,\n.mainGruvboxLightBlue,\n.mainGruvboxLightPurple {\n  --text-with-main-color: #fbf1c7;\n  --logo-icon-bar-color: url('../../_icons/iconGruvboxLightSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textGruvboxLightSmall.svg');\n}\n\n\n.mainGruvboxDarkGreen,\n.mainGruvboxDarkYellow,\n.mainGruvboxDarkAqua,\n.mainGruvboxDarkOrange {\n  --text-with-main-color: #3c3836;\n  --logo-icon-bar-color: url('../../_icons/iconGruvboxDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textGruvboxDarkSmall.svg');\n}\n\n.mainGruvboxDarkBlue,\n.mainGruvboxDarkPurple {\n  --text-with-main-color: #1d2021;\n  --logo-icon-bar-color: url('../../_icons/iconGruvboxDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textGruvboxDarkSmall.svg');\n}\n\n.mainCatppuccinFrappeRosewater,\n.mainCatppuccinFrappeFlamingo,\n.mainCatppuccinFrappePink,\n.mainCatppuccinFrappeMauve,\n.mainCatppuccinFrappeRed,\n.mainCatppuccinFrappeMaroon,\n.mainCatppuccinFrappePeach,\n.mainCatppuccinFrappeYellow,\n.mainCatppuccinFrappeGreen,\n.mainCatppuccinFrappeTeal,\n.mainCatppuccinFrappeSky,\n.mainCatppuccinFrappeSapphire,\n.mainCatppuccinFrappeBlue,\n.mainCatppuccinFrappeLavender {\n  --text-with-main-color: #24273a;\n  --logo-icon-bar-color: url('../../_icons/iconCatppuccinFrappeDarkSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textCatppuccinFrappeDarkSmall.svg');\n}\n\n.mainCatppuccinFrappeRosewater {\n  --primary-color: #f2d5cf;\n  --primary-color-hover: #f2e7e3;\n  --primary-color-active: #e0bfb9;\n}\n\n.mainCatppuccinFrappeFlamingo {\n  --primary-color: #eebebe;\n  --primary-color-hover: #f0d0d0;\n  --primary-color-active: #d8a0a0;\n}\n\n.mainCatppuccinFrappePink {\n  --primary-color: #f4b8e4;\n  --primary-color-hover: #f3c8e7;\n  --primary-color-active: #e19abf;\n}\n\n.mainCatppuccinFrappeMauve {\n  --primary-color: #ca9ee6;\n  --primary-color-hover: #d4b0e7;\n  --primary-color-active: #b37ac9;\n}\n\n.mainCatppuccinFrappeRed {\n  --primary-color: #e78284;\n  --primary-color-hover: #e99a9c;\n  --primary-color-active: #d46b6d;\n}\n\n.mainCatppuccinFrappeMaroon {\n  --primary-color: #ea999c;\n  --primary-color-hover: #eab4b8;\n  --primary-color-active: #d87c80;\n}\n\n.mainCatppuccinFrappePeach {\n  --primary-color: #ef9f76;\n  --primary-color-hover: #f7c0a0;\n  --primary-color-active: #e18b5e;\n}\n\n.mainCatppuccinFrappeYellow {\n  --primary-color: #e5c890;\n  --primary-color-hover: #f0e9c0;\n  --primary-color-active: #d8b790;\n}\n\n.mainCatppuccinFrappeGreen {\n  --primary-color: #a6d189;\n  --primary-color-hover: #bfe9b1;\n  --primary-color-active: #86c77b;\n}\n\n.mainCatppuccinFrappeTeal {\n  --primary-color: #81c8be;\n  --primary-color-hover: #a3d4cc;\n  --primary-color-active: #6fa9a0;\n}\n\n.mainCatppuccinFrappeSky {\n  --primary-color: #99d1db;\n  --primary-color-hover: #b3dce4;\n  --primary-color-active: #6fa9a0;\n}\n\n.mainCatppuccinFrappeSapphire {\n  --primary-color: #85c1dc;\n  --primary-color-hover: #a3d0e4;\n  --primary-color-active: #5a9ec6;\n}\n\n.mainCatppuccinFrappeBlue {\n  --primary-color: #8caaee;\n  --primary-color-hover: #9eb7f0;\n  --primary-color-active: #6c8dbf;\n}\n\n.mainCatppuccinFrappeLavender {\n  --primary-color: #babbf1;\n  --primary-color-hover: #c9c9f3;\n  --primary-color-active: #8a8abf;\n}\n\n.mainEverforestDarkRed,\n.mainEverforestDarkOrange,\n.mainEverforestDarkYellow,\n.mainEverforestDarkGreen,\n.mainEverforestDarkAqua,\n.mainEverforestDarkBlue,\n.mainEverforestDarkPurple,\n.mainEverforestLightRed,\n.mainEverforestLightOrange,\n.mainEverforestLightYellow,\n.mainEverforestLightGreen,\n.mainEverforestLightAqua,\n.mainEverforestLightBlue,\n.mainEverforestLightPurple {\n  --text-with-main-color: #1e2326;\n  --logo-icon-bar-color: url('../../_icons/iconEverforestDarkHardSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textEverforestDarkHardSmall.svg');\n}\n\n.mainEverforestDarkRed {\n  --primary-color: #e67e80;\n  --primary-color-hover: #e89e9f;\n  --primary-color-active: #d65f61;\n}\n\n.mainEverforestDarkOrange {\n  --primary-color: #e69875;\n  --primary-color-hover: #e8b095;\n  --primary-color-active: #b96e4f;\n}\n\n.mainEverforestDarkYellow {\n  --primary-color: #dbbc7f;\n  --primary-color-hover: #ddcc9f;\n  --primary-color-active: #bbae5f;\n}\n\n.mainEverforestDarkGreen {\n  --primary-color: #a7c080;\n  --primary-color-hover: #b9d09f;\n  --primary-color-active: #8b9e5f;\n}\n\n.mainEverforestDarkAqua {\n  --primary-color: #83c092;\n  --primary-color-hover: #95d0b0;\n  --primary-color-active: #6da07f;\n}\n\n.mainEverforestDarkBlue {\n  --primary-color: #7fbbb3;\n  --primary-color-hover: #91cbc3;\n  --primary-color-active: #5f9b93;\n}\n\n.mainEverforestDarkPurple {\n  --primary-color: #d699b6;\n  --primary-color-hover: #e6b9d6;\n  --primary-color-active: #b67a96;\n}\n\n.mainEverforestLightRed {\n  --primary-color: #d83532;\n  --primary-color-hover: #e84e3f;\n  --primary-color-active: #b83232;\n}\n\n.mainEverforestLightOrange {\n  --primary-color: #d55d0f;\n  --primary-color-hover: #e66f10;\n  --primary-color-active: #b64f00;\n}\n\n.mainEverforestLightYellow {\n  --primary-color: #a96e00;\n  --primary-color-hover: #c88b00;\n  --primary-color-active: #8b6e00;\n}\n\n.mainEverforestLightGreen {\n  --primary-color: #6d8100;\n  --primary-color-hover: #8da101;\n  --primary-color-active: #4f5f00;\n}\n\n.mainEverforestLightAqua {\n  --primary-color: #25976c;\n  --primary-color-hover: #46b38a;\n  --primary-color-active: #0d7e51;\n}\n\n.mainEverforestLightBlue {\n  --primary-color: #2a84b5;\n  --primary-color-hover: #4aa2d3;\n  --primary-color-active: #0a7ea5;\n}\n\n.mainEverforestLightPurple {\n  --primary-color: #cf59aa;\n  --primary-color-hover: #e77dc9;\n  --primary-color-active: #a63f9a;\n}\n\n.mainCatppuccinLatteMauve,\n.mainCatppuccinLatteRed {\n  --text-with-main-color: #fff;\n  --logo-icon-bar-color: url('../../_icons/iconCatppuccinLatteLightSmall.svg');\n  --logo-text-bar-color: url('../../_icons/textCatppuccinLatteLightSmall.svg');\n}\n\n.mainCatppuccinLatteMauve {\n  --primary-color: #8839ef;\n  --primary-color-hover: #9f5cf1;\n  --primary-color-active: #6c28ce;\n}\n\n.mainCatppuccinLatteRed {\n  --primary-color: #d20f39;\n  --primary-color-hover: #dd385c;\n  --primary-color-active: #a60c2d;\n}\n\n/*************** SECONDARY THEME COLOR DEFINTIONS ***************/\n\n/* dark secondary theme colors */\n.secRed,\n.secPink,\n.secPurple,\n.secDeepPurple,\n.secIndigo,\n.secBlue,\n.secLightBlue,\n.secCyan,\n.secTeal,\n.secGreen {\n  --text-with-accent-color: #fff;\n}\n\n/* light secondary theme colors */\n.secLightGreen,\n.secLime,\n.secYellow,\n.secAmber,\n.secOrange,\n.secDeepOrange {\n  --text-with-accent-color: #000;\n}\n\n.secRed {\n  --accent-color-rgb: 244 67 54;\n  --accent-color-hover: #e53935;\n  --accent-color-active: #c62828;\n  --accent-color-light: #ef9a9a;\n  --accent-color-visited: #b71c1c;\n}\n\n.secPink {\n  --accent-color-rgb: 233 30 99;\n  --accent-color-hover: #d81b60;\n  --accent-color-active: #ad1457;\n  --accent-color-light: #f48fb1;\n  --accent-color-visited: #880e4f;\n}\n\n.secPurple {\n  --accent-color-rgb: 156 39 176;\n  --accent-color-hover: #8e24aa;\n  --accent-color-active: #6a1b9a;\n  --accent-color-light: #ce93d8;\n  --accent-color-visited: #4a148c;\n}\n\n.secDeepPurple {\n  --accent-color-rgb: 103 58 183;\n  --accent-color-hover: #5e35b1;\n  --accent-color-active: #4527a0;\n  --accent-color-light: #b39ddb;\n  --accent-color-visited: #311b92;\n}\n\n.secIndigo {\n  --accent-color-rgb: 63 81 181;\n  --accent-color-hover: #3949ab;\n  --accent-color-active: #283593;\n  --accent-color-light: #9fa8da;\n  --accent-color-visited: #1a237e;\n}\n\n.secBlue {\n  --accent-color-rgb: 33 150 243;\n  --accent-color-hover: #1e88e5;\n  --accent-color-active: #1565c0;\n  --accent-color-light: #90caf9;\n  --accent-color-visited: #0d47a1;\n}\n\n.secLightBlue {\n  --accent-color-rgb: 3 169 244;\n  --accent-color-hover: #039be5;\n  --accent-color-active: #0277bd;\n  --accent-color-light: #81d4fa;\n  --accent-color-visited: #01579b;\n}\n\n.secCyan {\n  --accent-color-rgb: 0 188 212;\n  --accent-color-hover: #00acc1;\n  --accent-color-active: #00838f;\n  --accent-color-light: #80deea;\n  --accent-color-visited: #006064;\n}\n\n.secTeal {\n  --accent-color-rgb: 0 150 136;\n  --accent-color-hover: #00897b;\n  --accent-color-active: #00695c;\n  --accent-color-light: #80cbc4;\n  --accent-color-visited: #004d40;\n}\n\n.secGreen {\n  --accent-color-rgb: 76 175 80;\n  --accent-color-hover: #43a047;\n  --accent-color-active: #2e7d32;\n  --accent-color-light: #a5d6a7;\n  --accent-color-visited: #1b5e20;\n}\n\n.secLightGreen {\n  --accent-color-rgb: 139 195 74;\n  --accent-color-hover: #7cb342;\n  --accent-color-active: #558b2f;\n  --accent-color-light: #c5e1a5;\n  --accent-color-visited: #33691e;\n}\n\n.secLime {\n  --accent-color-rgb: 205 220 57;\n  --accent-color-hover: #c0ca33;\n  --accent-color-active: #9e9d24;\n  --accent-color-light: #e6ee9c;\n  --accent-color-visited: #827717;\n}\n\n.secYellow {\n  --accent-color-rgb: 255 235 59;\n  --accent-color-hover: #fdd835;\n  --accent-color-active: #f9a825;\n  --accent-color-light: #fff59d;\n  --accent-color-visited: #f57f17;\n}\n\n.secAmber {\n  --accent-color-rgb: 255 193 7;\n  --accent-color-hover: #ffb300;\n  --accent-color-active: #ff8f00;\n  --accent-color-light: #ffe082;\n  --accent-color-visited: #ff6f00;\n}\n\n.secOrange {\n  --accent-color-rgb: 255 152 0;\n  --accent-color-hover: #fb8c00;\n  --accent-color-active: #ef6c00;\n  --accent-color-light: #ffcc80;\n  --accent-color-visited: #e65100;\n}\n\n.secDeepOrange {\n  --accent-color-rgb: 255 87 34;\n  --accent-color-hover: #f4511e;\n  --accent-color-active: #d84315;\n  --accent-color-light: #ffab91;\n  --accent-color-visited: #bf360c;\n}\n\n\n/* SECONDARY THEME COLORS CORRESPONDING TO BASE THEMES */\n\n.secCatppuccinMochaRosewater,\n.secCatppuccinMochaFlamingo,\n.secCatppuccinMochaPink,\n.secCatppuccinMochaMauve,\n.secCatppuccinMochaRed,\n.secCatppuccinMochaMaroon,\n.secCatppuccinMochaPeach,\n.secCatppuccinMochaYellow,\n.secCatppuccinMochaGreen,\n.secCatppuccinMochaTeal,\n.secCatppuccinMochaSky,\n.secCatppuccinMochaSapphire,\n.secCatppuccinMochaBlue,\n.secCatppuccinMochaLavender {\n  --text-with-accent-color: #1e1e2e;\n}\n\n.secCatppuccinMochaRosewater {\n  --accent-color-rgb: 245 224 220;\n  --accent-color-hover: #fceeec;\n  --accent-color-active: #e1c8c3;\n  --accent-color-light: #f8eae7;\n  --accent-color-visited: #d3a197;\n}\n\n.secCatppuccinMochaFlamingo {\n  --accent-color-rgb: 242 205 205;\n  --accent-color-hover: #f3d7d7;\n  --accent-color-active: #ddb7b7;\n  --accent-color-light: #f7dfdf;\n  --accent-color-visited: #cf9898;\n}\n\n.secCatppuccinMochaPink {\n  --accent-color-rgb: 245 194 231;\n  --accent-color-hover: #f3cee9;\n  --accent-color-active: #dca3cd;\n  --accent-color-light: #f4dbed;\n  --accent-color-visited: #d28fc0;\n}\n\n.secCatppuccinMochaMauve {\n  --accent-color-rgb: 203 166 247;\n  --accent-color-hover: #d4b7f8;\n  --accent-color-active: #b38fdf;\n  --accent-color-light: #d6b9f9;\n  --accent-color-visited: #a171da;\n}\n\n.secCatppuccinMochaRed {\n  --accent-color-rgb: 243 139 168;\n  --accent-color-hover: #f399b2;\n  --accent-color-active: #de7693;\n  --accent-color-light: #f5a3ba;\n  --accent-color-visited: #d56c89;\n}\n\n.secCatppuccinMochaMaroon {\n  --accent-color-rgb: 235 160 172;\n  --accent-color-hover: #ebb4bd;\n  --accent-color-active: #d68895;\n  --accent-color-light: #f0b7c0;\n  --accent-color-visited: #c86a79;\n}\n\n.secCatppuccinMochaPeach {\n  --accent-color-rgb: 250 179 135;\n  --accent-color-hover: #f7bd99;\n  --accent-color-active: #e1996d;\n  --accent-color-light: #fbc4a2;\n  --accent-color-visited: #d78a5b;\n}\n\n.secCatppuccinMochaYellow {\n  --accent-color-rgb: 249 226 175;\n  --accent-color-hover: #f9e7bf;\n  --accent-color-active: #dec48d;\n  --accent-color-light: #fbeccb;\n  --accent-color-visited: #d5b05d;\n}\n\n.secCatppuccinMochaGreen {\n  --accent-color-rgb: 166 227 161;\n  --accent-color-hover: #b6e3b2;\n  --accent-color-active: #86c780;\n  --accent-color-light: #bceab8;\n  --accent-color-visited: #6ed166;\n}\n\n.secCatppuccinMochaTeal {\n  --accent-color-rgb: 148 226 213;\n  --accent-color-hover: #a1dfd5;\n  --accent-color-active: #6fc5b7;\n  --accent-color-light: #afe9df;\n  --accent-color-visited: #5cccb9;\n}\n\n.secCatppuccinMochaSky {\n  --accent-color-rgb: 137 220 235;\n  --accent-color-hover: #99dfeb;\n  --accent-color-active: #68bcca;\n  --accent-color-light: #9fe3ef;\n  --accent-color-visited: #64c2d3;\n}\n\n.secCatppuccinMochaSapphire {\n  --accent-color-rgb: 116 199 236;\n  --accent-color-hover: #84c7e6;\n  --accent-color-active: #59a9cf;\n  --accent-color-light: #93d4f0;\n  --accent-color-visited: #6ab6d7;\n}\n\n.secCatppuccinMochaBlue {\n  --accent-color-rgb: 137 220 235;\n  --accent-color-hover: #9bbef6;\n  --accent-color-active: #6593df;\n  --accent-color-light: #a7c7fb;\n  --accent-color-visited: #739cdd;\n}\n\n.secCatppuccinMochaLavender {\n  --accent-color-rgb: 180 190 254;\n  --accent-color-hover: #c9d0ff;\n  --accent-color-active: #8d98e4;\n  --accent-color-light: #d2d8fe;\n  --accent-color-visited: #96a1e9;\n}\n\n.secDraculaCyan,\n.secDraculaGreen,\n.secDraculaOrange,\n.secDraculaRed,\n.secDraculaYellow {\n  --text-with-accent-color: #212121;\n}\n\n.secDraculaPink,\n.secDraculaPurple {\n  --text-with-accent-color: #f8f8f2;\n}\n\n.secDraculaCyan {\n  --accent-color-rgb: 139 233 253;\n  --accent-color-hover: #97ebfd;\n  --accent-color-active: #7dd2e4;\n  --accent-color-light: #a2edfd;\n  --accent-color-visited: #6fbaca;\n\n}\n\n.secDraculaGreen {\n  --accent-color-rgb: 80 250 123;\n  --accent-color-hover: #62fb88;\n  --accent-color-active: #48e16f;\n  --accent-color-light: #73fb95;\n  --accent-color-visited: #40c862;\n}\n\n.secDraculaOrange {\n  --accent-color-rgb: 255 184 108;\n  --accent-color-hover: #ffbf7b;\n  --accent-color-active: #e6a661;\n  --accent-color-light: #ffc689;\n  --accent-color-visited: #cc9356;\n}\n\n.secDraculaPink {\n  --accent-color-rgb: 255 121 198;\n  --accent-color-hover: #ff86cc;\n  --accent-color-active: #e66db2;\n  --accent-color-light: #ff94d1;\n  --accent-color-visited: #cc619e;\n}\n\n.secDraculaPurple {\n  --accent-color-rgb: 189 147 249;\n  --accent-color-hover: #c49efa;\n  --accent-color-active: #aa84e0;\n  --accent-color-light: #caa9fa;\n  --accent-color-visited: #9776c7;\n}\n\n.secDraculaRed {\n  --accent-color-rgb: 255 85 85;\n  --accent-color-hover: #f66;\n  --accent-color-active: #e64d4d;\n  --accent-color-light: #f77;\n  --accent-color-visited: #c44;\n}\n\n.secDraculaYellow {\n  --accent-color-rgb: 241 250 140;\n  --accent-color-hover: #f2fb98;\n  --accent-color-active: #d9e17e;\n  --accent-color-light: #f4fba3;\n  --accent-color-visited: #c1c870;\n}\n\n.secSolarizedYellow,\n.secSolarizedOrange,\n.secSolarizedRed,\n.secSolarizedMagenta,\n.secSolarizedViolet,\n.secSolarizedGreen {\n  --text-with-accent-color: #fdf6e3;\n}\n\n.secSolarizedBlue,\n.secSolarizedCyan {\n  --text-with-accent-color: #000;\n}\n\n.secSolarizedYellow {\n  --accent-color-rgb: 165 165 0;\n  --primary-color-hover: #a9a130;\n  --accent-color-hover: #bb9f40;\n  --accent-color-active: #897710;\n  --accent-color-light: #dbc050;\n  --accent-color-visited: #a9a130;\n}\n\n.secSolarizedOrange {\n  --accent-color-rgb: 169 47 20;\n  --primary-color-hover: #c94d34;\n  --accent-color-hover: #db8140;\n  --accent-color-active: #b35936;\n  --accent-color-light: #eb8156;\n  --accent-color-visited: #c94d34;\n}\n\n.secSolarizedRed {\n  --accent-color-rgb: 186 16 29;\n  --primary-color-hover: #d8302d;\n  --accent-color-hover: #da504d;\n  --accent-color-active: #b8282b;\n  --accent-color-light: #fa726f;\n  --accent-color-visited: #d8302d;\n}\n\n.secSolarizedMagenta {\n  --accent-color-rgb: 176 20 96;\n  --primary-color-hover: #d23480;\n  --accent-color-hover: #dc5280;\n  --accent-color-active: #b814a0;\n  --accent-color-light: #fc5280;\n  --accent-color-visited: #d23480;\n}\n\n.secSolarizedViolet {\n  --accent-color-rgb: 78 83 164;\n  --primary-color-hover: #6e83c4;\n  --accent-color-hover: #8e77c4;\n  --accent-color-active: #5e63e4;\n  --accent-color-light: #ae95f4;\n  --accent-color-visited: #6e83c4;\n}\n\n.secSolarizedBlue {\n  --accent-color-rgb: 4 131 178;\n  --primary-color-hover: #4899d2;\n  --accent-color-hover: #469fd2;\n  --accent-color-active: #2483d4;\n  --accent-color-light: #66b1f4;\n  --accent-color-visited: #4899d2;\n}\n\n.secSolarizedCyan {\n  --accent-color-rgb: 8 135 118;\n  --primary-color-hover: #2ca998;\n  --accent-color-hover: #4cb9b8;\n  --accent-color-active: #1c9788;\n  --accent-color-light: #6ce1d8;\n  --accent-color-visited: #2ca998;\n}\n\n.secSolarizedGreen {\n  --accent-color-rgb: 101 119 0;\n  --primary-color-hover: #857720;\n  --accent-color-hover: #a59640;\n  --accent-color-active: #837720;\n  --accent-color-light: #c5d940;\n  --accent-color-visited: #857720;\n}\n\n.secGruvboxDarkGreen {\n  --accent-color-rgb: 152 151 26;\n  --accent-color-hover: #b9b93a;\n  --accent-color-active: #d9d95a;\n  --accent-color-light: #b8bb26;\n  --accent-color-visited: #98971a;\n}\n\n.secGruvboxDarkYellow {\n  --accent-color-rgb: 215 153 33;\n  --accent-color-hover: #f0b839;\n  --accent-color-active: #f0b839;\n  --accent-color-light: #fabd2f;\n  --accent-color-visited: #d79921;\n}\n\n.secGruvboxDarkBlue {\n  --accent-color-rgb: 69 133 136;\n  --accent-color-hover: #68948a;\n  --accent-color-active: #68948a;\n  --accent-color-light: #83a598;\n  --accent-color-visited: #458588;\n}\n\n.secGruvboxDarkPurple {\n  --accent-color-rgb: 177 98 134;\n  --accent-color-hover: #d3869b;\n  --accent-color-active: #d3869b;\n  --accent-color-light: #d3869b;\n  --accent-color-visited: #b16286;\n}\n\n.secGruvboxDarkAqua {\n  --accent-color-rgb: 104 157 106;\n  --accent-color-hover: #8ec07c;\n  --accent-color-active: #8ec07c;\n  --accent-color-light: #8ec07c;\n  --accent-color-visited: #689d6a;\n}\n\n.secGruvboxDarkOrange {\n  --accent-color-rgb: 214 93 14;\n  --accent-color-hover: #f2804f;\n  --accent-color-active: #f2804f;\n  --accent-color-light: #fe8019;\n  --accent-color-visited: #d65d0e;\n}\n\n.secGruvboxLightRed {\n  --text-with-accent-color: #fbf1c7;\n  --accent-color-rgb: 204 36 29;\n  --accent-color-hover: #d23c2a;\n  --accent-color-active: #a61f1f;\n  --accent-color-light: #fb4934;\n  --accent-color-visited: #a61f1f;\n}\n\n.secGruvboxLightBlue {\n  --accent-color-rgb: 69 133 136;\n  --accent-color-hover: #68948a;\n  --accent-color-active: #68948a;\n  --accent-color-light: #83a598;\n  --accent-color-visited: #458588;\n}\n\n.secGruvboxLightPurple {\n  --accent-color-rgb: 177 98 134;\n  --accent-color-hover: #d3869b;\n  --accent-color-active: #d3869b;\n  --accent-color-light: #d3869b;\n  --accent-color-visited: #b16286;\n}\n\n.secGruvboxLightOrange {\n  --accent-color-rgb: 214 93 14;\n  --accent-color-hover: #f2804f;\n  --accent-color-active: #f2804f;\n  --accent-color-light: #fe8019;\n  --accent-color-visited: #d65d0e;\n}\n\n.secGruvboxLightOrange,\n.secGruvboxLightRed,\n.secGruvboxLightBlue,\n.secGruvboxLightPurple {\n  --text-with-accent-color: #fbf1c7;\n}\n\n.secGruvboxDarkGreen,\n.secGruvboxDarkYellow,\n.secGruvboxDarkAqua,\n.secGruvboxDarkOrange {\n  --text-with-accent-color: #3c3836;\n}\n\n.secGruvboxDarkBlue,\n.secGruvboxDarkPurple {\n  --text-with-accent-color: #1d2021;\n}\n\n.secCatppuccinFrappeRosewater,\n.secCatppuccinFrappeFlamingo,\n.secCatppuccinFrappePink,\n.secCatppuccinFrappeMauve,\n.secCatppuccinFrappeRed,\n.secCatppuccinFrappeMaroon,\n.secCatppuccinFrappePeach,\n.secCatppuccinFrappeYellow,\n.secCatppuccinFrappeGreen,\n.secCatppuccinFrappeTeal,\n.secCatppuccinFrappeSky,\n.secCatppuccinFrappeSapphire,\n.secCatppuccinFrappeBlue,\n.secCatppuccinFrappeLavender {\n  --text-with-accent-color: #24273a;\n}\n\n.secCatppuccinFrappeRosewater {\n  --accent-color-rgb: 243 214 223;\n  --accent-color-hover: #f3e0e8;\n  --accent-color-active: #e0bfcf;\n  --accent-color-light: #f8e9f2;\n  --accent-color-visited: #d3a1b3;\n}\n\n.secCatppuccinFrappeFlamingo {\n  --accent-color-rgb: 239 191 191;\n  --accent-color-hover: #f0c9c9;\n  --accent-color-active: #dca8a8;\n  --accent-color-light: #f7dada;\n  --accent-color-visited: #cf8f8f;\n}\n\n.secCatppuccinFrappePink {\n  --accent-color-rgb: 245 185 229;\n  --accent-color-hover: #f5c5e9;\n  --accent-color-active: #e0a0d0;\n  --accent-color-light: #f8d4f0;\n  --accent-color-visited: #d38cb7;\n}\n\n.secCatppuccinFrappeMauve {\n  --accent-color-rgb: 203 159 231;\n  --accent-color-hover: #d4b0e8;\n  --accent-color-active: #b38fdf;\n  --accent-color-light: #d6b9f9;\n  --accent-color-visited: #a171da;\n}\n\n.secCatppuccinFrappeRed {\n  --accent-color-rgb: 232 131 133;\n  --accent-color-hover: #f08b8d;\n  --accent-color-active: #d86f71;\n  --accent-color-light: #f7a0a2;\n  --accent-color-visited: #d86f71;\n}\n\n.secCatppuccinFrappeMaroon {\n  --accent-color-rgb: 235 154 157;\n  --accent-color-hover: #f0a1a4;\n  --accent-color-active: #d88b8e;\n  --accent-color-light: #f7b0b3;\n  --accent-color-visited: #d88b8e;\n}\n\n.secCatppuccinFrappePeach {\n  --accent-color-rgb: 255 175 119;\n  --accent-color-hover: #ffbb8a;\n  --accent-color-active: #e69e6b;\n  --accent-color-light: #fc9;\n  --accent-color-visited: #e69e6b;\n}\n\n.secCatppuccinFrappeYellow {\n  --accent-color-rgb: 230 201 145;\n  --accent-color-hover: #f0d8a1;\n  --accent-color-active: #d8b07f;\n  --accent-color-light: #f7e2b0;\n  --accent-color-visited: #d8b07f;\n}\n\n.secCatppuccinFrappeGreen {\n  --accent-color-rgb: 167 210 138;\n  --accent-color-hover: #b7d28f;\n  --accent-color-active: #87b96f;\n  --accent-color-light: #bde6a0;\n  --accent-color-visited: #6fc75f;\n}\n\n.secCatppuccinFrappeTeal {\n  --accent-color-rgb: 130 201 191;\n  --accent-color-hover: #92d0c6;\n  --accent-color-active: #6eb5ab;\n  --accent-color-light: #a0d6ce;\n  --accent-color-visited: #6eb5ab;\n}\n\n.secCatppuccinFrappeSky {\n  --accent-color-rgb: 154 210 220;\n  --accent-color-hover: #a9d7e0;\n  --accent-color-active: #7dbecb;\n  --accent-color-light: #b4e6f0;\n  --accent-color-visited: #6aaed0;\n}\n\n.secCatppuccinFrappeSapphire {\n  --accent-color-rgb: 134 194 221;\n  --accent-color-hover: #96c9e1;\n  --accent-color-active: #6aaed0;\n  --accent-color-light: #a0d4e6;\n  --accent-color-visited: #6aaed0;\n}\n\n.secCatppuccinFrappeBlue {\n  --accent-color-rgb: 141 171 239;\n  --accent-color-hover: #9dbbef;\n  --accent-color-active: #6b8fcf;\n  --accent-color-light: #a7c1f4;\n  --accent-color-visited: #6b8fcf;\n}\n\n.secCatppuccinFrappeLavender {\n  --accent-color-rgb: 187 188 242;\n  --accent-color-hover: #c4c5f2;\n  --accent-color-active: #a8a9f2;\n  --accent-color-light: #c7c8f2;\n  --accent-color-visited: #9a9bf2;\n}\n\n.secEverforestDarkRed,\n.secEverforestDarkOrange,\n.secEverforestDarkYellow,\n.secEverforestDarkGreen,\n.secEverforestDarkAqua,\n.secEverforestDarkBlue,\n.secEverforestDarkPurple,\n.secEverforestLightRed,\n.secEverforestLightOrange,\n.secEverforestLightYellow,\n.secEverforestLightGreen,\n.secEverforestLightAqua,\n.secEverforestLightBlue,\n.secEverforestLightPurple {\n  --text-with-accent-color: #1e2326;\n}\n\n.secEverforestDarkRed {\n  --accent-color-rgb: 230 126 128;\n  --accent-color-hover: #e78b8d;\n  --accent-color-active: #d66f71;\n  --accent-color-light: #f68e90;\n  --accent-color-visited: #d66f71;\n}\n\n.secEverforestDarkOrange {\n  --accent-color-rgb: 230 152 117;\n  --accent-color-hover: #e6a383;\n  --accent-color-active: #d68360;\n  --accent-color-light: #f6a885;\n  --accent-color-visited: #d68360;\n}\n\n.secEverforestDarkYellow {\n  --accent-color-rgb: 219 188 127;\n  --accent-color-hover: #ddc98f;\n  --accent-color-active: #c8a76b;\n  --accent-color-light: #ebcc8f;\n  --accent-color-visited: #c8a76b;\n}\n\n.secEverforestDarkGreen {\n  --accent-color-rgb: 167 192 128;\n  --accent-color-hover: #b1c98f;\n  --accent-color-active: #8fa76b;\n  --accent-color-light: #b7d090;\n  --accent-color-visited: #8fa76b;\n}\n\n.secEverforestDarkAqua {\n  --accent-color-rgb: 131 192 146;\n  --accent-color-hover: #8dc99f;\n  --accent-color-active: #6ba77b;\n  --accent-color-light: #93d0a2;\n  --accent-color-visited: #6ba77b;\n}\n\n.secEverforestDarkBlue {\n  --accent-color-rgb: 127 187 179;\n  --accent-color-hover: #8cc9c1;\n  --accent-color-active: #6ba79f;\n  --accent-color-light: #8fcbc3;\n  --accent-color-visited: #6ba79f;\n}\n\n.secEverforestDarkPurple {\n  --accent-color-rgb: 214 153 182;\n  --accent-color-hover: #dca3c0;\n  --accent-color-active: #c883a0;\n  --accent-color-light: #e6a9c6;\n  --accent-color-visited: #c883a0;\n}\n\n.secEverforestLightRed {\n  --accent-color-rgb: 248 85 82;\n  --accent-color-hover: #f96360;\n  --accent-color-active: #e64441;\n  --accent-color-light: #f97673;\n  --accent-color-visited: #e64441;\n}\n\n.secEverforestLightOrange {\n  --accent-color-rgb: 245 125 38;\n  --accent-color-hover: #f68b34;\n  --accent-color-active: #e66f10;\n  --accent-color-light: #f79f5a;\n  --accent-color-visited: #e66f10;\n}\n\n.secEverforestLightYellow {\n  --accent-color-rgb: 223 160 0;\n  --accent-color-hover: #e0ad0e;\n  --accent-color-active: #c88b00;\n  --accent-color-light: #f0c000;\n  --accent-color-visited: #c88b00;\n}\n\n.secEverforestLightGreen {\n  --accent-color-rgb: 141 161 1;\n  --accent-color-hover: #9dbf0f;\n  --accent-color-active: #7b8f00;\n  --accent-color-light: #a5d000;\n  --accent-color-visited: #7b8f00;\n}\n\n.secEverforestLightAqua {\n  --accent-color-rgb: 53 167 124;\n  --accent-color-hover: #46b38a;\n  --accent-color-active: #24a569;\n  --accent-color-light: #5ad0a0;\n  --accent-color-visited: #24a569;\n}\n\n.secEverforestLightBlue {\n  --accent-color-rgb: 58 148 197;\n  --accent-color-hover: #4aa2d3;\n  --accent-color-active: #2881b2;\n  --accent-color-light: #5ab0e0;\n  --accent-color-visited: #2881b2;\n}\n\n.secEverforestLightPurple {\n  --accent-color-rgb: 223 105 186;\n  --accent-color-hover: #e77dc9;\n  --accent-color-active: #c84f9a;\n  --accent-color-light: #f09ed0;\n  --accent-color-visited: #c84f9a;\n}\n\n.secCatppuccinLatteMauve,\n.secCatppuccinLatteRed {\n  --text-with-accent-color: #fff;\n}\n\n.secCatppuccinLatteMauve {\n  --accent-color-rgb: 136 57 239;\n  --accent-color-hover: #9f5cf1;\n  --accent-color-active: #7129d2;\n  --accent-color-light: #b076f8;\n  --accent-color-visited: #6021a9;\n}\n\n.secCatppuccinLatteRed {\n  --accent-color-rgb: 210 15 57;\n  --accent-color-hover: #dd385c;\n  --accent-color-active: #ad0c2e;\n  --accent-color-light: #e64e71;\n  --accent-color-visited: #810922;\n}\n\n/*************** DESTRUCTIVE THEME COLOR OVERRIDES ***************/\n\n/* stylelint-disable no-descending-specificity */\n\n/* destructive color in case of conflict with red color themes (sets new destructive color to purple)\n  NOTE: RED COLORS MUST CONTAIN 'Red' IN CLASSNAME.\n*/\nbody[class*='Red'] * {\n  --destructive-color: #9c27b0;\n  --destructive-text-color: #fff;\n  --destructive-hover-color: #8e24aa;\n  --destructive-active-color: #6a1b9a;\n}\n\n/* destructive color in case of conflict with red and purple color themes (sets new destructive color to yellow)\n  NOTE: PURPLE COLORS MUST CONTAIN 'Purple' IN CLASSNAME.\n*/\nbody[class*='Red'][class*='Purple'] * {\n  --destructive-color: #ff9800;\n  --destructive-text-color: #fff;\n  --destructive-hover-color: #fb8c00;\n  --destructive-active-color: #ef6c00;\n}\n\n/* stylelint-enable no-descending-specificity */\n\n\n/*************** LEFT-TO-RIGHT AND RIGHT-TO-LEFT RULES ***************/\n\nbody[dir='ltr'] {\n  --horizontal-directionality-coefficient: 1;\n}\n\nbody[dir='rtl'] {\n  --horizontal-directionality-coefficient: -1;\n}\n\nbody[dir='rtl'] [data-prefix='fas']:not([data-icon='magnifying-glass'], [data-icon='circle-question'], [data-icon='check']) {\n  transform: scale(-1, 1);\n}\n\n/* Arabic, Kurdish, Persian and Urdu have a reversed question mark, but not Hebrew and Yiddish */\nhtml[lang='ar'] [data-prefix='fas'][data-icon='circle-question'],\nhtml[lang='fa'] [data-prefix='fas'][data-icon='circle-question'],\nhtml[lang='ku'] [data-prefix='fas'][data-icon='circle-question'],\nhtml[lang='ur'] [data-prefix='fas'][data-icon='circle-question'] {\n  transform: scale(-1, 1);\n}\n\n\n/*************** MAIN APP STYLING RULES ***************/\n\n.app {\n  color: var(--primary-text-color);\n  background-color: var(--bg-color);\n}\n\n\n/* stylelint-disable no-descending-specificity */\n\n/* stylelint-disable-next-line a11y/no-outline-none */\n.hideOutlines *:focus {\n  outline: none;\n}\n\na:link {\n  color: var(--link-color);\n}\n\na:visited {\n  color: var(--link-visited-color);\n}\n\n/* stylelint-enable no-descending-specificity */\n\n@media (prefers-reduced-motion) {\n  * {\n    transition: none !important;\n    animation: none !important;\n  }\n}\n\n::-webkit-scrollbar {\n  inline-size: auto;\n  block-size: auto;\n}\n\n::-webkit-scrollbar-thumb {\n  background: var(--scrollbar-color);\n  border-radius: 6px;\n  border: 2px solid transparent;\n  background-clip: padding-box;\n}\n\n::-webkit-scrollbar-thumb:hover {\n  border: 0;\n}\n\n::-webkit-scrollbar-thumb:hover,\n::-webkit-scrollbar-thumb:focus {\n  background: var(--scrollbar-color-hover);\n}\n\n/***** REMOVE MAIN SCROLLBAR WHEN PROMPT IS OPEN ******/\n\n/* stylelint-disable-next-line selector-no-qualifying-type */\nbody:has(.prompt) {\n  overflow: hidden;\n}\n"
  },
  {
    "path": "src/renderer/views/About/About.css",
    "content": ".card {\n  margin-block: 0 60px;\n  margin-inline: auto;\n  inline-size: 85%;\n}\n\n.brand {\n  text-align: center;\n}\n\n.logo {\n  max-inline-size: 100%;\n  inline-size: 500px;\n}\n\n.version {\n  text-align: center;\n  font-size: 2em;\n  margin-block-end: 1em;\n}\n\n.about-chunks {\n  display: grid;\n  gap: 16px;\n  grid-template-columns: 1fr 1fr;\n  margin-inline: auto;\n  max-inline-size: 860px;\n}\n\n.chunk {\n  align-items: start;\n  background-color: var(--bg-color);\n  border-radius: 8px;\n  box-shadow: 0 1px 4px -1px rgb(0 0 0 / 50%);\n  display: grid;\n  gap: 6px 14px;\n  grid-template: 'icon title' auto 'icon content' 1fr / auto 1fr;\n  justify-content: start;\n  margin: 0;\n  padding: 18px;\n  overflow-wrap: break-word;\n  overflow-wrap: anywhere;\n}\n\n.icon {\n  font-size: 24px;\n  grid-area: icon;\n}\n\n.title {\n  grid-area: title;\n  margin: 0;\n}\n\n.content {\n  grid-area: content;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <=650px) {\n  .about-chunks {\n    grid-template-columns: 1fr;\n  }\n}\n\n@media only screen and (width <=680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/About/About.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'info-circle']\"\n          class=\"headingIcon\"\n        />\n        {{ $t(\"About.About\") }}\n      </h2>\n      <section class=\"brand\">\n        <FtLogoFull class=\"logo\" />\n        <div class=\"version\">\n          {{ versionNumber }} {{ $t(\"About.Beta\") }}\n        </div>\n      </section>\n      <section class=\"about-chunks\">\n        <figure\n          v-for=\"chunk in chunks\"\n          :key=\"chunk.title\"\n          class=\"chunk\"\n        >\n          <FontAwesomeIcon\n            class=\"icon\"\n            :icon=\"chunk.icon\"\n          />\n          <h3 class=\"title\">\n            {{ chunk.title }}\n          </h3>\n          <div\n            v-safer-html=\"chunk.content\"\n            class=\"content\"\n          />\n        </figure>\n      </section>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtLogoFull from '../../components/FtLogoFull/FtLogoFull.vue'\nimport { vSaferHtml } from '../../directives/vSaferHtml.js'\n\nimport { ABOUT_BITCOIN_ADDRESS } from '../../../constants'\nimport packageDetails from '../../../../package.json'\n\nconst { t } = useI18n()\n\nconst versionNumber = `v${packageDetails.version}`\n\nconst chunks = computed(() => [\n  {\n    icon: ['fab', 'github'],\n    title: t('About.Source code'),\n    content: [\n      '<a href=\"https://github.com/FreeTubeApp/FreeTube\" lang=\"en\" dir=\"ltr\">GitHub: FreeTubeApp/FreeTube</a>',\n      t('About.Licensed under the {licenseLink}', {\n        licenseLink: `<a href=\"https://www.gnu.org/licenses/agpl-3.0.en.html\">${t('About.AGPLv3')}</a>`,\n      }),\n    ].join('<br>'),\n  },\n  {\n    icon: ['fas', 'file-download'],\n    title: t('About.Downloads / Changelog'),\n    content: `<a href=\"https://github.com/FreeTubeApp/FreeTube/releases\">${t('About.GitHub releases')}</a>`,\n  },\n  {\n    icon: ['fas', 'question-circle'],\n    title: t('About.Help'),\n    content: [\n      `<a href=\"https://docs.freetubeapp.io/\">${t('About.FreeTube Wiki')}</a>`,\n      `<a href=\"https://docs.freetubeapp.io/faq/\">${t('About.FAQ')}</a>`,\n      `<a href=\"https://github.com/FreeTubeApp/FreeTube/discussions/\">${t('About.Discussions')}</a>`\n    ].join(' / '),\n  },\n  {\n    icon: ['fas', 'exclamation-circle'],\n    title: t('About.Report a problem'),\n    content: [\n      `<a href=\"https://github.com/FreeTubeApp/FreeTube/issues\">${t('About.GitHub issues')}</a>`,\n      t('About.Please check for duplicates before posting'),\n    ].join('<br>'),\n  },\n  {\n    icon: ['fas', 'globe'],\n    title: t('About.Website'),\n    content: '<a href=\"https://freetubeapp.io/\">https://freetubeapp.io/</a>',\n  },\n  {\n    icon: ['fas', 'newspaper'],\n    title: t('About.Blog'),\n    content: '<a href=\"https://blog.freetubeapp.io\">https://blog.freetubeapp.io</a>',\n  },\n  {\n    icon: ['fas', 'envelope'],\n    title: t('About.Email'),\n    content: '<a href=\"mailto:FreeTubeApp@protonmail.com\">FreeTubeApp@protonmail.com</a>',\n  },\n  {\n    icon: ['fab', 'mastodon'],\n    title: t('About.Mastodon'),\n    content: '<a href=\"https://fosstodon.org/@FreeTube\">@FreeTube@fosstodon.org</a>',\n  },\n  {\n    icon: ['fas', 'comment-dots'],\n    title: t('About.Chat on Matrix'),\n    content: [\n      '<a href=\"https://matrix.to/#/#freetube:matrix.org\">#freetube:matrix.org</a>',\n      t('About.Please read the {roomRulesLink}', {\n        roomRulesLink: `<a href=\"https://docs.freetubeapp.io/community/matrix/\">${t('About.room rules')}</a>`,\n      }),\n    ].join('<br>'),\n  },\n  {\n    icon: ['fas', 'language'],\n    title: t('About.Translate'),\n    content: '<a href=\"https://hosted.weblate.org/engage/free-tube/\">https://hosted.weblate.org/engage/free-tube/</a>',\n  },\n  {\n    icon: ['fas', 'users'],\n    title: t('About.Credits'),\n    content: t('About.FreeTube is made possible by {creditsPageLink}', {\n      creditsPageLink: `<a href=\"https://docs.freetubeapp.io/credits/\">${t('About.these people and projects')}</a>`,\n    }),\n  },\n  {\n    icon: ['fab', 'bitcoin'],\n    title: `${t('About.Donate')} - BTC`,\n    content: `<a href=\"bitcoin:${ABOUT_BITCOIN_ADDRESS}\">${ABOUT_BITCOIN_ADDRESS}</a>`\n  }\n])\n</script>\n\n<style scoped src=\"./About.css\" />\n"
  },
  {
    "path": "src/renderer/views/Channel/Channel.css",
    "content": ".card {\n  position: relative;\n  inline-size: 85%;\n  margin-block: 0 20px;\n  margin-inline: auto;\n  box-sizing: border-box;\n}\n\n.channelDetails {\n  padding: 0;\n  max-inline-size: 92vw;\n}\n\n.select-container {\n  display: flex;\n  flex-direction: row;\n  justify-content: flex-end;\n  margin-block-end: 10px;\n}\n\n.elementListLoading {\n  margin-block-start: 200px;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.getNextPage {\n  background-color: var(--search-bar-color);\n  inline-size: 100%;\n  block-size: 45px;\n  line-height: 45px;\n  text-align: center;\n  cursor: pointer;\n  margin-block-start: 16px;\n}\n\n@media only screen and (width <= 800px) {\n  .communityPanel {\n    margin-block-start: 1rem;\n  }\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    max-inline-size: none;\n    inline-size: 100%;\n  }\n}\n\n@media only screen and (width <= 260px) {\n  .channelDetails {\n    max-inline-size: none;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Channel/Channel.vue",
    "content": "<template>\n  <div>\n    <FtLoader\n      v-if=\"isLoading && !errorMessage\"\n      :fullscreen=\"true\"\n    />\n    <ChannelDetails\n      v-else-if=\"(isFamilyFriendly || !showFamilyFriendlyOnly)\"\n      :id=\"id\"\n      :name=\"channelName\"\n      :banner-url=\"bannerUrl\"\n      :has-error-message=\"!!errorMessage\"\n      :thumbnail-url=\"thumbnailUrl\"\n      :sub-count=\"subCount\"\n      :show-share-menu=\"showShareMenu\"\n      :show-search-bar=\"showSearchBar\"\n      :is-subscribed=\"isSubscribed\"\n      :visible-tabs=\"tabInfoValues\"\n      :current-tab=\"currentTab\"\n      :query=\"lastSearchQuery\"\n      class=\"card channelDetails\"\n      @change-tab=\"changeTab\"\n      @search=\"newSearchWithStatePersist\"\n      @subscribed=\"handleSubscription\"\n    />\n    <FtCard\n      v-if=\"!isLoading && !errorMessage && (isFamilyFriendly || !showFamilyFriendlyOnly)\"\n      class=\"card\"\n    >\n      <ChannelAbout\n        v-if=\"currentTab === 'about'\"\n        id=\"aboutPanel\"\n        :description=\"description\"\n        :joined=\"joined\"\n        :views=\"viewCount\"\n        :videos=\"videoCount\"\n        :location=\"location\"\n        :tags=\"tags\"\n        :related-channels=\"relatedChannels\"\n      />\n      <div class=\"select-container\">\n        <FtSelect\n          v-if=\"showVideoSortBy\"\n          v-show=\"currentTab === 'videos' && (showFetchMoreButton || filteredVideos.length > 1)\"\n          :value=\"videoSortBy\"\n          :select-names=\"videoLiveShortSelectNames\"\n          :select-values=\"videoLiveShortSelectValues\"\n          :placeholder=\"$t('Global.Sort By')\"\n          :icon=\"getIconForSortPreference(videoSortBy)\"\n          @change=\"videoSortBy = $event\"\n        />\n        <FtSelect\n          v-if=\"!hideChannelShorts && showShortSortBy\"\n          v-show=\"currentTab === 'shorts' && (showFetchMoreButton || filteredShorts.length > 1)\"\n          :value=\"shortSortBy\"\n          :select-names=\"videoLiveShortSelectNames\"\n          :select-values=\"videoLiveShortSelectValues\"\n          :placeholder=\"$t('Global.Sort By')\"\n          :icon=\"getIconForSortPreference(shortSortBy)\"\n          @change=\"shortSortBy = $event\"\n        />\n        <FtSelect\n          v-if=\"!hideLiveStreams && showLiveSortBy\"\n          v-show=\"currentTab === 'live' && (showFetchMoreButton || filteredLive.length > 1)\"\n          :value=\"liveSortBy\"\n          :select-names=\"videoLiveShortSelectNames\"\n          :select-values=\"videoLiveShortSelectValues\"\n          :placeholder=\"$t('Global.Sort By')\"\n          :icon=\"getIconForSortPreference(liveSortBy)\"\n          @change=\"liveSortBy = $event\"\n        />\n        <FtSelect\n          v-if=\"!hideChannelPlaylists && showPlaylistSortBy\"\n          v-show=\"currentTab === 'playlists' && latestPlaylists.length > 0\"\n          :value=\"playlistSortBy\"\n          :select-names=\"playlistSelectNames\"\n          :select-values=\"PLAYLIST_SELECT_VALUES\"\n          :placeholder=\"$t('Global.Sort By')\"\n          :icon=\"getIconForSortPreference(playlistSortBy)\"\n          @change=\"playlistSortBy = $event\"\n        />\n      </div>\n      <FtLoader\n        v-if=\"isCurrentTabLoading\"\n      />\n      <div\n        v-if=\"currentTab !== 'about' && !isElementListLoading\"\n        class=\"elementList\"\n      >\n        <ChannelHome\n          v-show=\"currentTab === 'home'\"\n          id=\"homePanel\"\n          :shelves=\"homeData\"\n          role=\"tabpanel\"\n          aria-labelledby=\"homeTab\"\n        />\n        <FtElementList\n          v-show=\"currentTab === 'videos'\"\n          id=\"videoPanel\"\n          :data=\"filteredVideos\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"videosTab\"\n        />\n        <FtFlexBox\n          v-if=\"currentTab === 'videos' && latestVideos.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Videos.This channel does not currently have any videos\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelShorts && currentTab === 'shorts'\"\n          id=\"shortPanel\"\n          :data=\"filteredShorts\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"shortsTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelShorts && currentTab === 'shorts' && latestShorts.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Shorts.This channel does not currently have any shorts\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideLiveStreams\"\n          v-show=\"currentTab === 'live'\"\n          id=\"livePanel\"\n          :data=\"filteredLive\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"liveTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideLiveStreams && currentTab === 'live' && latestLive.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Live.This channel does not currently have any live streams\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelPodcasts && currentTab === 'podcasts'\"\n          id=\"podcastPanel\"\n          :data=\"latestPodcasts\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"podcastsTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelPodcasts && currentTab === 'podcasts' && latestPodcasts.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Podcasts.This channel does not currently have any podcasts\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelReleases && currentTab === 'releases'\"\n          id=\"releasePanel\"\n          :data=\"latestReleases\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"releasesTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelReleases && currentTab === 'releases' && latestReleases.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Releases.This channel does not currently have any releases\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelCourses && currentTab === 'courses'\"\n          id=\"coursesPanel\"\n          :data=\"latestCourses\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"coursesTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelCourses && currentTab === 'courses' && latestCourses.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Courses.This channel does not currently have any courses\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelPlaylists && currentTab === 'playlists'\"\n          id=\"playlistPanel\"\n          :data=\"latestPlaylists\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"playlistsTab\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelPlaylists && currentTab === 'playlists' && latestPlaylists.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Playlists.This channel does not currently have any playlists\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-if=\"!hideChannelCommunity && currentTab === 'community'\"\n          id=\"communityPanel\"\n          class=\"communityPanel\"\n          :data=\"latestCommunityPosts\"\n          :use-channels-hidden-preference=\"false\"\n          role=\"tabpanel\"\n          aria-labelledby=\"communityTab\"\n          display=\"list\"\n        />\n        <FtFlexBox\n          v-if=\"!hideChannelCommunity && currentTab === 'community' && latestCommunityPosts.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Posts.This channel currently does not have any posts\") }}\n          </p>\n        </FtFlexBox>\n        <FtElementList\n          v-show=\"currentTab === 'search'\"\n          :data=\"searchResults\"\n          :use-channels-hidden-preference=\"false\"\n        />\n        <FtFlexBox\n          v-if=\"currentTab === 'search' && !isSearchTabLoading && searchResults.length === 0\"\n        >\n          <p class=\"message\">\n            {{ $t(\"Channel.Your search results have returned 0 results\") }}\n          </p>\n        </FtFlexBox>\n        <FtAutoLoadNextPageWrapper\n          v-if=\"showFetchMoreButton\"\n          @load-next-page=\"handleFetchMore\"\n        >\n          <div\n            class=\"getNextPage\"\n            role=\"button\"\n            tabindex=\"0\"\n            @click=\"handleFetchMore\"\n            @keydown.space.prevent=\"handleFetchMore\"\n            @keydown.enter.prevent=\"handleFetchMore\"\n          >\n            <FontAwesomeIcon :icon=\"['fas', 'search']\" /> {{ $t(\"Search Filters.Fetch more results\") }}\n          </div>\n        </FtAutoLoadNextPageWrapper>\n      </div>\n    </FtCard>\n    <FtCard\n      v-if=\"errorMessage\"\n      class=\"card\"\n    >\n      <p>\n        {{ errorMessage }}\n      </p>\n    </FtCard>\n    <FtAgeRestricted\n      v-else-if=\"!isLoading && (!isFamilyFriendly && showFamilyFriendlyOnly)\"\n      class=\"ageRestricted\"\n      :is-channel=\"true\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport autolinker from 'autolinker'\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { isNavigationFailure, NavigationFailureType, useRoute, useRouter } from 'vue-router'\nimport { YTNodes } from 'youtubei.js'\n\nimport ChannelAbout from '../../components/ChannelAbout/ChannelAbout.vue'\nimport ChannelDetails from '../../components/ChannelDetails/ChannelDetails.vue'\nimport ChannelHome from '../../components/ChannelHome/ChannelHome.vue'\nimport FtAgeRestricted from '../../components/FtAgeRestricted/FtAgeRestricted.vue'\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtSelect from '../../components/FtSelect/FtSelect.vue'\n\nimport store from '../../store/index'\n\nimport packageDetails from '../../../../package.json'\nimport {\n  copyToClipboard,\n  extractNumberFromString,\n  showToast,\n  getChannelPlaylistId,\n  getIconForSortPreference,\n  removeFromArrayIfExists\n} from '../../helpers/utils'\nimport { isNullOrEmpty } from '../../helpers/strings'\nimport {\n  getInvidiousChannelLive,\n  getInvidiousChannelPlaylists,\n  getInvidiousChannelPodcasts,\n  getInvidiousChannelReleases,\n  getInvidiousChannelCourses,\n  getInvidiousChannelShorts,\n  getInvidiousChannelVideos,\n  invidiousGetChannelId,\n  invidiousGetChannelInfo,\n  invidiousGetCommunityPosts,\n  searchInvidiousChannel,\n  youtubeImageUrlToInvidious\n} from '../../helpers/api/invidious'\nimport {\n  getLocalChannel,\n  getLocalChannelId,\n  getLocalArtistTopicChannelReleases,\n  parseLocalChannelHeader,\n  parseLocalChannelShorts,\n  parseLocalChannelVideos,\n  parseLocalCommunityPosts,\n  parseLocalListPlaylist,\n  parseLocalListVideo,\n  parseLocalSubscriberCount,\n  getLocalArtistTopicChannelReleasesContinuation,\n  getLocalPlaylist,\n  parseLocalPlaylistVideo,\n  parseChannelHomeTab\n} from '../../helpers/api/local'\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nlet skipRouteChangeWatcherOnce = false\nlet autoRefreshOnSortByChangeEnabled = false\n/** @type {import('youtubei.js').YT.Channel|null} */\nlet channelInstance = null\n/** @type {'local' | 'invidious' | ''} */\nlet apiUsed = ''\nlet mayContainContentFromOtherChannels = false\n\nconst isLoading = ref(true)\nconst isElementListLoading = ref(false)\nconst isSearchTabLoading = ref(false)\nconst currentTab = ref('videos')\n\nconst isCurrentTabLoading = computed(() => {\n  return currentTab.value === 'search' ? isSearchTabLoading.value : isElementListLoading.value\n})\n\nconst id = ref('')\nconst channelName = ref('')\nconst bannerUrl = ref('')\nconst thumbnailUrl = ref('')\nconst subCount = ref(0)\nconst description = ref('')\nconst tags = shallowRef([])\nconst viewCount = ref(0)\nconst videoCount = ref(0)\nconst joined = ref(0)\nconst location = ref(null)\nconst relatedChannels = shallowRef([])\nconst isArtistTopicChannel = ref(false)\nconst isFamilyFriendly = ref(false)\n\nconst errorMessage = ref('')\nconst showSearchBar = ref(true)\nconst showShareMenu = ref(true)\n\nconst PLAYLIST_SELECT_VALUES = ['newest', 'last']\nconst playlistSelectNames = computed(() => [\n  t('Channel.Playlists.Sort Types.Newest'),\n  t('Channel.Playlists.Sort Types.Last Video Added')\n])\n\nconst videoLiveShortSelectValues = computed(() => {\n  return isArtistTopicChannel.value\n    ? ['newest', 'popular']\n    : ['newest', 'popular', 'oldest']\n})\n\nconst videoLiveShortSelectNames = computed(() => {\n  if (isArtistTopicChannel.value) {\n    return [\n      t('Channel.Videos.Sort Types.Newest'),\n      t('Channel.Videos.Sort Types.Most Popular'),\n    ]\n  }\n\n  return [\n    t('Channel.Videos.Sort Types.Newest'),\n    t('Channel.Videos.Sort Types.Most Popular'),\n    t('Channel.Videos.Sort Types.Oldest')\n  ]\n})\n\nconst SUPPORTED_CHANNEL_TABS = [\n  'home',\n  'videos',\n  'shorts',\n  'live',\n  'releases',\n  'podcasts',\n  'courses',\n  'playlists',\n  'community',\n  'about'\n]\n\nconst channelTabs = shallowRef([\n  'videos',\n  'shorts',\n  'live',\n  'releases',\n  'podcasts',\n  'courses',\n  'playlists',\n  'community',\n  'about'\n])\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showFamilyFriendlyOnly = computed(() => store.getters.getShowFamilyFriendlyOnly)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\nconst activeProfile = computed(() => store.getters.getActiveProfile)\n\nconst subscriptionInfo = computed(() => {\n  return activeProfile.value.subscriptions.find((channel) => {\n    return channel.id === id.value\n  }) ?? null\n})\n\nconst isSubscribed = computed(() => subscriptionInfo.value !== null)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst isSubscribedInAnyProfile = computed(() => {\n  return store.getters.getSubscribedChannelIdSet.has(id.value)\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelHome = computed(() => store.getters.getHideChannelHome)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelShorts = computed(() => store.getters.getHideChannelShorts)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideLiveStreams = computed(() => store.getters.getHideLiveStreams)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelPodcasts = computed(() => store.getters.getHideChannelPodcasts)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelReleases = computed(() => store.getters.getHideChannelReleases)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelCourses = computed(() => store.getters.getHideChannelCourses)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelPlaylists = computed(() => store.getters.getHideChannelPlaylists)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideChannelCommunity = computed(() => store.getters.getHideChannelCommunity)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideWatchedSubs = computed(() => store.getters.getHideWatchedSubs)\n\nconst tabInfoValues = computed(() => {\n  const values = [...channelTabs.value]\n\n  // remove tabs from the array based on user settings\n  if (hideChannelHome.value || !homeData.value || homeData.value.length === 0) {\n    removeFromArrayIfExists(values, 'home')\n  }\n\n  if (hideChannelShorts.value) {\n    removeFromArrayIfExists(values, 'shorts')\n  }\n\n  if (hideLiveStreams.value) {\n    removeFromArrayIfExists(values, 'live')\n  }\n\n  if (hideChannelPlaylists.value) {\n    removeFromArrayIfExists(values, 'playlists')\n  }\n\n  if (hideChannelCommunity.value) {\n    removeFromArrayIfExists(values, 'community')\n  }\n\n  if (hideChannelPodcasts.value) {\n    removeFromArrayIfExists(values, 'podcasts')\n  }\n\n  if (hideChannelReleases.value) {\n    removeFromArrayIfExists(values, 'releases')\n  }\n\n  if (hideChannelCourses.value) {\n    removeFromArrayIfExists(values, 'courses')\n  }\n\n  return values\n})\n\nwatch(route, () => {\n  if (skipRouteChangeWatcherOnce) {\n    skipRouteChangeWatcherOnce = false\n    return\n  }\n  isLoading.value = true\n\n  if (route.query.url) {\n    resolveChannelUrl(route.query.url, route.params.currentTab)\n    return\n  }\n\n  // Disable auto refresh on sort value change during state reset\n  autoRefreshOnSortByChangeEnabled = false\n\n  id.value = route.params.id\n  searchPage = 1\n  relatedChannels.value = []\n  latestVideos.value = []\n  latestShorts.value = []\n  latestLive.value = []\n  videoSortBy.value = 'newest'\n  shortSortBy.value = 'newest'\n  liveSortBy.value = 'newest'\n  playlistSortBy.value = 'newest'\n  latestPlaylists.value = []\n  latestPodcasts.value = []\n  latestReleases.value = []\n  latestCommunityPosts.value = []\n  searchResults.value = []\n  apiUsed = ''\n  channelInstance = null\n  mayContainContentFromOtherChannels = false\n  isArtistTopicChannel.value = false\n  videoContinuationData.value = null\n  shortContinuationData.value = null\n  liveContinuationData.value = null\n  playlistContinuationData.value = null\n  podcastContinuationData.value = null\n  releaseContinuationData.value = null\n  searchContinuationData.value = null\n  communityContinuationData.value = null\n  showSearchBar.value = true\n  showVideoSortBy.value = true\n  showShortSortBy.value = true\n  showLiveSortBy.value = true\n  showPlaylistSortBy.value = true\n\n  currentTab.value = currentOrFirstTab(route.params.currentTab)\n\n  if (id.value === '@@@') {\n    showShareMenu.value = false\n    setErrorMessage(t('Channel.This channel does not exist'))\n    return\n  }\n\n  showShareMenu.value = true\n  errorMessage.value = ''\n\n  // Re-enable auto refresh on sort value change AFTER update done\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    getChannelInfoInvidious().finally(() => {\n      autoRefreshOnSortByChangeEnabled = true\n    })\n  } else {\n    getChannelLocal().finally(() => {\n      autoRefreshOnSortByChangeEnabled = true\n    })\n  }\n}, { deep: true })\n\nonMounted(async () => {\n  if (route.query.url) {\n    await resolveChannelUrl(route.query.url, route.params.currentTab)\n    return\n  }\n\n  id.value = route.params.id\n\n  currentTab.value = currentOrFirstTab(route.params.currentTab)\n\n  if (id.value === '@@@') {\n    showShareMenu.value = false\n    setErrorMessage(t('Channel.This channel does not exist'))\n    return\n  }\n\n  // Enable auto refresh on sort value change AFTER initial update done\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    await getChannelInfoInvidious().finally(() => {\n      autoRefreshOnSortByChangeEnabled = true\n    })\n  } else {\n    await getChannelLocal().finally(() => {\n      autoRefreshOnSortByChangeEnabled = true\n    })\n  }\n\n  const oldQuery = route.query.searchQueryText ?? ''\n  if (oldQuery !== '') {\n    newSearch(oldQuery)\n  }\n})\n\n/**\n * @param {string} url\n * @param {string|undefined} tab\n */\nasync function resolveChannelUrl(url, tab = undefined) {\n  let id\n\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    id = await invidiousGetChannelId(url)\n  } else {\n    id = await getLocalChannelId(url)\n  }\n\n  if (id === null) {\n    // the channel page shows an error about the channel not existing when the id is @@@\n    id = '@@@'\n  }\n\n  // use router.replace to replace the current history entry\n  // with the one with the resolved channel id\n  // that way if you navigate back or forward in the history to this entry\n  // we don't need to resolve the URL again as we already know it\n  if (tab) {\n    router.replace({ path: `/channel/${id}/${tab}` })\n  } else {\n    router.replace({ path: `/channel/${id}` })\n  }\n}\n\n/**\n * @param {string} currentTab\n */\nfunction currentOrFirstTab(currentTab) {\n  return tabInfoValues.value.includes(currentTab) ? currentTab : tabInfoValues.value[0]\n}\n\nasync function ensureChannelInstance() {\n  if (!channelInstance) {\n    channelInstance = await getLocalChannel(id.value)\n  }\n}\n\nasync function getChannelLocal() {\n  apiUsed = 'local'\n  isLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    let channelName_\n    let channelThumbnailUrl\n\n    if (channelInstance.alert) {\n      setErrorMessage(channelInstance.alert)\n      return\n    } else if (channelInstance.memo.has('ChannelAgeGate')) {\n      /** @type {import('youtubei.js').YTNodes.ChannelAgeGate} */\n      const ageGate = channelInstance.memo.get('ChannelAgeGate')[0]\n\n      channelName_ = ageGate.channel_title\n      channelThumbnailUrl = ageGate.avatar[0].url\n\n      channelName.value = channelName\n      thumbnailUrl.value = channelThumbnailUrl\n\n      store.commit('setAppTitle', `${channelName_} - ${packageDetails.productName}`)\n\n      store.dispatch('updateSubscriptionDetails', { channelThumbnailUrl, channelName: channelName_, channelId: id.value })\n\n      setErrorMessage(t('Channel[\"This channel is age-restricted and currently cannot be viewed in FreeTube.\"]'), true)\n      return\n    }\n\n    errorMessage.value = ''\n    if (expectedId !== id.value) {\n      return\n    }\n\n    const parsedHeader = parseLocalChannelHeader(channelInstance)\n\n    const channelId = parsedHeader.id ?? id.value\n    const subscriberText = parsedHeader.subscriberText ?? null\n    let tags_ = parsedHeader.tags\n\n    channelThumbnailUrl = parsedHeader.thumbnailUrl ?? subscriptionInfo.value?.thumbnail\n    channelName_ = parsedHeader.name ?? subscriptionInfo.value?.name\n\n    if (channelThumbnailUrl?.startsWith('//')) {\n      channelThumbnailUrl = `https:${channelThumbnailUrl}`\n    }\n\n    channelName.value = channelName_\n    thumbnailUrl.value = channelThumbnailUrl\n    bannerUrl.value = parsedHeader.bannerUrl ?? null\n    isFamilyFriendly.value = !!channelInstance.metadata.is_family_safe\n    isArtistTopicChannel.value = channelName_.endsWith('- Topic') && !!channelInstance.metadata.music_artist_name\n\n    mayContainContentFromOtherChannels = isArtistTopicChannel.value ||\n      !!channelInstance.header?.is(YTNodes.CarouselHeader, YTNodes.InteractiveTabbedHeader) ||\n      !!(channelInstance.header?.is(YTNodes.PageHeader) && channelInstance.header.content?.animated_image)\n\n    if (channelInstance.metadata.tags) {\n      tags_.push(...channelInstance.metadata.tags)\n    }\n\n    // deduplicate tags\n    // a Set can only ever contain unique elements,\n    // so this is an easy way to get rid of duplicates\n    if (tags_.length > 0) {\n      tags_ = Array.from(new Set(tags_))\n    }\n    tags.value = tags_\n\n    store.commit('setAppTitle', `${channelName_} - ${packageDetails.productName}`)\n\n    if (subscriberText) {\n      const subCount_ = parseLocalSubscriberCount(subscriberText)\n\n      if (isNaN(subCount_)) {\n        subCount.value = null\n      } else {\n        subCount.value = subCount_\n      }\n    } else {\n      subCount.value = null\n    }\n\n    store.dispatch('updateSubscriptionDetails', { channelThumbnailUrl, channelName: channelName_, channelId })\n\n    if (channelInstance.has_about) {\n      getChannelAboutLocal()\n    } else {\n      description.value = ''\n      viewCount.value = null\n      videoCount.value = null\n      joined.value = 0\n      location.value = null\n    }\n    const tabs = ['about']\n\n    // we'll count it as home page if it's not video. This will help us support some special channels\n    if ((channelInstance.has_home || channelInstance.tabs[0] !== 'Videos')) {\n      if (!hideChannelHome.value) {\n        tabs.push('home')\n      }\n      // we still parse the home page so we can set related channels\n      getChannelHomeLocal()\n    }\n\n    if (channelInstance.has_videos || isArtistTopicChannel.value) {\n      tabs.push('videos')\n      getChannelVideosLocal()\n    }\n\n    if (!hideChannelShorts.value && channelInstance.has_shorts) {\n      tabs.push('shorts')\n      getChannelShortsLocal()\n    }\n\n    if (!hideLiveStreams.value && channelInstance.has_live_streams) {\n      tabs.push('live')\n      getChannelLiveLocal()\n    }\n\n    if (!hideChannelPodcasts.value && channelInstance.has_podcasts) {\n      tabs.push('podcasts')\n      getChannelPodcastsLocal()\n    }\n\n    if (!hideChannelReleases.value && (channelInstance.has_releases || isArtistTopicChannel.value)) {\n      tabs.push('releases')\n      getChannelReleasesLocal()\n    }\n\n    if (!hideChannelCourses.value && channelInstance.has_courses) {\n      tabs.push('courses')\n      getChannelCoursesLocal()\n    }\n\n    if (!hideChannelPlaylists.value) {\n      if (channelInstance.has_playlists) {\n        tabs.push('playlists')\n        getChannelPlaylistsLocal()\n      }\n    }\n\n    if (!hideChannelCommunity.value && channelInstance.has_community) {\n      tabs.push('community')\n      getCommunityPostsLocal()\n    }\n\n    channelTabs.value = SUPPORTED_CHANNEL_TABS.filter(tab => {\n      return tabs.includes(tab)\n    })\n\n    currentTab.value = currentOrFirstTab(route.params.currentTab)\n    showSearchBar.value = channelInstance.has_search\n\n    isLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getChannelInfoInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelAboutLocal() {\n  try {\n    await ensureChannelInstance()\n    const about = await channelInstance.getAbout()\n\n    if (about.is(YTNodes.ChannelAboutFullMetadata)) {\n      description.value = about.description.isEmpty() ? '' : autolinker.link(about.description.text)\n\n      const viewCount_ = extractNumberFromString(about.view_count.text)\n      viewCount.value = isNaN(viewCount_) ? null : viewCount_\n\n      videoCount.value = null\n\n      joined.value = about.joined_date.isEmpty() ? 0 : Date.parse(about.joined_date.text.replace('Joined').trim())\n\n      location.value = about.country.isEmpty() ? null : about.country.text\n    } else {\n      description.value = about.metadata.description ? autolinker.link(about.metadata.description) : ''\n\n      const viewCount_ = extractNumberFromString(about.metadata.view_count)\n      viewCount.value = isNaN(viewCount_) ? null : viewCount_\n\n      const videoCount_ = extractNumberFromString(about.metadata.video_count)\n      videoCount.value = isNaN(videoCount_) ? null : videoCount_\n\n      joined.value = about.metadata.joined_date && !about.metadata.joined_date.isEmpty() ? Date.parse(about.metadata.joined_date.text.replace('Joined').trim()) : 0\n\n      location.value = about.metadata.country ?? null\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getChannelInfoInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nconst homeData = shallowRef([])\n\nfunction getChannelHomeLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    const homeTab = channelInstance //  await channel.getHome()\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    let homeData_\n\n    if (mayContainContentFromOtherChannels) {\n      homeData_ = parseChannelHomeTab(homeTab)\n    } else {\n      homeData_ = parseChannelHomeTab(homeTab, id.value, channelName.value)\n    }\n\n    if (!hideChannelHome.value) {\n      homeData.value = homeData_\n    }\n\n    // parse related channels from home page data\n    const relatedChannels_ = []\n    /** @type {Set<string>} */\n    const knownChannelIds = new Set()\n\n    for (const shelf of homeData_) {\n      for (const item of shelf.content) {\n        if (item.type === 'channel' && !knownChannelIds.has(item.id)) {\n          knownChannelIds.add(item)\n          relatedChannels_.push({\n            name: item.name,\n            id: item.id,\n            thumbnailUrl: item.thumbnail\n          })\n        }\n      }\n    }\n    relatedChannels.value = relatedChannels_\n\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function getChannelInfoInvidious() {\n  isLoading.value = true\n  apiUsed = 'invidious'\n  channelInstance = null\n\n  const expectedId = id.value\n  try {\n    const response = await invidiousGetChannelInfo(id.value)\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    const channelName_ = response.author\n    const channelId = response.authorId\n    channelName.value = channelName_\n    store.commit('setAppTitle', `${channelName_} - ${packageDetails.productName}`)\n    id.value = channelId\n    isFamilyFriendly.value = response.isFamilyFriendly\n    subCount.value = response.subCount\n    const thumbnail = response.authorThumbnails[3].url\n    thumbnailUrl.value = youtubeImageUrlToInvidious(thumbnail, currentInvidiousInstanceUrl.value)\n    store.dispatch('updateSubscriptionDetails', { channelThumbnailUrl: thumbnail, channelName: channelName_, channelId })\n    description.value = autolinker.link(response.description)\n    viewCount.value = response.totalViews\n    videoCount.value = null\n    joined.value = response.joined * 1000\n    relatedChannels.value = response.relatedChannels.map((channel) => {\n      const thumbnailUrl = channel.authorThumbnails.at(-1).url\n\n      return {\n        name: channel.author,\n        id: channel.authorId,\n        thumbnailUrl: youtubeImageUrlToInvidious(thumbnailUrl, currentInvidiousInstanceUrl.value)\n      }\n    })\n\n    if (Array.isArray(response.authorBanners) && response.authorBanners.length > 0) {\n      bannerUrl.value = youtubeImageUrlToInvidious(response.authorBanners[0].url, currentInvidiousInstanceUrl.value)\n    } else {\n      bannerUrl.value = null\n    }\n\n    errorMessage.value = ''\n\n    // some channels only have a few tabs\n    // here are all possible values: home, videos, shorts, streams, playlists, community, channels, about\n\n    channelTabs.value = SUPPORTED_CHANNEL_TABS.filter(tab => {\n      return response.tabs.includes(tab) && tab !== 'home'\n    })\n\n    currentTab.value = currentOrFirstTab(route.params.currentTab)\n\n    if (response.tabs.includes('videos')) {\n      channelInvidiousVideos()\n    }\n\n    if (!hideChannelShorts.value && response.tabs.includes('shorts')) {\n      channelInvidiousShorts()\n    }\n\n    if (!hideLiveStreams.value && response.tabs.includes('live')) {\n      channelInvidiousLive()\n    }\n\n    if (!hideChannelPodcasts.value && response.tabs.includes('podcasts')) {\n      channelInvidiousPodcasts()\n    }\n\n    if (!hideChannelReleases.value && response.tabs.includes('releases')) {\n      channelInvidiousReleases()\n    }\n\n    if (!hideChannelCourses.value && response.tabs.includes('courses')) {\n      channelInvidiousCourses()\n    }\n\n    if (!hideChannelPlaylists.value && response.tabs.includes('playlists')) {\n      getPlaylistsInvidious()\n    }\n\n    if (!hideChannelCommunity.value && response.tabs.includes('community')) {\n      getCommunityPostsInvidious()\n    }\n\n    isLoading.value = false\n  } catch (err) {\n    setErrorMessage(err)\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getChannelLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nconst latestVideos = shallowRef([])\nconst videoContinuationData = shallowRef(null)\nconst showVideoSortBy = ref(true)\nconst videoSortBy = ref('newest')\n\nconst filteredVideos = computed(() => {\n  if (hideWatchedSubs.value) {\n    return filterWatchedArray(latestVideos.value)\n  } else {\n    return latestVideos.value\n  }\n})\n\nconst filteredShorts = computed(() => {\n  if (hideWatchedSubs.value) {\n    return filterWatchedArray(latestShorts.value)\n  } else {\n    return latestShorts.value\n  }\n})\n\nconst filteredLive = computed(() => {\n  if (hideWatchedSubs.value) {\n    return filterWatchedArray(latestLive.value)\n  } else {\n    return latestLive.value\n  }\n})\n\nwatch(videoSortBy, () => {\n  if (!autoRefreshOnSortByChangeEnabled) { return }\n\n  isElementListLoading.value = true\n  latestVideos.value = []\n  videoContinuationData.value = null\n\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n    getChannelVideosLocal()\n  } else {\n    channelInvidiousVideos(true)\n  }\n})\n\nasync function getChannelVideosLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    if (isArtistTopicChannel.value) {\n      // Artist topic channels don't have a videos tab.\n      // Interestingly the auto-generated uploads playlists do exist for those channels,\n      // so we'll use them instead.\n\n      const playlistId = getChannelPlaylistId(id.value, 'videos', videoSortBy.value)\n      const playlist = await getLocalPlaylist(playlistId)\n\n      if (expectedId !== id.value) {\n        return\n      }\n\n      latestVideos.value = playlist.items.map(parseLocalPlaylistVideo)\n      videoContinuationData.value = playlist.has_continuation ? playlist : null\n      isElementListLoading.value = false\n    } else {\n      await ensureChannelInstance()\n\n      let videosTab = await channelInstance.getVideos()\n\n      showVideoSortBy.value = videosTab.filters.length > 1\n\n      if (showVideoSortBy.value && videoSortBy.value !== 'newest') {\n        const index = videoLiveShortSelectValues.value.indexOf(videoSortBy.value)\n        videosTab = await videosTab.applyFilter(videosTab.filters[index])\n      }\n\n      if (expectedId !== id.value) {\n        return\n      }\n\n      latestVideos.value = parseLocalChannelVideos(videosTab.videos, id.value, channelName.value)\n      videoContinuationData.value = videosTab.has_continuation ? videosTab : null\n      isElementListLoading.value = false\n    }\n\n    if (isSubscribedInAnyProfile.value && latestVideos.value.length > 0 && videoSortBy.value === 'newest') {\n      store.dispatch('updateSubscriptionVideosCacheByChannel', {\n        channelId: id.value,\n        videos: latestVideos.value\n      })\n    }\n  } catch (err) {\n    if (isArtistTopicChannel.value && err.message === 'The playlist does not exist.') {\n      // If this artist topic channel doesn't have any videos, ignore the error.\n      return\n    }\n\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getChannelInfoInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelVideosLocalMore() {\n  try {\n    if (isArtistTopicChannel.value) {\n      /** @type {import('youtubei.js').YT.Playlist} */\n      const continuation = await videoContinuationData.value.getContinuation()\n\n      latestVideos.value = latestVideos.value.concat(continuation.items.map(parseLocalPlaylistVideo))\n      videoContinuationData.value = continuation.has_continuation ? continuation : null\n    } else {\n      /**\n       * @type {import('youtubei.js').YT.ChannelListContinuation|import('youtubei.js').YT.FilteredChannelList}\n       */\n      const continuation = await videoContinuationData.value.getContinuation()\n\n      latestVideos.value = latestVideos.value.concat(parseLocalChannelVideos(continuation.videos, id.value, channelName.value))\n      videoContinuationData.value = continuation.has_continuation ? continuation : null\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\n/**\n * @param {boolean} sortByChanged\n */\nasync function channelInvidiousVideos(sortByChanged = false) {\n  if (sortByChanged) {\n    videoContinuationData.value = null\n  }\n\n  let more = false\n  if (videoContinuationData.value) {\n    more = true\n  } else {\n    isElementListLoading.value = true\n  }\n\n  try {\n    const response = await getInvidiousChannelVideos(id.value, videoSortBy.value, videoContinuationData.value)\n    if (more) {\n      latestVideos.value = latestVideos.value.concat(response.videos)\n    } else {\n      latestVideos.value = response.videos\n    }\n    videoContinuationData.value = response.continuation || null\n    isElementListLoading.value = false\n\n    if (isSubscribedInAnyProfile.value && !more && latestVideos.value.length > 0 && videoSortBy.value === 'newest') {\n      store.dispatch('updateSubscriptionVideosCacheByChannel', {\n        channelId: id.value,\n        videos: latestVideos.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestShorts = shallowRef([])\nconst shortContinuationData = shallowRef(null)\nconst showShortSortBy = ref(true)\nconst shortSortBy = ref('newest')\n\nwatch(shortSortBy, () => {\n  if (!autoRefreshOnSortByChangeEnabled) { return }\n\n  isElementListLoading.value = true\n  latestShorts.value = []\n  shortContinuationData.value = null\n\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n    getChannelShortsLocal()\n  } else {\n    channelInvidiousShorts(true)\n  }\n})\n\nasync function getChannelShortsLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    let shortsTab = await channelInstance.getShorts()\n\n    showShortSortBy.value = shortsTab.filters.length > 1\n\n    if (showShortSortBy.value && shortSortBy.value !== 'newest') {\n      const index = videoLiveShortSelectValues.value.indexOf(shortSortBy.value)\n      shortsTab = await shortsTab.applyFilter(shortsTab.filters[index])\n    }\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    let parsedShorts\n\n    if (mayContainContentFromOtherChannels) {\n      parsedShorts = parseLocalChannelShorts(shortsTab.videos)\n    } else {\n      parsedShorts = parseLocalChannelShorts(shortsTab.videos, id.value, channelName.value)\n    }\n\n    latestShorts.value = parsedShorts\n    shortContinuationData.value = shortsTab.has_continuation ? shortsTab : null\n    isElementListLoading.value = false\n\n    if (isSubscribedInAnyProfile.value && latestShorts.value.length > 0 && shortSortBy.value === 'newest') {\n      // As the shorts tab API response doesn't include the published dates,\n      // we can't just write the results to the subscriptions cache like we do with videos and live (can't sort chronologically without the date).\n      // However we can still update the metadata in the cache such as the view count and title that might have changed since it was cached\n      store.dispatch('updateSubscriptionShortsCacheWithChannelPageShorts', {\n        channelId: id.value,\n        videos: latestShorts.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getChannelInfoInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelShortsLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation|import('youtubei.js').YT.FilteredChannelList}\n     */\n    const continuation = await shortContinuationData.value.getContinuation()\n\n    let parsedShorts\n\n    if (mayContainContentFromOtherChannels) {\n      parsedShorts = parseLocalChannelShorts(continuation.videos)\n    } else {\n      parsedShorts = parseLocalChannelShorts(continuation.videos, id.value, channelName.value)\n    }\n\n    latestShorts.value = latestShorts.value.concat(parsedShorts)\n    shortContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\n/**\n * @param {boolean} sortByChanged\n */\nasync function channelInvidiousShorts(sortByChanged = false) {\n  if (sortByChanged) {\n    shortContinuationData.value = null\n  }\n\n  let more = false\n  if (shortContinuationData.value) {\n    more = true\n  } else {\n    isElementListLoading.value = true\n  }\n\n  try {\n    const response = await getInvidiousChannelShorts(id.value, shortSortBy.value, shortContinuationData.value)\n    if (more) {\n      latestShorts.value = latestShorts.value.concat(response.videos)\n    } else {\n      latestShorts.value = response.videos\n    }\n    shortContinuationData.value = response.continuation || null\n    isElementListLoading.value = false\n\n    if (isSubscribedInAnyProfile.value && !more && latestShorts.value.length > 0 && shortSortBy.value === 'newest') {\n      // As the shorts tab API response doesn't include the published dates,\n      // we can't just write the results to the subscriptions cache like we do with videos and live (can't sort chronologically without the date).\n      // However we can still update the metadata in the cache e.g. adding the duration, as that isn't included in the RSS feeds\n      // and updating the view count and title that might have changed since it was cached\n      store.dispatch('updateSubscriptionShortsCacheWithChannelPageShorts', {\n        channelId: id.value,\n        videos: latestShorts.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestLive = shallowRef([])\nconst liveContinuationData = shallowRef(null)\nconst showLiveSortBy = ref(true)\nconst liveSortBy = ref('newest')\n\nwatch(liveSortBy, () => {\n  if (!autoRefreshOnSortByChangeEnabled) { return }\n\n  isElementListLoading.value = true\n  latestLive.value = []\n  liveContinuationData.value = null\n\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n    getChannelLiveLocal()\n  } else {\n    channelInvidiousLive(true)\n  }\n})\n\nasync function getChannelLiveLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    let liveTab = await channelInstance.getLiveStreams()\n\n    showLiveSortBy.value = liveTab.filters.length > 1\n\n    if (showLiveSortBy.value && liveSortBy.value !== 'newest') {\n      const index = videoLiveShortSelectValues.value.indexOf(liveSortBy.value)\n      liveTab = await liveTab.applyFilter(liveTab.filters[index])\n    }\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    // work around YouTube bug where it will return a bunch of responses with only continuations in them\n    // e.g. https://www.youtube.com/@TWLIVES/streams\n\n    let videos = liveTab.videos\n    while (videos.length === 0 && liveTab.has_continuation) {\n      liveTab = await liveTab.getContinuation()\n      videos = liveTab.videos\n    }\n\n    latestLive.value = parseLocalChannelVideos(videos, id.value, channelName.value)\n    liveContinuationData.value = liveTab.has_continuation ? liveTab : null\n    isElementListLoading.value = false\n\n    if (isSubscribedInAnyProfile.value && latestLive.value.length > 0 && liveSortBy.value === 'newest') {\n      store.dispatch('updateSubscriptionLiveCacheByChannel', {\n        channelId: id.value,\n        videos: latestLive.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getChannelInfoInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelLiveLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation|import('youtubei.js').YT.FilteredChannelList}\n     */\n    const continuation = await liveContinuationData.value.getContinuation()\n\n    latestLive.value = latestLive.value.concat(parseLocalChannelVideos(continuation.videos, id.value, channelName.value))\n    liveContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\n/**\n * @param {boolean} sortByChanged\n */\nasync function channelInvidiousLive(sortByChanged) {\n  if (sortByChanged) {\n    liveContinuationData.value = null\n  }\n\n  let more = false\n  if (liveContinuationData.value) {\n    more = true\n  } else {\n    isElementListLoading.value = true\n  }\n\n  try {\n    const response = await getInvidiousChannelLive(id.value, liveSortBy.value, liveContinuationData.value)\n    if (more) {\n      latestLive.value = latestLive.value.concat(response.videos)\n    } else {\n      latestLive.value = response.videos\n    }\n    liveContinuationData.value = response.continuation || null\n    isElementListLoading.value = false\n\n    if (isSubscribedInAnyProfile.value && !more && latestLive.value.length > 0 && liveSortBy.value === 'newest') {\n      store.dispatch('updateSubscriptionLiveCacheByChannel', {\n        channelId: id.value,\n        videos: latestLive.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestPlaylists = shallowRef([])\nconst playlistContinuationData = shallowRef(null)\nconst showPlaylistSortBy = ref(true)\nconst playlistSortBy = ref('newest')\n\nwatch(playlistSortBy, () => {\n  if (!autoRefreshOnSortByChangeEnabled) { return }\n\n  isElementListLoading.value = true\n  latestPlaylists.value = []\n  playlistContinuationData.value = null\n\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n    getChannelPlaylistsLocal()\n  } else {\n    getPlaylistsInvidious(true)\n  }\n})\n\nasync function getChannelPlaylistsLocal() {\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    let playlistsTab = await channelInstance.getPlaylists()\n\n    // some channels have more categories of playlists than just \"Created Playlists\" e.g. https://www.youtube.com/channel/UCez-2shYlHQY3LfILBuDYqQ\n    // for the moment we just want the \"Created Playlists\" category that has all playlists in it\n\n    if (playlistsTab.content_type_filters.length > 1) {\n      /**\n       * @type {import('youtubei.js').YTNodes.ChannelSubMenu}\n       */\n      const menu = playlistsTab.current_tab.content.sub_menu\n      const createdPlaylistsFilter = menu.content_type_sub_menu_items.find(contentType => {\n        const url = `https://youtube.com/${contentType.endpoint.metadata.url}`\n        return new URL(url).searchParams.get('view') === '1'\n      }).title\n\n      playlistsTab = await playlistsTab.applyContentTypeFilter(createdPlaylistsFilter)\n    }\n\n    // YouTube seems to allow the playlists tab to be sorted even if it only has one playlist\n    // as it doesn't make sense to sort a list with a single playlist in it, we'll hide the sort by element if there is a single playlist\n    showPlaylistSortBy.value = playlistsTab.sort_filters.length > 1 && playlistsTab.playlists.length > 1\n\n    if (showPlaylistSortBy.value && playlistSortBy.value !== 'newest') {\n      const index = PLAYLIST_SELECT_VALUES.indexOf(playlistSortBy.value)\n      playlistsTab = await playlistsTab.applySort(playlistsTab.sort_filters[index])\n    }\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    latestPlaylists.value = playlistsTab.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    playlistContinuationData.value = playlistsTab.has_continuation ? playlistsTab : null\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getPlaylistsInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelPlaylistsLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation}\n     */\n    const continuation = await playlistContinuationData.value.getContinuation()\n\n    const parsedPlaylists = continuation.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    latestPlaylists.value = latestPlaylists.value.concat(parsedPlaylists)\n    playlistContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function getPlaylistsInvidious() {\n  isElementListLoading.value = true\n\n  try {\n    const response = await getInvidiousChannelPlaylists(id.value, playlistSortBy.value)\n    playlistContinuationData.value = response.continuation || null\n    latestPlaylists.value = response.playlists\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getChannelPlaylistsLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getPlaylistsInvidiousMore() {\n  try {\n    const response = await getInvidiousChannelPlaylists(id.value, playlistSortBy.value, playlistContinuationData.value)\n    playlistContinuationData.value = response.continuation || null\n    latestPlaylists.value = latestPlaylists.value.concat(response.playlists)\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestReleases = shallowRef([])\nconst releaseContinuationData = shallowRef(null)\n\nasync function getChannelReleasesLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n    if (isArtistTopicChannel.value) {\n      const { releases, continuationData } = await getLocalArtistTopicChannelReleases(channelInstance)\n\n      if (expectedId !== id.value) {\n        return\n      }\n\n      latestReleases.value = releases\n      releaseContinuationData.value = continuationData\n    } else {\n      const releaseTab = await channelInstance.getReleases()\n\n      if (expectedId !== id.value) {\n        return\n      }\n\n      latestReleases.value = releaseTab.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n      releaseContinuationData.value = releaseTab.has_continuation ? releaseTab : null\n    }\n\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      channelInvidiousReleases()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelReleasesLocalMore() {\n  try {\n    if (isArtistTopicChannel.value) {\n      await ensureChannelInstance()\n\n      const { releases, continuationData } = await getLocalArtistTopicChannelReleasesContinuation(\n        channelInstance, releaseContinuationData.value\n      )\n\n      latestReleases.value = latestReleases.value.concat(releases)\n      releaseContinuationData.value = continuationData\n    } else {\n      /**\n       * @type {import('youtubei.js').YT.ChannelListContinuation}\n       */\n      const continuation = await releaseContinuationData.value.getContinuation()\n\n      const parsedReleases = continuation.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n      latestReleases.value = latestReleases.value.concat(parsedReleases)\n      releaseContinuationData.value = continuation.has_continuation ? continuation : null\n    }\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function channelInvidiousReleases() {\n  isElementListLoading.value = true\n\n  try {\n    const response = await getInvidiousChannelReleases(id.value)\n    releaseContinuationData.value = response.continuation || null\n    latestReleases.value = response.playlists\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getChannelReleasesLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function channelInvidiousReleasesMore() {\n  try {\n    const response = await getInvidiousChannelReleases(id.value, releaseContinuationData.value)\n    releaseContinuationData.value = response.continuation || null\n    latestReleases.value = latestReleases.value.concat(response.playlists)\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestPodcasts = shallowRef([])\nconst podcastContinuationData = shallowRef(null)\n\nasync function getChannelPodcastsLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    const podcastTab = await channelInstance.getPodcasts()\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    latestPodcasts.value = podcastTab.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    podcastContinuationData.value = podcastTab.has_continuation ? podcastTab : null\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      channelInvidiousPodcasts()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelPodcastsLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation}\n     */\n    const continuation = await podcastContinuationData.value.getContinuation()\n\n    const parsedPodcasts = continuation.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    latestPodcasts.value = latestPodcasts.value.concat(parsedPodcasts)\n    podcastContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function channelInvidiousPodcasts() {\n  isElementListLoading.value = true\n\n  try {\n    const response = await getInvidiousChannelPodcasts(id.value)\n    podcastContinuationData.value = response.continuation || null\n    latestPodcasts.value = response.playlists\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getChannelPodcastsLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function channelInvidiousPodcastsMore() {\n  try {\n    const response = await getInvidiousChannelPodcasts(id.value, podcastContinuationData.value)\n    podcastContinuationData.value = response.continuation || null\n    latestPodcasts.value = latestPodcasts.value.concat(response.playlists)\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestCourses = shallowRef([])\nconst coursesContinuationData = shallowRef(null)\n\nasync function getChannelCoursesLocal() {\n  isElementListLoading.value = true\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    const coursesTab = await channelInstance.getCourses()\n\n    if (expectedId !== id.value) {\n      return\n    }\n\n    latestCourses.value = coursesTab.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    coursesContinuationData.value = coursesTab.has_continuation ? coursesTab : null\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      channelInvidiousCourses()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getChannelCoursesLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation}\n     */\n    const continuation = await coursesContinuationData.value.getContinuation()\n\n    const parsedCourses = continuation.playlists.map(playlist => parseLocalListPlaylist(playlist, id.value, channelName.value))\n    latestCourses.value = latestCourses.value.concat(parsedCourses)\n    coursesContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function channelInvidiousCourses() {\n  isElementListLoading.value = true\n\n  try {\n    const response = await getInvidiousChannelCourses(id.value)\n    coursesContinuationData.value = response.continuation || null\n    latestCourses.value = response.playlists\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getChannelCoursesLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function channelInvidiousCoursesMore() {\n  try {\n    const response = await getInvidiousChannelCourses(id.value, coursesContinuationData.value)\n    coursesContinuationData.value = response.continuation || null\n    latestCourses.value = latestCourses.value.concat(response.playlists)\n    isElementListLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nconst latestCommunityPosts = shallowRef([])\nconst communityContinuationData = shallowRef(null)\n\nasync function getCommunityPostsLocal() {\n  const expectedId = id.value\n\n  try {\n    await ensureChannelInstance()\n\n    /**\n     * @type {import('youtubei.js').YT.Channel|import('youtubei.js').YT.ChannelListContinuation}\n     */\n    let communityTab = await channelInstance.getCommunity()\n    if (expectedId !== id.value) {\n      return\n    }\n\n    // work around YouTube bug where it will return a bunch of responses with only continuations in them\n    // e.g. https://www.youtube.com/@TheLinuxEXP/community\n\n    let posts = communityTab.posts\n    while (posts.length === 0 && communityTab.has_continuation) {\n      communityTab = await communityTab.getContinuation()\n      posts = communityTab.posts\n    }\n\n    latestCommunityPosts.value = parseLocalCommunityPosts(posts)\n    communityContinuationData.value = communityTab.has_continuation ? communityTab : null\n\n    if (latestCommunityPosts.value.length > 0) {\n      store.dispatch('updateSubscriptionPostsCacheByChannel', {\n        channelId: id.value,\n        posts: latestCommunityPosts.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      getCommunityPostsInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getCommunityPostsLocalMore() {\n  try {\n    /**\n     * @type {import('youtubei.js').YT.ChannelListContinuation}\n     */\n    let continuation = await communityContinuationData.value.getContinuation()\n\n    // work around YouTube bug where it will return a bunch of responses with only continuations in them\n    // e.g. https://www.youtube.com/@TheLinuxEXP/community\n    let posts = continuation.posts\n    while (posts.length === 0 && continuation.has_continuation) {\n      continuation = await continuation.getContinuation()\n      posts = continuation.posts\n    }\n\n    latestCommunityPosts.value = latestCommunityPosts.value.concat(parseLocalCommunityPosts(posts))\n    communityContinuationData.value = continuation.has_continuation ? continuation : null\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\nasync function getCommunityPostsInvidious() {\n  const more = !isNullOrEmpty(communityContinuationData.value)\n\n  try {\n    const { posts, continuation } = await invidiousGetCommunityPosts(id.value, communityContinuationData.value)\n    if (more) {\n      latestCommunityPosts.value = latestCommunityPosts.value.concat(posts)\n    } else {\n      latestCommunityPosts.value = posts\n    }\n    communityContinuationData.value = continuation\n\n    if (isSubscribedInAnyProfile.value && !more && latestCommunityPosts.value.length > 0) {\n      store.dispatch('updateSubscriptionPostsCacheByChannel', {\n        channelId: id.value,\n        posts: latestCommunityPosts.value\n      })\n    }\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      getCommunityPostsLocal()\n    }\n  }\n}\n\nlet searchPage = 1\nconst lastSearchQuery = ref('')\nconst searchResults = shallowRef([])\nconst searchContinuationData = shallowRef(null)\n\nasync function searchChannelLocal() {\n  const isNewSearch = searchContinuationData.value === null\n\n  try {\n    await ensureChannelInstance()\n\n    let result\n    let contents\n\n    if (isNewSearch) {\n      if (!channelInstance.has_search) {\n        showToast(t('Channel.This channel does not allow searching'), 5000)\n        showSearchBar.value = false\n        return\n      }\n      result = await channelInstance.search(lastSearchQuery.value)\n      contents = result.current_tab.content.contents\n    } else {\n      result = await searchContinuationData.value.getContinuation()\n      contents = result.contents.contents\n    }\n\n    const results = contents\n      .filter(node => node.type === 'ItemSection')\n      .flatMap(itemSection => itemSection.contents)\n      .filter(item => item.type === 'Video' || (!hideChannelPlaylists.value && item.type === 'Playlist'))\n      .map(item => {\n        if (item.type === 'Video') {\n          return parseLocalListVideo(item)\n        } else {\n          return parseLocalListPlaylist(item, id.value, channelName.value)\n        }\n      })\n\n    if (isNewSearch) {\n      searchResults.value = results\n    } else {\n      searchResults.value = searchResults.value.concat(results)\n    }\n\n    searchContinuationData.value = result.has_continuation ? result : null\n    isSearchTabLoading.value = false\n  } catch (err) {\n    console.error(err)\n    const errorMessage = t('Local API Error (Click to copy)')\n\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (isNewSearch) {\n      if (backendPreference.value === 'local' && backendFallback.value) {\n        showToast(t('Falling back to Invidious API'))\n        searchChannelInvidious()\n      } else {\n        isLoading.value = false\n      }\n    }\n  }\n}\n\nasync function searchChannelInvidious() {\n  try {\n    const response = await searchInvidiousChannel(id.value, lastSearchQuery.value, searchPage)\n\n    if (hideChannelPlaylists.value) {\n      searchResults.value = searchResults.value.concat(response.filter(item => item.type !== 'playlist'))\n    } else {\n      searchResults.value = searchResults.value.concat(response)\n    }\n\n    isSearchTabLoading.value = false\n    searchPage++\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      searchChannelLocal()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\n/**\n * @param {string} query\n */\nfunction newSearch(query) {\n  lastSearchQuery.value = query\n  searchContinuationData.value = null\n  isSearchTabLoading.value = true\n  searchPage = 1\n  searchResults.value = []\n  changeTab('search')\n\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n    searchChannelLocal()\n  } else {\n    searchChannelInvidious()\n  }\n}\n\n/**\n * @param {string} query\n */\nfunction newSearchWithStatePersist(query) {\n  saveStateInRouter(query)\n  newSearch(query)\n}\n\nasync function saveStateInRouter(query) {\n  skipRouteChangeWatcherOnce = true\n\n  let location\n\n  if (query === '') {\n    location = { path: `/channel/${id.value}` }\n  } else {\n    location = {\n      path: `/channel/${id.value}`,\n      params: {\n        currentTab: 'search',\n      },\n      query: {\n        searchQueryText: query,\n      }\n    }\n  }\n\n  try {\n    await router.replace(location)\n  } catch (failure) {\n    if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n      return\n    }\n\n    throw failure\n  }\n\n  skipRouteChangeWatcherOnce = false\n}\n\n/**\n * @param {string} message\n * @param {boolean} responseHasNameAndThumbnail\n */\nfunction setErrorMessage(message, responseHasNameAndThumbnail = false) {\n  isLoading.value = false\n  errorMessage.value = message\n\n  if (!responseHasNameAndThumbnail) {\n    channelName.value = subscriptionInfo.value?.name\n    thumbnailUrl.value = subscriptionInfo.value?.thumbnail\n  }\n\n  bannerUrl.value = null\n  subCount.value = null\n}\n\nconst showFetchMoreButton = computed(() => {\n  switch (currentTab.value) {\n    case 'videos':\n      return !isNullOrEmpty(videoContinuationData.value)\n    case 'shorts':\n      return !isNullOrEmpty(shortContinuationData.value)\n    case 'live':\n      return !isNullOrEmpty(liveContinuationData.value)\n    case 'releases':\n      return !isNullOrEmpty(releaseContinuationData.value)\n    case 'podcasts':\n      return !isNullOrEmpty(podcastContinuationData.value)\n    case 'courses':\n      return !isNullOrEmpty(coursesContinuationData.value)\n    case 'playlists':\n      return !isNullOrEmpty(playlistContinuationData.value)\n    case 'community':\n      return !isNullOrEmpty(communityContinuationData.value)\n    case 'search':\n      return !isNullOrEmpty(searchContinuationData.value)\n    default:\n      return false\n  }\n})\n\nfunction handleFetchMore() {\n  switch (currentTab.value) {\n    case 'videos':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelVideosLocalMore()\n      } else {\n        channelInvidiousVideos()\n      }\n      break\n    case 'shorts':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelShortsLocalMore()\n      } else {\n        channelInvidiousShorts()\n      }\n      break\n    case 'live':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelLiveLocalMore()\n      } else {\n        channelInvidiousLive()\n      }\n      break\n    case 'releases':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelReleasesLocalMore()\n      } else {\n        channelInvidiousReleasesMore()\n      }\n      break\n    case 'podcasts':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelPodcastsLocalMore()\n      } else {\n        channelInvidiousPodcastsMore()\n      }\n      break\n    case 'courses':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelCoursesLocalMore()\n      } else {\n        channelInvidiousCoursesMore()\n      }\n      break\n    case 'playlists':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getChannelPlaylistsLocalMore()\n      } else {\n        getPlaylistsInvidiousMore()\n      }\n      break\n    case 'search':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        searchChannelLocal()\n      } else {\n        searchChannelInvidious()\n      }\n      break\n    case 'community':\n      if (process.env.SUPPORTS_LOCAL_API && apiUsed === 'local') {\n        getCommunityPostsLocalMore()\n      } else {\n        getCommunityPostsInvidious()\n      }\n      break\n    default:\n      console.error(currentTab.value)\n  }\n}\n\nfunction changeTab(tab) {\n  // `newTabNode` can be `null` when `tab` === \"search\"\n  const newTabNode = document.getElementById(`${tab}Tab`)\n  currentTab.value = tab\n\n  if (newTabNode != null) {\n    newTabNode.focus()\n    store.commit('setOutlinesHidden', false)\n  }\n}\n\nfunction handleSubscription() {\n  // We can't cache the shorts data as YouTube doesn't return published dates on the shorts channel tab\n\n  if (videoSortBy.value === 'newest') {\n    store.dispatch('updateSubscriptionVideosCacheByChannel', {\n      channelId: id.value,\n      videos: latestVideos.value\n    })\n  }\n\n  if (liveSortBy.value === 'newest') {\n    store.dispatch('updateSubscriptionLiveCacheByChannel', {\n      channelId: id.value,\n      videos: latestLive.value\n    })\n  }\n\n  store.dispatch('updateSubscriptionPostsCacheByChannel', {\n    channelId: id.value,\n    posts: latestCommunityPosts.value\n  })\n}\n\nfunction filterWatchedArray(videos) {\n  const historyCache = store.getters.getHistoryCacheById\n  return videos.filter(video => historyCache[video.videoId] === undefined)\n}\n</script>\n\n<style scoped src=\"./Channel.css\" />\n"
  },
  {
    "path": "src/renderer/views/Hashtag/Hashtag.css",
    "content": ".getNextPage {\n  background-color: var(--search-bar-color);\n  inline-size: 100%;\n  block-size: 45px;\n  line-height: 45px;\n  text-align: center;\n  cursor: pointer;\n  margin-block-start: 16px;\n}\n\n.getNextPage:hover,\n.getNextPage:focus {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n}\n\n.card {\n  margin-block: 0 20px;\n  margin-inline: auto;\n  inline-size: 85%;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Hashtag/Hashtag.vue",
    "content": "<template>\n  <div>\n    <FtLoader\n      v-if=\"isLoading\"\n      :fullscreen=\"true\"\n    />\n    <FtCard\n      v-else\n      class=\"card\"\n    >\n      <h2>\n        <font-awesome-icon\n          :icon=\"['fas', 'hashtag']\"\n          aria-hidden=\"false\"\n          class=\"headingIcon\"\n        />\n        <bdi>{{ hashtag }}</bdi>\n      </h2>\n      <FtElementList\n        v-if=\"videos.length > 0\"\n        :data=\"videos\"\n      />\n      <FtFlexBox\n        v-else\n      >\n        <p\n          class=\"message\"\n        >\n          {{ $t(\"Hashtag.This hashtag does not currently have any videos\") }}\n        </p>\n      </FtFlexBox>\n\n      <FtAutoLoadNextPageWrapper\n        v-if=\"showFetchMoreButton\"\n        @load-next-page=\"handleFetchMore\"\n      >\n        <div\n          class=\"getNextPage\"\n          role=\"button\"\n          tabindex=\"0\"\n          @click=\"handleFetchMore\"\n          @keydown.space.prevent=\"handleFetchMore\"\n          @keydown.enter.prevent=\"handleFetchMore\"\n        >\n          <FontAwesomeIcon :icon=\"['fas', 'search']\" /> {{ $t(\"Search Filters.Fetch more results\") }}\n        </div>\n      </FtAutoLoadNextPageWrapper>\n    </FtCard>\n  </div>\n</template>\n<script setup>\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\nimport store from '../../store/index'\nimport { useRoute } from 'vue-router'\nimport packageDetails from '../../../../package.json'\nimport { getHashtagLocal, parseLocalListVideo } from '../../helpers/api/local'\nimport { copyToClipboard, showToast } from '../../helpers/utils'\nimport { isNullOrEmpty } from '../../helpers/strings'\nimport { getHashtagInvidious } from '../../helpers/api/invidious'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nconst { t } = useI18n()\n\nconst route = useRoute()\n\nconst hashtag = ref('')\nconst hashtagContinuationData = shallowRef(null)\nconst videos = shallowRef([])\n/** @type {import('vue').Ref<'local' | 'invidious'>} */\nconst apiUsed = ref('local')\nconst pageNumber = ref(1)\nconst isLoading = ref(true)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => {\n  return store.getters.getBackendFallback\n})\n\nconst showFetchMoreButton = computed(() => {\n  return !isNullOrEmpty(hashtagContinuationData.value) || apiUsed.value === 'invidious'\n})\n\nonMounted(() => {\n  getHashtag()\n})\n\nwatch(() => route.params.hashtag, () => {\n  resetData()\n  getHashtag()\n})\n\nfunction resetData() {\n  isLoading.value = true\n  hashtag.value = ''\n  hashtagContinuationData.value = null\n  videos.value = []\n  apiUsed.value = 'local'\n  pageNumber.value = 1\n}\n\nasync function getHashtag() {\n  hashtag.value = decodeURIComponent(route.params.hashtag)\n  if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'local') {\n    await getLocalHashtag()\n  } else {\n    await getInvidiousHashtag()\n  }\n  store.commit('setAppTitle', `#${hashtag.value} - ${packageDetails.productName}`)\n}\n\n/**\n * @param {number} page\n */\nasync function getInvidiousHashtag(page = 1) {\n  try {\n    const fetchedVideos = await getHashtagInvidious(hashtag.value, page)\n    isLoading.value = false\n    apiUsed.value = 'invidious'\n    videos.value = videos.value.concat(fetchedVideos)\n    pageNumber.value += 1\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      resetData()\n      getLocalHashtag()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getLocalHashtag() {\n  try {\n    const hashtagData = await getHashtagLocal(hashtag.value)\n    videos.value = hashtagData.videos.map((video) => parseLocalListVideo(video))\n    apiUsed.value = 'local'\n    hashtagContinuationData.value = hashtagData.has_continuation ? hashtagData : null\n    isLoading.value = false\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      resetData()\n      getInvidiousHashtag()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getLocalHashtagMore() {\n  try {\n    const continuation = await hashtagContinuationData.value.getContinuation()\n    const newVideos = continuation.videos.map((video) => parseLocalListVideo(video))\n    hashtagContinuationData.value = continuation.has_continuation ? continuation : null\n    videos.value = videos.value.concat(newVideos)\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      resetData()\n      getInvidiousHashtag()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nfunction handleFetchMore() {\n  if (process.env.SUPPORTS_LOCAL_API && apiUsed.value === 'local') {\n    getLocalHashtagMore()\n  } else if (apiUsed.value === 'invidious') {\n    getInvidiousHashtag(pageNumber.value)\n  }\n}\n</script>\n<style scoped src=\"./Hashtag.css\" />\n"
  },
  {
    "path": "src/renderer/views/History/History.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.optionsRow {\n  display: grid;\n  grid-template-columns: repeat(2, 1fr);\n  grid-template-rows: 1fr;\n  align-items: center;\n}\n\n@media only screen and (width <= 800px) {\n  .optionsRow {\n    /* Switch to 2 rows from 2 columns */\n    grid-template-columns: auto;\n    grid-template-rows: auto auto;\n    align-items: stretch;\n  }\n}\n\n.sortSelect {\n  /* Put it on the right */\n  margin-inline-start: auto;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/History/History.vue",
    "content": "<template>\n  <div>\n    <FtCard\n      class=\"card\"\n    >\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'history']\"\n          class=\"headingIcon\"\n        />\n        {{ t('History.History') }}\n      </h2>\n      <FtInput\n        v-show=\"fullData.length > 1\"\n        ref=\"searchBar\"\n        :placeholder=\"t('History.Search bar placeholder')\"\n        :show-clear-text-button=\"true\"\n        :show-action-button=\"false\"\n        :value=\"query\"\n        @input=\"handleQueryChange\"\n        @clear=\"() => handleQueryChange('')\"\n      />\n      <div\n        class=\"optionsRow\"\n      >\n        <FtToggleSwitch\n          v-if=\"fullData.length > 1\"\n          :label=\"t('History.Case Sensitive Search')\"\n          :compact=\"true\"\n          :default-value=\"doCaseSensitiveSearch\"\n          @change=\"doCaseSensitiveSearch = !doCaseSensitiveSearch\"\n        />\n        <FtSelect\n          v-if=\"fullData.length > 1\"\n          class=\"sortSelect\"\n          :placeholder=\"t('Global.Sort By')\"\n          :value=\"sortBy\"\n          :select-names=\"sortByNames\"\n          :select-values=\"SORT_BY_VALUES\"\n          :icon=\"sortByIcon\"\n          @change=\"updateUserHistorySortBy\"\n        />\n      </div>\n      <FtFlexBox\n        v-if=\"fullData.length === 0\"\n      >\n        <p class=\"message\">\n          {{ t(\"History['Your history list is currently empty.']\") }}\n        </p>\n      </FtFlexBox>\n      <FtFlexBox\n        v-else-if=\"activeData.length === 0\"\n      >\n        <p class=\"message\">\n          {{ t(\"History['Empty Search Message']\") }}\n        </p>\n      </FtFlexBox>\n      <FtElementList\n        v-if=\"activeData.length > 0\"\n        :data=\"activeData\"\n        :show-video-with-last-viewed-playlist=\"true\"\n        :use-channels-hidden-preference=\"false\"\n        :hide-forbidden-titles=\"false\"\n      />\n      <FtAutoLoadNextPageWrapper\n        v-if=\"showLoadMoreButton\"\n        @load-next-page=\"increaseLimit\"\n      >\n        <FtFlexBox>\n          <FtButton\n            :label=\"t('Subscriptions.Load More Videos')\"\n            background-color=\"var(--primary-color)\"\n            text-color=\"var(--text-with-main-color)\"\n            @click=\"increaseLimit\"\n          />\n        </FtFlexBox>\n      </FtAutoLoadNextPageWrapper>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { isNavigationFailure, NavigationFailureType, useRoute, useRouter } from 'vue-router'\n\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\nimport FtButton from '../../components/FtButton/FtButton.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtInput from '../../components/FtInput/FtInput.vue'\nimport FtSelect from '../../components/FtSelect/FtSelect.vue'\nimport FtToggleSwitch from '../../components/FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../../store'\n\nimport { ctrlFHandler, debounce, getIconForSortPreference } from '../../helpers/utils'\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst oldDataLimit = sessionStorage.getItem('History/dataLimit')\nconst dataLimit = ref(oldDataLimit !== null ? parseInt(oldDataLimit) : 100)\n\nconst searchDataLimit = ref(100)\nconst doCaseSensitiveSearch = ref(false)\nconst showLoadMoreButton = ref(false)\nconst query = ref('')\nconst activeData = ref([])\n\nconst HISTORY_SORT_BY_VALUES = {\n  DateAddedNewest: 'latest_played_first',\n  DateAddedOldest: 'earliest_played_first',\n}\n\nconst SORT_BY_VALUES = Object.values(HISTORY_SORT_BY_VALUES)\n\nconst sortByNames = computed(() => [\n  t('History.DateNewestHistory'),\n  t('History.DateOldestHistory')\n])\n\n/** @type {import('vue').ComputedRef<'latest_played_first' | 'earliest_played_first'>} */\nconst sortBy = computed(() => store.getters.getUserHistorySortBy)\n\nconst sortByIcon = computed(() => getIconForSortPreference(sortBy.value))\n\n/**\n * @param {'latest_played_first' | 'earliest_played_first'} value\n */\nfunction updateUserHistorySortBy(value) {\n  store.dispatch('updateUserHistorySortBy', value)\n}\n\nconst historyCacheSorted = computed(() => {\n  const historySorted = store.getters.getHistoryCacheSorted\n\n  if (sortBy.value === HISTORY_SORT_BY_VALUES.DateAddedOldest) {\n    return historySorted.toReversed()\n  } else {\n    return historySorted\n  }\n})\n\nconst fullData = computed(() => {\n  if (historyCacheSorted.value.length < dataLimit.value) {\n    return historyCacheSorted.value\n  } else {\n    return historyCacheSorted.value.slice(0, dataLimit.value)\n  }\n})\n\nwatch(fullData, filterHistory, { deep: true })\nwatch(doCaseSensitiveSearch, () => {\n  filterHistory()\n  saveStateInRouter()\n})\n\n/**\n * @param {string} query_\n * @param {string} [limit]\n * @param {boolean} [doCaseSensitiveSearch_]\n * @param {boolean} [filterNow=false]\n */\nfunction handleQueryChange(query_, limit = undefined, doCaseSensitiveSearch_ = undefined, filterNow = false) {\n  query.value = query_\n\n  let newLimit = 100\n\n  if (limit !== undefined) {\n    const parsedLimit = parseInt(limit)\n\n    if (!isNaN(parsedLimit)) {\n      newLimit = parsedLimit\n    }\n  }\n\n  searchDataLimit.value = newLimit\n\n  if (doCaseSensitiveSearch_ !== undefined) {\n    doCaseSensitiveSearch.value = doCaseSensitiveSearch_\n  }\n\n  saveStateInRouter()\n\n  if (filterNow) {\n    filterHistory()\n  } else {\n    filterHistoryAsync()\n  }\n}\n\nfunction increaseLimit() {\n  if (query.value.length > 0) {\n    searchDataLimit.value += 100\n    filterHistory()\n  } else {\n    dataLimit.value += 100\n    sessionStorage.setItem('History/dataLimit', dataLimit.value.toFixed(0))\n  }\n}\n\nfunction filterHistory() {\n  if (query.value.length === 0) {\n    activeData.value = fullData.value\n    showLoadMoreButton.value = activeData.value.length < historyCacheSorted.value.length\n    return\n  }\n\n  let filteredQuery\n  if (doCaseSensitiveSearch.value) {\n    filteredQuery = filterVideosWithQuery(historyCacheSorted.value, query.value)\n  } else {\n    filteredQuery = filterVideosWithQuery(historyCacheSorted.value, query.value.toLowerCase(), (s) => s.toLowerCase())\n  }\n\n  activeData.value = filteredQuery.length < searchDataLimit.value ? filteredQuery : filteredQuery.slice(0, searchDataLimit.value)\n  showLoadMoreButton.value = activeData.value.length > searchDataLimit.value\n}\n\nconst filterHistoryAsync = debounce(filterHistory, 500)\n\nasync function saveStateInRouter() {\n  const query_ = query.value\n\n  let location\n\n  if (query_.length === 0) {\n    location = { path: '/history' }\n  } else {\n    location = {\n      path: '/history',\n      query: {\n        searchQueryText: query_,\n        searchDataLimit: searchDataLimit.value.toFixed(0)\n      }\n    }\n\n    if (doCaseSensitiveSearch.value) {\n      location.query.doCaseSensitiveSearch = 'true'\n    }\n  }\n\n  try {\n    await router.replace(location)\n  } catch (failure) {\n    if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n      return\n    }\n\n    throw failure\n  }\n}\n\nconst oldQuery = route.query.searchQueryText\nif (oldQuery != null && oldQuery !== '') {\n  // `handleQueryChange` must be called after `filterHistoryDebounce` assigned\n  handleQueryChange(\n    oldQuery,\n    route.query.searchDataLimit,\n    route.query.doCaseSensitiveSearch === 'true',\n    true\n  )\n} else {\n  // Only display unfiltered data when no query used last time\n  filterHistory()\n}\n\nconst searchBar = useTemplateRef('searchBar')\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchBar.value)\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n\nconst identity = (v) => v\n\n/**\n * @param {any[]} videos\n * @param {string} query\n * @param {(attr: string) => string} attrProcessor\n */\nfunction filterVideosWithQuery(videos, query, attrProcessor = identity) {\n  return videos.filter((video) => {\n    if (typeof (video.title) === 'string' && attrProcessor(video.title).includes(query)) {\n      return true\n    } else if (typeof (video.author) === 'string' && attrProcessor(video.author).includes(query)) {\n      return true\n    }\n\n    return false\n  })\n}\n</script>\n\n<style scoped src=\"./History.css\" />\n"
  },
  {
    "path": "src/renderer/views/Playlist/Playlist.scss",
    "content": "@use '../../scss-partials/utils';\n\n.playlistItemsCard {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n  margin: 0;\n}\n\n.playlistInfoContainer {\n  box-sizing: border-box;\n\n  /* This is needed to make prompt always above video entries. Value being too high would block search suggestions */\n  z-index: 1;\n\n  &.promptOpen {\n    z-index: 200;\n    // Otherwise sidebar would be above the prompt\n  }\n}\n\n.routerView {\n  display: flex;\n\n  &.grid {\n    flex-direction: column;\n\n    &.hasNoPlaylistDescription {\n      --top-bar-push-down-adjustment-no-description: 19px;\n    }\n\n    &.playlistInEditMode {\n      --top-bar-push-down-adjustment-edit-mode: 85px;\n      --top-bar-push-down-adjustment-no-description: 11px;\n    }\n\n    &.oneOrFewer {\n      --top-bar-push-down-adjustment-one-or-fewer: -62px;\n    }\n\n    .playlistInfoContainer {\n      position: sticky;\n      margin-block: -35px 16px;\n      inset-block-start: calc(var(--top-bar-push-down-adjustment-default) + var(--top-bar-push-down-adjustment-edit-mode) + var(--top-bar-push-down-adjustment-no-description) + var(--top-bar-push-down-adjustment-one-or-fewer));\n      padding-block: 0;\n      margin-inline: auto;\n      padding-inline: 16px;\n      box-sizing: content-box;\n      inline-size: 85%;\n      background-color: var(--card-bg-color);\n      box-shadow: 0 2px 1px 0 var(--primary-shadow-color);\n\n      /* video progress bar has z-index 2 and this must be above it */\n      z-index: 3;\n\n      .playlistInfo {\n        padding-block: 10px;\n        padding-inline: 16px;\n      }\n    }\n\n    .playlistItemsCard {\n      inline-size: 85%;\n      margin-block: 0 60px;\n      margin-inline: auto;\n    }\n  }\n\n  &.list {\n    gap: 1em;\n\n    .playlistInfoContainer {\n      background-color: var(--card-bg-color);\n      block-size: calc(100vh - 132px);\n      inline-size: 30%;\n      inset-block-start: 96px;\n      position: sticky;\n\n      .playlistInfo {\n        padding: 10px;\n      }\n    }\n\n    .playlistItemsCard {\n      inline-size: 60%;\n      padding: 10px;\n    }\n  }\n}\n\n\n.playlistItem {\n  display: grid;\n  grid-template-columns: 30px 1fr;\n  column-gap: 8px;\n  align-items: center;\n}\n\n.playlistItem-move,\n.playlistItem-enter-active,\n.playlistItem-leave-active {\n  transition: all 0.2s ease;\n\n  // Hide action buttons during transitions\n  // The class for icon container is mainly styled in `ft-list-item.scss`\n  // But the transition related classes are all on container elements\n  // So `:deep` is used\n  :deep(.ft-list-item .videoThumbnail .playlistIcons) {\n    display: none;\n  }\n  // Prevent link click\n  :deep(.ft-list-item .videoThumbnail .thumbnailLink) {\n    // https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events\n    pointer-events: none;\n  }\n}\n\n.playlistItem-enter,\n.playlistItem-leave-to {\n  opacity: 0;\n  transform: translate(calc(10% * var(--horizontal-directionality-coefficient)));\n}\n\n.loadNextPageWrapper {\n  /* about the same height as the button */\n  max-block-size: 7vh;\n}\n\n.sortSelect {\n  /* Put it on the right and align with 'More Options' dropdown button */\n  margin-inline: auto 20px;\n}\n\n:deep(.videoThumbnail) {\n  margin-block: auto;\n}\n\n@media only screen and (width <= 850px) {\n  .routerView {\n    flex-direction: column;\n\n    &.list {\n      gap: 0;\n\n      .playlistInfoContainer {\n        box-sizing: border-box;\n        position: relative;\n        inset-block-start: 0;\n        block-size: auto;\n        inline-size: 100%;\n        // Reset margin\n        margin-inline-end: 0;\n      }\n\n      .playlistItemsCard {\n        box-sizing: border-box;\n        inline-size: 100%;\n      }\n    }\n  }\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n"
  },
  {
    "path": "src/renderer/views/Playlist/Playlist.vue",
    "content": "<template>\n  <div\n    :class=\"{\n      [listType]: true,\n      playlistInEditMode,\n      hasNoPlaylistDescription: !playlistDescription,\n      oneOrFewer: shownVideoCount < 2\n    }\"\n    class=\"playlistPage\"\n  >\n    <FtLoader\n      v-if=\"isLoading\"\n      :fullscreen=\"true\"\n    />\n    <div\n      v-if=\"!isLoading\"\n      class=\"playlistInfoContainer\"\n      :class=\"{\n        promptOpen,\n      }\"\n    >\n      <PlaylistInfo\n        :id=\"playlistId\"\n        :first-video-id=\"firstVideoId\"\n        :first-video-playlist-item-id=\"firstVideoPlaylistItemId\"\n        :playlist-thumbnail=\"playlistThumbnail\"\n        :title=\"playlistTitle\"\n        :channel-name=\"channelName\"\n        :channel-thumbnail=\"channelThumbnail\"\n        :channel-id=\"channelId\"\n        :last-updated=\"lastUpdated\"\n        :description=\"playlistDescription\"\n        :video-count=\"shownVideoCount\"\n        :videos=\"shownPlaylistItems\"\n        :sorted-videos=\"sortedPlaylistItems\"\n        :view-count=\"viewCount\"\n        :total-playlist-duration=\"totalPlaylistDuration\"\n        :is-duration-approximate=\"isDurationApproximate\"\n        :info-source=\"infoSource\"\n        :more-video-data-available=\"moreVideoDataAvailable\"\n        :search-video-mode-allowed=\"isUserPlaylistRequested && shownVideoCount > 1\"\n        :search-query-text=\"searchQueryTextRequested\"\n        :theme=\"listType === 'list' ? 'base' : 'top-bar'\"\n        class=\"playlistInfo\"\n        @enter-edit-mode=\"playlistInEditMode = true\"\n        @exit-edit-mode=\"playlistInEditMode = false\"\n        @search-video-query-change=\"handleVideoSearchQueryChange\"\n        @prompt-open=\"promptOpen = true\"\n        @prompt-close=\"promptOpen = false\"\n      />\n    </div>\n\n    <FtCard\n      v-if=\"!isLoading\"\n      class=\"playlistItemsCard\"\n    >\n      <template\n        v-if=\"shownPlaylistItems.length > 0\"\n      >\n        <FtSelect\n          v-if=\"isUserPlaylistRequested && shownPlaylistItems.length > 1\"\n          class=\"sortSelect\"\n          :value=\"sortOrder\"\n          :select-names=\"sortBySelectNames\"\n          :select-values=\"SORT_BY_SELECT_VALUES\"\n          :placeholder=\"t('Global.Sort By')\"\n          :icon=\"sortOrderIcon\"\n          @change=\"updateUserPlaylistSortOrder\"\n        />\n        <template\n          v-if=\"visiblePlaylistItems.length > 0\"\n        >\n          <FtElementList\n            v-if=\"listType === 'grid'\"\n            :data=\"visiblePlaylistItems\"\n            display=\"grid\"\n            :playlist-id=\"playlistId\"\n            :playlist-type=\"infoSource\"\n            :show-video-with-last-viewed-playlist=\"true\"\n            :use-channels-hidden-preference=\"false\"\n            :hide-forbidden-titles=\"false\"\n            :always-show-add-to-playlist-button=\"true\"\n            :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n            :can-move-video-up=\"canMoveVideos\"\n            :can-move-video-down=\"canMoveVideos\"\n            :playlist-items-length=\"shownPlaylistItems.length\"\n            :can-remove-from-playlist=\"true\"\n            @move-video-up=\"moveVideoUp\"\n            @move-video-down=\"moveVideoDown\"\n            @remove-from-playlist=\"removeVideoFromPlaylist\"\n          />\n          <TransitionGroup\n            v-else\n            name=\"playlistItem\"\n            tag=\"span\"\n            class=\"playlistItems\"\n          >\n            <FtListVideoNumbered\n              v-for=\"(item, index) in visiblePlaylistItems\"\n              :key=\"`${item.videoId}-${item.playlistItemId || index}`\"\n              class=\"playlistItem\"\n              :data=\"item\"\n              :playlist-id=\"playlistId\"\n              :playlist-type=\"infoSource\"\n              :playlist-index=\"playlistInVideoSearchMode ? shownPlaylistItems.findIndex(i => i === item) : index\"\n              :playlist-item-id=\"item.playlistItemId\"\n              appearance=\"result\"\n              :always-show-add-to-playlist-button=\"true\"\n              :quick-bookmark-button-enabled=\"quickBookmarkButtonEnabled\"\n              :can-move-video-up=\"index > 0 && canMoveVideos\"\n              :can-move-video-down=\"index < shownPlaylistItems.length - 1 && canMoveVideos\"\n              :can-remove-from-playlist=\"true\"\n              :video-index=\"playlistInVideoSearchMode ? shownPlaylistItems.findIndex(i => i === item) : index\"\n              :initial-visible-state=\"index < 10\"\n              @move-video-up=\"moveVideoUp\"\n              @move-video-down=\"moveVideoDown\"\n              @remove-from-playlist=\"removeVideoFromPlaylist\"\n            />\n          </TransitionGroup>\n          <FtAutoLoadNextPageWrapper\n            v-if=\"moreVideoDataAvailable && !isLoadingMore\"\n            @load-next-page=\"getNextPage\"\n          >\n            <FtFlexBox>\n              <FtButton\n                :label=\"t('Subscriptions.Load More Videos')\"\n                background-color=\"var(--primary-color)\"\n                text-color=\"var(--text-with-main-color)\"\n                @click=\"getNextPage\"\n              />\n            </FtFlexBox>\n          </FtAutoLoadNextPageWrapper>\n          <div\n            v-if=\"isLoadingMore\"\n            class=\"loadNextPageWrapper\"\n          >\n            <FtLoader />\n          </div>\n        </template>\n        <FtFlexBox\n          v-else\n        >\n          <p class=\"message\">\n            {{ t(\"User Playlists['Empty Search Message']\") }}\n          </p>\n        </FtFlexBox>\n      </template>\n      <FtFlexBox\n        v-else\n      >\n        <p class=\"message\">\n          {{ t(\"User Playlists['This playlist currently has no videos.']\") }}\n        </p>\n      </FtFlexBox>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { isNavigationFailure, NavigationFailureType, onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'\n\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport PlaylistInfo from '../../components/PlaylistInfo/PlaylistInfo.vue'\nimport FtListVideoNumbered from '../../components/FtListVideoNumbered/FtListVideoNumbered.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtButton from '../../components/FtButton/FtButton.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtSelect from '../../components/FtSelect/FtSelect.vue'\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\n\nimport store from '../../store/index'\n\nimport {\n  extractLocalCacheablePlaylistContinuation,\n  getLocalPlaylist,\n  getLocalPlaylistContinuation,\n  parseLocalPlaylistVideo,\n} from '../../helpers/api/local'\nimport {\n  debounce,\n  extractNumberFromString,\n  getIconForSortPreference,\n  showToast,\n  deepCopy,\n} from '../../helpers/utils'\nimport { invidiousGetPlaylistInfo, youtubeImageUrlToInvidious } from '../../helpers/api/invidious'\nimport { getSortedPlaylistItems, videoDurationPresent, videoDurationWithFallback, SORT_BY_VALUES } from '../../helpers/playlists'\nimport packageDetails from '../../../../package.json'\nimport { MOBILE_WIDTH_THRESHOLD, PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD } from '../../../constants'\n\nconst { locale, t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst isLoading = ref(true)\nconst playlistTitle = ref('')\nconst playlistDescription = ref('')\nconst firstVideoId = ref('')\nconst firstVideoPlaylistItemId = ref('')\nconst playlistThumbnail = ref('')\nconst viewCount = ref(0)\nconst videoCount = ref(0)\n/** @type {import('vue').Ref<string | undefined>} */\nconst lastUpdated = ref(undefined)\nconst channelName = ref('')\nconst channelThumbnail = ref('')\nconst channelId = ref('')\nconst infoSource = ref('local')\nconst playlistItems = ref([])\nconst userPlaylistVisibleLimit = ref(100)\n/** @type {import('vue').ShallowRef<import('youtubei.js').YT.Playlist | null>} */\nconst continuationData = shallowRef(null)\nconst isLoadingMore = ref(false)\nconst playlistInEditMode = ref(false)\nconst forceListView = ref(false)\nlet alreadyShownNotice = false\nconst videoSearchQuery = ref('')\nconst promptOpen = ref(false)\n/** @type {import('vue').Ref<string[]>} */\nconst toBeDeletedPlaylistItemIds = ref([])\n/** @type {AbortController | null} */\nlet undoToastAbortController = null\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => store.getters.getCurrentInvidiousInstanceUrl)\n\n/** @type {import('vue').ComputedRef<string>} */\nconst userPlaylistSortOrder = computed(() => store.getters.getUserPlaylistSortOrder)\n\nconst sortOrder = computed(() => isUserPlaylistRequested.value ? userPlaylistSortOrder.value : SORT_BY_VALUES.Custom)\n\nconst playlistId = computed(() => route.params.id)\n\n/** @type {import('vue').ComputedRef<'grid' | 'list'>} */\nconst listType = computed(() => isUserPlaylistRequested.value && !forceListView.value ? store.getters.getListType : 'list')\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst userPlaylistsReady = computed(() => store.getters.getPlaylistsReady)\n\nconst selectedUserPlaylist = computed(() => {\n  const playlistId_ = playlistId.value\n\n  if (\n    !isUserPlaylistRequested.value ||\n    playlistId_ == null ||\n    playlistId_ === ''\n  ) {\n    return null\n  }\n\n  return store.getters.getPlaylist(playlistId_)\n})\n\n/** @type {import('vue').ComputedRef<number | undefined>} */\nconst selectedUserPlaylistLastUpdatedAt = computed(() => selectedUserPlaylist.value?.lastUpdatedAt)\n\n/** @type {import('vue').ComputedRef<any[]>} */\nconst selectedUserPlaylistVideos = computed(() => selectedUserPlaylist.value?.videos ?? [])\n\nconst selectedUserPlaylistVideoCount = computed(() => selectedUserPlaylistVideos.value.length)\n\nconst moreVideoDataAvailable = computed(() => {\n  return isUserPlaylistRequested.value\n    ? userPlaylistVisibleLimit.value < sometimesFilteredUserPlaylistItems.value.length\n    : continuationData.value !== null\n})\n\nconst processedVideoSearchQuery = computed(() => videoSearchQuery.value.trim().toLowerCase())\n\nconst playlistInVideoSearchMode = computed(() => processedVideoSearchQuery.value !== '')\n\n/** @type {import('vue').ComputedRef<string>} */\nconst searchQueryTextRequested = computed(() => route.query.searchQueryText ?? '')\nconst searchQueryTextPresent = computed(() => {\n  const searchQueryText = searchQueryTextRequested.value\n  return typeof searchQueryText === 'string' && searchQueryText !== ''\n})\n\nconst isUserPlaylistRequested = computed(() => route.query.playlistType === 'user')\n\n/** @type {import('vue').ComputedRef<string | undefined>} */\nconst quickBookmarkPlaylistId = computed(() => store.getters.getQuickBookmarkTargetPlaylistId)\n\nconst quickBookmarkButtonEnabled = computed(() => {\n  if (selectedUserPlaylist.value == null) { return true }\n\n  return selectedUserPlaylist.value?._id !== quickBookmarkPlaylistId.value\n})\n\nconst sometimesFilteredUserPlaylistItems = computed(() => {\n  if (!isUserPlaylistRequested.value || processedVideoSearchQuery.value === '') {\n    return sortedPlaylistItems.value\n  }\n\n  const processedVideoSearchQuery_ = processedVideoSearchQuery.value\n\n  return sortedPlaylistItems.value.filter((v) => {\n    return (typeof v.title === 'string' && v.title.toLowerCase().includes(processedVideoSearchQuery_)) ||\n      (typeof v.author === 'string' && v.author.toLowerCase().includes(processedVideoSearchQuery_))\n  })\n})\n\nconst isSortOrderCustom = computed(() => sortOrder.value === SORT_BY_VALUES.Custom)\n\nconst sortedPlaylistItems = computed(() => {\n  if (\n    sortOrder.value === SORT_BY_VALUES.VideoDurationAscending ||\n    sortOrder.value === SORT_BY_VALUES.VideoDurationDescending\n  ) {\n    const playlistItems = getPlaylistItemsWithDuration()\n    return getSortedPlaylistItems(playlistItems, sortOrder.value, locale.value)\n  }\n  return getSortedPlaylistItems(shownPlaylistItems.value, sortOrder.value, locale.value)\n})\n\nconst visiblePlaylistItems = computed(() => {\n  if (!isUserPlaylistRequested.value) {\n    // No filtering for non user playlists yet\n    return sortedPlaylistItems.value\n  }\n\n  if (userPlaylistVisibleLimit.value < sometimesFilteredUserPlaylistItems.value.length) {\n    return sometimesFilteredUserPlaylistItems.value.slice(0, userPlaylistVisibleLimit.value)\n  } else {\n    return sometimesFilteredUserPlaylistItems.value\n  }\n})\n\nconst sortOrderIcon = computed(() => getIconForSortPreference(sortOrder.value))\n\nconst SORT_BY_SELECT_VALUES = Object.values(SORT_BY_VALUES)\n\nconst sortBySelectNames = computed(() => {\n  return SORT_BY_SELECT_VALUES.map((k) => {\n    switch (k) {\n      case SORT_BY_VALUES.Custom:\n        return t('Playlist.Sort By.Custom')\n      case SORT_BY_VALUES.DateAddedNewest:\n        return t('Playlist.Sort By.DateAddedNewest')\n      case SORT_BY_VALUES.DateAddedOldest:\n        return t('Playlist.Sort By.DateAddedOldest')\n      case SORT_BY_VALUES.PublishedNewest:\n        return t('Playlist.Sort By.PublishedNewest')\n      case SORT_BY_VALUES.PublishedOldest:\n        return t('Playlist.Sort By.PublishedOldest')\n      case SORT_BY_VALUES.VideoTitleAscending:\n        return t('Playlist.Sort By.VideoTitleAscending')\n      case SORT_BY_VALUES.VideoTitleDescending:\n        return t('Playlist.Sort By.VideoTitleDescending')\n      case SORT_BY_VALUES.AuthorAscending:\n        return t('Playlist.Sort By.AuthorAscending')\n      case SORT_BY_VALUES.AuthorDescending:\n        return t('Playlist.Sort By.AuthorDescending')\n      case SORT_BY_VALUES.VideoDurationAscending:\n        return t('Playlist.Sort By.VideoDurationAscending')\n      case SORT_BY_VALUES.VideoDurationDescending:\n        return t('Playlist.Sort By.VideoDurationDescending')\n      default:\n        console.error(`Unknown sort: ${k}`)\n        return k\n    }\n  })\n})\n\n/**\n * @param {string} value\n */\nfunction updateUserPlaylistSortOrder(value) {\n  store.dispatch('updateUserPlaylistSortOrder', value)\n}\n\n/** @type {import('vue').ComputedRef<number>} */\nconst totalPlaylistDuration = computed(() => {\n  return shownPlaylistItems.value.reduce((acc, video) => {\n    return typeof video.lengthSeconds === 'number' ? acc + video.lengthSeconds : acc\n  }, 0)\n})\n\nconst isDurationApproximate = computed(() => {\n  return shownPlaylistItems.value.some((video) => typeof video.lengthSeconds !== 'number')\n})\n\nconst noPlaylistItemsPendingDeletion = computed(() => toBeDeletedPlaylistItemIds.value.length === 0)\n\nconst shownPlaylistItems = computed(() => {\n  if (noPlaylistItemsPendingDeletion.value) {\n    return playlistItems.value\n  }\n\n  const toBeDeletedPlaylistItemIds_ = toBeDeletedPlaylistItemIds.value\n  return playlistItems.value.filter((v) => !toBeDeletedPlaylistItemIds_.includes(v.playlistItemId))\n})\n\nconst shownPlaylistItemCount = computed(() => shownPlaylistItems.value)\n\nconst shownVideoCount = computed(() => isUserPlaylistRequested.value ? shownPlaylistItemCount.value.length : videoCount.value)\n\nfunction getPlaylistInfo() {\n  isLoading.value = true\n\n  if (isUserPlaylistRequested.value) {\n    if (!userPlaylistsReady.value) { return }\n\n    if (selectedUserPlaylist.value != null) {\n      parseUserPlaylist(selectedUserPlaylist.value)\n    } else {\n      showToast(t('User Playlists.SinglePlaylistView.Toast.This playlist does not exist'))\n    }\n  } else {\n    if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n      getPlaylistInvidious()\n    } else {\n      getPlaylistLocal()\n    }\n  }\n}\n\nconst getPlaylistInfoDebounce = debounce(getPlaylistInfo, 100)\n\nasync function getPlaylistLocal() {\n  try {\n    const result = await getLocalPlaylist(playlistId.value)\n\n    let channelName_\n\n    if (result.info.author) {\n      channelName_ = result.info.author.name\n    } else {\n      const subtitle = result.info.subtitle?.toString()\n      if (subtitle) {\n        const index = subtitle.lastIndexOf('•')\n        channelName_ = subtitle.substring(0, index).trim()\n      } else {\n        channelName_ = ''\n      }\n    }\n\n    const playlistItems_ = result.items.map(parseLocalPlaylistVideo)\n\n    playlistTitle.value = result.info.title\n    playlistDescription.value = result.info.description ?? ''\n    firstVideoId.value = playlistItems_[0].videoId\n    playlistThumbnail.value = result.info.thumbnails[0].url\n    viewCount.value = result.info.views.toLowerCase() === 'no views' ? 0 : extractNumberFromString(result.info.views)\n    videoCount.value = extractNumberFromString(result.info.total_items)\n    lastUpdated.value = result.info.last_updated ?? ''\n    channelName.value = channelName_ ?? ''\n    channelThumbnail.value = result.info.author?.best_thumbnail?.url ?? ''\n    channelId.value = result.info.author?.id\n    infoSource.value = 'local'\n\n    store.dispatch('updateSubscriptionDetails', {\n      channelThumbnailUrl: channelThumbnail.value,\n      channelName: channelName_,\n      channelId: channelId.value\n    })\n\n    playlistItems.value = playlistItems_\n\n    let shouldGetNextPage = false\n    if (result.has_continuation) {\n      continuationData.value = result\n      shouldGetNextPage = playlistItems.value.length < 100\n    }\n    // To workaround the effect of useless continuation data\n    // auto load next page again when no. of parsed items < page size\n    if (shouldGetNextPage) {\n      getNextPageLocal()\n    }\n\n    updatePageTitle()\n\n    isLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      console.warn('Falling back to Invidious API')\n      getPlaylistInvidious()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getPlaylistInvidious() {\n  try {\n    const result = await invidiousGetPlaylistInfo(playlistId.value)\n\n    playlistTitle.value = result.title\n    playlistDescription.value = result.description\n    firstVideoId.value = result.videos[0].videoId\n    viewCount.value = result.viewCount\n    videoCount.value = result.videoCount\n    channelName.value = result.author\n    channelThumbnail.value = youtubeImageUrlToInvidious(result.authorThumbnails[2].url, currentInvidiousInstanceUrl.value)\n    channelId.value = result.authorId\n    infoSource.value = 'invidious'\n\n    store.dispatch('updateSubscriptionDetails', {\n      channelThumbnailUrl: result.authorThumbnails[2].url,\n      channelName: channelName.value,\n      channelId: channelId.value\n    })\n\n    const dateString = new Date(result.updated * 1000)\n    lastUpdated.value = dateString.toLocaleDateString(locale.value, { year: 'numeric', month: 'short', day: 'numeric' })\n\n    playlistItems.value = result.videos\n\n    updatePageTitle()\n\n    isLoading.value = false\n  } catch (err) {\n    console.error(err)\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      console.warn('Error getting data with Invidious, falling back to local backend')\n      getPlaylistLocal()\n    } else {\n      isLoading.value = false\n      // TODO: Show toast with error message\n    }\n  }\n}\n\nfunction parseUserPlaylist(playlist) {\n  playlistTitle.value = playlist.playlistName\n  playlistDescription.value = playlist.description ?? ''\n\n  if (playlist.videos.length > 0) {\n    firstVideoId.value = playlist.videos[0].videoId\n    firstVideoPlaylistItemId.value = playlist.videos[0].playlistItemId\n  } else {\n    firstVideoId.value = ''\n    firstVideoPlaylistItemId.value = ''\n  }\n\n  const dateString = new Date(playlist.lastUpdatedAt)\n  lastUpdated.value = dateString.toLocaleDateString(locale.value, { year: 'numeric', month: 'short', day: 'numeric' })\n  viewCount.value = 0\n  channelName.value = ''\n  channelThumbnail.value = ''\n  channelId.value = ''\n  infoSource.value = 'user'\n\n  playlistItems.value = playlist.videos\n\n  updatePageTitle()\n\n  isLoading.value = false\n}\n\n// react to route changes...\nwatch(playlistId, getPlaylistInfoDebounce)\n\nwatch(userPlaylistsReady, () => {\n  // Fetch from local store when playlist data ready\n  if (!isUserPlaylistRequested.value) { return }\n\n  getPlaylistInfoDebounce()\n})\n\n// Fetch from local store when current user playlist changed\nwatch(selectedUserPlaylist, getPlaylistInfoDebounce)\n\n// Re-fetch from local store when current user playlist updated\nwatch(selectedUserPlaylistLastUpdatedAt, getPlaylistInfoDebounce)\n\nwatch(selectedUserPlaylistVideoCount, async () => {\n  // Monitoring `selectedUserPlaylistVideos` makes this function called\n  // Even when the same array object is returned\n  // So length is monitored instead\n  // Assuming in user playlist video cannot be swapped without length change\n\n  // Re-fetch from local store when current user playlist videos updated\n  // MUST NOT use `getPlaylistInfoDebounce` as it will cause delay in data update\n  // Causing deleted videos to reappear for one frame\n  getPlaylistInfo()\n})\n\nconst historyCacheById = computed(() => store.getters.getHistoryCacheById)\n\nfunction getPlaylistItemsWithDuration() {\n  const modifiedPlaylistItems = deepCopy(shownPlaylistItems.value)\n  let anyVideoMissingDuration = false\n\n  modifiedPlaylistItems.forEach(video => {\n    if (videoDurationPresent(video)) { return }\n\n    const videoHistory = historyCacheById[video.videoId]\n\n    if (typeof videoHistory !== 'undefined') {\n      const fetchedLengthSeconds = videoDurationWithFallback(videoHistory)\n      video.lengthSeconds = fetchedLengthSeconds\n\n      // if the video duration is 0, it will be the fallback value, so mark it as missing a duration\n      if (fetchedLengthSeconds === 0) {\n        anyVideoMissingDuration = true\n      }\n    } else {\n      // Mark at least one video have no duration, show notice later\n      // Also assign fallback duration here\n      anyVideoMissingDuration = true\n      video.lengthSeconds = 0\n    }\n  })\n\n  // Show notice if not already shown before returning playlist items\n  if (anyVideoMissingDuration && !alreadyShownNotice) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast.This playlist has a video with a duration error'), 5000)\n    alreadyShownNotice = true\n  }\n\n  return modifiedPlaylistItems\n}\n\nfunction getNextPage() {\n  if (process.env.SUPPORTS_LOCAL_API && infoSource.value === 'local') {\n    getNextPageLocal()\n  } else if (infoSource.value === 'user') {\n    // Stop users from spamming the load more button, by replacing it with a loading symbol until the newly added items are renderered\n    isLoadingMore.value = true\n\n    nextTick(() => {\n      if (userPlaylistVisibleLimit.value + 100 < shownVideoCount.value) {\n        userPlaylistVisibleLimit.value += 100\n      } else {\n        userPlaylistVisibleLimit.value = shownVideoCount.value\n      }\n\n      isLoadingMore.value = false\n    })\n  } else if (infoSource.value === 'invidious') {\n    console.error('Playlist pagination is not currently supported when the Invidious backend is selected.')\n  }\n}\n\nasync function getNextPageLocal() {\n  isLoadingMore.value = true\n\n  const result = await getLocalPlaylistContinuation(continuationData.value)\n\n  let shouldGetNextPage = false\n\n  if (result) {\n    const parsedVideos = result.items.map(parseLocalPlaylistVideo)\n    playlistItems.value = playlistItems.value.concat(parsedVideos)\n\n    if (result.has_continuation) {\n      continuationData.value = result\n\n      // To workaround the effect of useless continuation data\n      // auto load next page again when no. of parsed items < page size\n      shouldGetNextPage = parsedVideos.length < 100\n    } else {\n      continuationData.value = null\n    }\n  } else {\n    continuationData.value = null\n  }\n\n  isLoadingMore.value = false\n\n  if (shouldGetNextPage) {\n    getNextPageLocal()\n  }\n}\n\nconst canMoveVideos = computed(() => {\n  return !playlistInVideoSearchMode.value && isSortOrderCustom.value && noPlaylistItemsPendingDeletion.value\n})\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoUp(videoId, playlistItemId) {\n  const playlistItems_ = playlistItems.value.slice()\n\n  const index = playlistItems_.findIndex((video) => {\n    return video.videoId === videoId && video.playlistItemId === playlistItemId\n  })\n\n  if (index === 0) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"This video cannot be moved up.\"]'))\n    return\n  }\n\n  [playlistItems_[index], playlistItems_[index - 1]] = [playlistItems_[index - 1], playlistItems_[index]]\n\n  const playlist = {\n    playlistName: playlistTitle.value,\n    protected: selectedUserPlaylist.value.protected,\n    description: playlistDescription.value,\n    videos: deepCopy(playlistItems_),\n    _id: playlistId.value\n  }\n\n  try {\n    store.dispatch('updatePlaylist', playlist)\n    playlistItems.value = playlistItems_\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There was an issue with updating this playlist.\"]'))\n    console.error(e)\n  }\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction moveVideoDown(videoId, playlistItemId) {\n  const playlistItems_ = playlistItems.value.slice()\n\n  const index = playlistItems_.findIndex((video) => {\n    return video.videoId === videoId && video.playlistItemId === playlistItemId\n  })\n\n  if (index + 1 >= playlistItems_.length) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"This video cannot be moved down.\"]'))\n    return\n  }\n\n  [playlistItems_[index], playlistItems_[index + 1]] = [playlistItems_[index + 1], playlistItems_[index]]\n\n  const playlist = {\n    playlistName: playlistTitle.value,\n    protected: selectedUserPlaylist.value.protected,\n    description: playlistDescription.value,\n    videos: deepCopy(playlistItems_),\n    _id: playlistId.value\n  }\n\n  try {\n    store.dispatch('updatePlaylist', playlist)\n    playlistItems.value = playlistItems_\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast[\"There was an issue with updating this playlist.\"]'))\n    console.error(e)\n  }\n}\n\n/**\n * @param {string} videoId\n * @param {string} playlistItemId\n */\nfunction removeVideoFromPlaylist(videoId, playlistItemId) {\n  try {\n    const foundVideo = playlistItems.value.some((video) => {\n      return video.videoId === videoId && video.playlistItemId === playlistItemId\n    })\n\n    if (foundVideo) {\n      toBeDeletedPlaylistItemIds.value.push(playlistItemId)\n\n      // Only show toast when no existing toast shown\n      if (undoToastAbortController == null) {\n        undoToastAbortController = new AbortController()\n\n        const timeoutMs = 5000\n        const actualRemoveVideosTimeout = setTimeout(() => {\n          removeToBeDeletedVideosSometimes()\n        }, timeoutMs)\n\n        showToast(\n          t('User Playlists.SinglePlaylistView.Toast[\"Video has been removed. Click here to undo.\"]'),\n          timeoutMs,\n          () => {\n            clearTimeout(actualRemoveVideosTimeout)\n            toBeDeletedPlaylistItemIds.value = []\n            undoToastAbortController = null\n          },\n          undoToastAbortController.signal,\n        )\n      }\n    }\n  } catch (e) {\n    showToast(t('User Playlists.SinglePlaylistView.Toast.There was a problem with removing this video'))\n    console.error(e)\n  }\n}\n\nasync function removeToBeDeletedVideosSometimes() {\n  if (isLoading.value) { return }\n\n  if (toBeDeletedPlaylistItemIds.value.length > 0) {\n    await store.dispatch('removeVideos', {\n      _id: playlistId.value,\n      // Create a new non-reactive array to avoid Electron erroring about Proxy objects not being clonable\n      playlistItemIds: [...toBeDeletedPlaylistItemIds.value],\n    })\n\n    toBeDeletedPlaylistItemIds.value = []\n    undoToastAbortController?.abort()\n    undoToastAbortController = null\n  }\n}\n\nfunction updatePageTitle() {\n  const playlistTitle_ = playlistTitle.value\n  const channelName_ = channelName.value\n\n  let titleText = ''\n\n  if (playlistTitle_) {\n    titleText = playlistTitle_\n  }\n\n  if (channelName_) {\n    if (titleText.length > 0) {\n      titleText += `| ${channelName_}`\n    } else {\n      titleText = channelName_\n    }\n  }\n\n  store.commit('setAppTitle', `${titleText} - ${packageDetails.productName}`)\n}\n\n/**\n * @param {string} value\n */\nfunction handleVideoSearchQueryChange(value) {\n  videoSearchQuery.value = value\n\n  saveStateInRouter(value)\n}\n\n/**\n * @param {string} query\n */\nasync function saveStateInRouter(query) {\n  const routeQuery = {\n    playlistType: route.query.playlistType,\n  }\n\n  if (query !== '') {\n    routeQuery.searchQueryText = query\n  }\n\n  try {\n    await router.replace({\n      path: `/playlist/${playlistId.value}`,\n      query: routeQuery,\n    })\n  } catch (failure) {\n    if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n      return\n    }\n\n    throw failure\n  }\n}\n\nif (isUserPlaylistRequested.value && searchQueryTextPresent.value) {\n  handleVideoSearchQueryChange(searchQueryTextRequested.value)\n}\n\nfunction handleResize() {\n  forceListView.value = window.innerWidth <= MOBILE_WIDTH_THRESHOLD || window.innerHeight <= PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD\n}\n\nonMounted(() => {\n  getPlaylistInfoDebounce()\n  handleResize()\n  window.addEventListener('resize', handleResize)\n})\n\nonBeforeUnmount(() => {\n  window.removeEventListener('resize', handleResize)\n})\n\nonBeforeRouteLeave((to) => {\n  if (!isLoading.value && to.path.startsWith('/watch') && to.query.playlistId === playlistId.value) {\n    store.commit('setCachedPlaylist', {\n      id: playlistId.value,\n      title: playlistTitle.value,\n      channelName: channelName.value,\n      channelId: channelId.value,\n      items: sortedPlaylistItems.value,\n      continuationData: continuationData.value\n        ? extractLocalCacheablePlaylistContinuation(continuationData.value)\n        : null,\n    })\n  }\n\n  removeToBeDeletedVideosSometimes()\n})\n</script>\n\n<style scoped src=\"./Playlist.scss\" lang=\"scss\" />\n"
  },
  {
    "path": "src/renderer/views/Popular/Popular.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Popular/Popular.vue",
    "content": "<template>\n  <div>\n    <ft-loader\n      v-if=\"isLoading\"\n      :fullscreen=\"true\"\n    />\n    <ft-card\n      v-else\n      class=\"card\"\n    >\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'users']\"\n          class=\"headingIcon\"\n        />\n        {{ $t(\"Most Popular\") }}\n      </h2>\n      <ft-element-list\n        :data=\"shownResults\"\n      />\n    </ft-card>\n    <ft-refresh-widget\n      :disable-refresh=\"isLoading\"\n      :last-refresh-timestamp=\"lastPopularRefreshTimestamp\"\n      :title=\"$t('Most Popular')\"\n      @click=\"fetchPopularInfo\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'\n\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtRefreshWidget from '../../components/FtRefreshWidget/FtRefreshWidget.vue'\nimport store from '../../store/index'\n\nimport { getInvidiousPopularFeed } from '../../helpers/api/invidious'\nimport { copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { KeyboardShortcuts } from '../../../constants'\n\nconst { t } = useI18n()\n\nconst isLoading = ref(false)\n\nconst lastPopularRefreshTimestamp = computed(() => {\n  return getRelativeTimeFromDate(store.getters.getLastPopularRefreshTimestamp, true)\n})\n\n/** @type {import('vue').ComputedRef<Array | null>} */\nconst popularCache = computed(() => {\n  return store.getters.getPopularCache\n})\n\nconst shownResults = shallowRef(popularCache.value || [])\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n\n  if (shownResults.value.length === 0) {\n    fetchPopularInfo()\n  }\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n\nasync function fetchPopularInfo() {\n  isLoading.value = true\n\n  try {\n    const items = await getInvidiousPopularFeed()\n\n    store.commit('setLastPopularRefreshTimestamp', new Date())\n    shownResults.value = items\n    isLoading.value = false\n    store.commit('setPopularCache', items)\n  } catch (err) {\n    isLoading.value = false\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n  }\n}\n\n/**\n * @param {KeyboardEvent} event the keyboard event\n */\nfunction keyboardShortcutHandler(event) {\n  if (document.activeElement.classList.contains('ft-input')) {\n    return\n  }\n  // Avoid handling events due to user holding a key (not released)\n  // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat\n  if (event.repeat) { return }\n\n  switch (event.key.toLowerCase()) {\n    case 'f5':\n    case KeyboardShortcuts.APP.SITUATIONAL.REFRESH:\n      if (!isLoading.value) {\n        fetchPopularInfo()\n      }\n      break\n  }\n}\n\n</script>\n<style scoped src=\"./Popular.css\" />\n"
  },
  {
    "path": "src/renderer/views/Post.vue",
    "content": "<template>\n  <div>\n    <FtLoader v-if=\"isLoading\" />\n    <template\n      v-else\n    >\n      <FtCard>\n        <FtCommunityPost\n          :data=\"post\"\n          :single-post=\"true\"\n          appearance=\"result\"\n        />\n      </FtCard>\n      <CommentSection\n        :id=\"post.postId\"\n        :channel-name=\"post.author\"\n        :post-author-id=\"authorId\"\n        :video-player-ready=\"false\"\n        :force-state=\"null\"\n        :is-post-comments=\"true\"\n        :channel-thumbnail=\"post.authorThumbnails[0].url\"\n        :show-sort-by=\"backendPreference == 'local'\"\n      />\n    </template>\n  </div>\n</template>\n\n<script setup>\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport packageDetails from '../../../package.json'\nimport { useI18n } from '../composables/use-i18n-polyfill'\n\nimport FtCard from '../components/ft-card/ft-card.vue'\nimport FtCommunityPost from '../components/FtCommunityPost/FtCommunityPost.vue'\nimport FtLoader from '../components/FtLoader/FtLoader.vue'\nimport CommentSection from '../components/CommentSection/CommentSection.vue'\n\nimport store from '../store/index'\n\nimport { getInvidiousCommunityPost } from '../helpers/api/invidious'\nimport { getLocalCommunityPost } from '../helpers/api/local'\nimport { copyToClipboard, showToast } from '../helpers/utils'\n\nconst { t } = useI18n()\n\nconst router = useRouter()\nconst route = useRoute()\n\nconst id = ref('')\nconst authorId = ref('')\nconst post = shallowRef(null)\nconst isLoading = ref(true)\n\n/** @type {import('vue').ComputedRef<'invidious' | 'local'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => {\n  return store.getters.getBackendFallback\n})\n\nonMounted(async () => {\n  id.value = route.params.id\n  authorId.value = route.query.authorId\n\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    await loadDataInvidiousAsync()\n  } else {\n    await loadDataLocalAsync()\n  }\n})\n\nfunction updateTitleAndRoute() {\n  store.commit('setAppTitle', `${post.value.author} - ${packageDetails.productName}`)\n  isLoading.value = false\n\n  // If the authorId is missing from the URL we should add it,\n  // that way if the user comes back to this page by pressing the back button\n  // we don't have to resolve the authorId again\n  if (authorId.value !== route.query.authorId) {\n    router.replace({\n      path: `/post/${id.value}`,\n      query: {\n        authorId: authorId.value\n      }\n    })\n  }\n}\n\nasync function loadDataLocalAsync() {\n  try {\n    post.value = await getLocalCommunityPost(id.value, authorId.value)\n    authorId.value = post.value.authorId\n    updateTitleAndRoute()\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      await loadDataInvidiousAsync()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function loadDataInvidiousAsync() {\n  try {\n    post.value = await getInvidiousCommunityPost(id.value, authorId.value)\n    authorId.value = post.value.authorId\n    updateTitleAndRoute()\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      await loadDataLocalAsync()\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nwatch(() => route.params.id, async () => {\n  // react to route changes...\n  isLoading.value = true\n  id.value = route.params.id\n  authorId.value = route.query.authorId\n  if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {\n    await loadDataInvidiousAsync()\n  } else {\n    await loadDataLocalAsync()\n  }\n})\n</script>\n"
  },
  {
    "path": "src/renderer/views/ProfileSettings/ProfileSettings.css",
    "content": "h2 {\n  text-align: center;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.profileList {\n  max-inline-size: 1000px;\n  margin-block: 0 10px;\n  margin-inline: auto;\n}\n\n.openedProfile {\n  background-color: var(--primary-text-color);\n  transition: background 0.2s ease-out;\n  color: var(--card-bg-color);\n}\n\n.openedProfile:hover,\n.openedProfile:focus-visible {\n  background-color: var(--tertiary-text-color);\n  transition: background 0.2s ease-in;\n}\n\n.card {\n  inline-size: 85%;\n  margin-block: 0 15px;\n  margin-inline: auto;\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/ProfileSettings/ProfileSettings.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>{{ $t(\"Profile.Profile Manager\") }}</h2>\n      <FtFlexBox\n        class=\"profileList\"\n      >\n        <FtProfileBubble\n          v-for=\"profile in profileList\"\n          :key=\"profile._id\"\n          :is-main-profile=\"profile._id === MAIN_PROFILE_ID\"\n          :profile-name=\"profile.name\"\n          :background-color=\"profile.bgColor\"\n          :text-color=\"profile.textColor\"\n          :class=\"{ openedProfile: openSettingsProfile?._id === profile._id }\"\n          @click=\"openSettingsForProfileWithId(profile._id)\"\n        />\n      </FtFlexBox>\n      <FtFlexBox\n        v-if=\"!isNewProfileOpen\"\n      >\n        <FtButton\n          :label=\"$t('Profile.Create New Profile')\"\n          @click=\"openSettingsForNewProfile\"\n        />\n      </FtFlexBox>\n    </FtCard>\n    <div\n      v-if=\"openSettingsProfile\"\n      :key=\"openSettingsProfileId\"\n    >\n      <FtProfileChannelList\n        v-if=\"!isNewProfileOpen\"\n        :profile=\"openSettingsProfile\"\n        :is-main-profile=\"isMainProfile\"\n      />\n      <FtProfileFilterChannelsList\n        v-if=\"!isNewProfileOpen && !isMainProfile\"\n        :profile=\"openSettingsProfile\"\n      />\n      <FtProfileEdit\n        :profile=\"openSettingsProfile\"\n        :is-new=\"isNewProfileOpen\"\n        :is-main-profile=\"isMainProfile\"\n        @new-profile-created=\"handleNewProfileCreated\"\n        @profile-deleted=\"handleProfileDeleted\"\n      />\n    </div>\n  </div>\n</template>\n\n<script setup>\nimport { computed, ref, shallowRef, watch } from 'vue'\n\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtProfileBubble from '../../components/FtProfileBubble/FtProfileBubble.vue'\nimport FtButton from '../../components/FtButton/FtButton.vue'\nimport FtProfileEdit from '../../components/FtProfileEdit/FtProfileEdit.vue'\nimport FtProfileChannelList from '../../components/FtProfileChannelList/FtProfileChannelList.vue'\nimport FtProfileFilterChannelsList from '../../components/FtProfileFilterChannelsList/FtProfileFilterChannelsList.vue'\n\nimport store from '../../store/index'\n\nimport { calculateColorLuminance, getRandomColor } from '../../helpers/colors'\nimport { MAIN_PROFILE_ID } from '../../../constants'\n\n/**\n * @typedef {object} Profile\n * @property {string} _id\n * @property {string} name\n * @property {string} bgColor\n * @property {string} textColor\n * @property {object[]} subscriptions\n * @property {string} subscriptions[].id\n * @property {string|undefined} subscriptions[].name\n * @property {string|undefined} subscriptions[].thumbnail\n */\n\nconst isNewProfileOpen = ref(false)\n\n/** @type {import('vue').Ref<string>} */\nconst openSettingsProfileId = ref('')\n\n/** @type {import('vue').ShallowRef<Profile|null>} */\nconst openSettingsProfile = shallowRef(null)\n\n/** @type {import('vue').ComputedRef<Profile[]>} */\nconst profileList = computed(() => {\n  return store.getters.getProfileList\n})\n\nwatch(profileList, () => {\n  openSettingsProfile.value = getProfileById(openSettingsProfileId.value)\n}, { deep: true })\n\nconst isMainProfile = computed(() => {\n  return MAIN_PROFILE_ID === openSettingsProfileId.value\n})\n\nfunction openSettingsForNewProfile() {\n  isNewProfileOpen.value = true\n\n  openSettingsProfile.value = {\n    name: '',\n    bgColor: getRandomColor().value,\n    textColor: calculateColorLuminance(getRandomColor().value),\n    subscriptions: []\n  }\n\n  openSettingsProfileId.value = ''\n}\n\n/**\n * @param {string} profileId\n */\nfunction openSettingsForProfileWithId(profileId) {\n  if (profileId === openSettingsProfileId.value) {\n    return\n  }\n\n  isNewProfileOpen.value = false\n  openSettingsProfileId.value = profileId\n  openSettingsProfile.value = getProfileById(profileId)\n}\n\n/**\n * @param {string | null} profileId\n */\nfunction getProfileById(profileId) {\n  if (!profileId) {\n    return null\n  }\n\n  return store.getters.profileById(profileId)\n}\n\nfunction handleNewProfileCreated() {\n  isNewProfileOpen.value = false\n  openSettingsProfile.value = null\n  openSettingsProfileId.value = ''\n}\n\nfunction handleProfileDeleted() {\n  openSettingsProfile.value = null\n  openSettingsProfileId.value = ''\n}\n</script>\n\n<style scoped src=\"./ProfileSettings.css\" />\n"
  },
  {
    "path": "src/renderer/views/SearchPage/SearchPage.css",
    "content": ".getNextPage {\n  background-color: var(--search-bar-color);\n  inline-size: 100%;\n  block-size: 45px;\n  line-height: 45px;\n  text-align: center;\n  cursor: pointer;\n  margin-block-start: 16px;\n}\n\n.getNextPage:hover,\n.getNextPage:focus {\n  background-color: var(--side-nav-hover-color);\n  color: var(--side-nav-hover-text-color);\n}\n\n.card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/SearchPage/SearchPage.vue",
    "content": "<template>\n  <div>\n    <FtLoader\n      v-if=\"isLoading\"\n      :fullscreen=\"true\"\n    />\n    <FtCard\n      v-else\n      class=\"card\"\n    >\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'search']\"\n          class=\"headingIcon\"\n        />\n        {{ t(\"Search Filters.Search Results\") }}\n      </h2>\n      <FtElementList\n        :data=\"shownResults\"\n      />\n      <FtAutoLoadNextPageWrapper\n        @load-next-page=\"nextPage\"\n      >\n        <div\n          class=\"getNextPage\"\n          role=\"button\"\n          tabindex=\"0\"\n          @click=\"nextPage\"\n          @keydown.enter.prevent=\"nextPage\"\n          @keydown.space.prevent=\"nextPage\"\n        >\n          <FontAwesomeIcon :icon=\"['fas', 'search']\" /> {{ t(\"Search Filters.Fetch more results\") }}\n        </div>\n      </FtAutoLoadNextPageWrapper>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onMounted, ref, shallowRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { useRoute } from 'vue-router'\n\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\n\nimport store from '../../store'\n\nimport packageDetails from '../../../../package.json'\nimport {\n  copyToClipboard,\n  searchFiltersMatch,\n  showToast,\n} from '../../helpers/utils'\nimport {\n  extractLocalCacheableSearchContinuation,\n  getLocalSearchContinuation,\n  getLocalSearchResults\n} from '../../helpers/api/local'\nimport { getInvidiousSearchResults } from '../../helpers/api/invidious'\nimport { SEARCH_CHAR_LIMIT } from '../../../constants'\n\nconst { t } = useI18n()\nconst route = useRoute()\n\nconst isLoading = ref(false)\nconst apiUsed = ref('local')\nconst searchSettings = ref({})\nconst searchPage = ref(1)\n/** @type {import('vue').ShallowRef<import('youtubei.js').YT.Search | string | null>} */\nconst nextPageRef = shallowRef(null)\nconst shownResults = shallowRef([])\n\nconst query = ref('')\nconst processedQuery = computed(() => query.value.trim())\n\n/** @type {import('vue').ComputedRef<any[]>} */\nconst sessionSearchHistory = computed(() => store.getters.getSessionSearchHistory)\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => store.getters.getBackendPreference)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => store.getters.getBackendFallback)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst showFamilyFriendlyOnly = computed(() => store.getters.getShowFamilyFriendlyOnly)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst rememberSearchHistory = computed(() => store.getters.getRememberSearchHistory)\n\nwatch(route, () => {\n  const query_ = route.params.query.trim()\n  let features = route.query.features\n  // if page gets refreshed and there's only one feature then it will be a string\n  if (typeof features === 'string') {\n    features = [features]\n  }\n  const searchSettings = {\n    sortBy: route.query.sortBy,\n    time: route.query.time,\n    type: route.query.type,\n    duration: route.query.duration,\n    features: features ?? [],\n  }\n\n  const payload = {\n    query: query_,\n    options: {},\n    searchSettings: searchSettings\n  }\n\n  query.value = query_\n\n  store.commit('setAppTitle', `${processedQuery.value} - ${packageDetails.productName}`)\n  checkSearchCache(payload)\n}, { deep: true })\n\nonMounted(() => {\n  query.value = route.params.query\n  store.commit('setAppTitle', `${processedQuery.value} - ${packageDetails.productName}`)\n\n  let features = route.query.features\n  // if page gets refreshed and there's only one feature then it will be a string\n  if (typeof features === 'string') {\n    features = [features]\n  }\n\n  searchSettings.value = {\n    sortBy: route.query.sortBy,\n    time: route.query.time,\n    type: route.query.type,\n    duration: route.query.duration,\n    features: features ?? [],\n  }\n\n  const payload = {\n    query: processedQuery.value,\n    options: {},\n    searchSettings: searchSettings.value\n  }\n\n  checkSearchCache(payload)\n})\n\nfunction updateSearchHistoryEntry() {\n  const persistentSearchHistoryPayload = {\n    _id: processedQuery.value,\n    lastUpdatedAt: Date.now()\n  }\n\n  store.dispatch('updateSearchHistoryEntry', persistentSearchHistoryPayload)\n}\n\nfunction checkSearchCache(payload) {\n  if (payload.query.length > SEARCH_CHAR_LIMIT) {\n    console.warn(`Search character limit is: ${SEARCH_CHAR_LIMIT}`)\n    showToast(t('Search character limit', { searchCharacterLimit: SEARCH_CHAR_LIMIT }))\n    return\n  }\n\n  const sameSearch = sessionSearchHistory.value.filter((search) => {\n    return search.query === payload.query && searchFiltersMatch(payload.searchSettings, search.searchSettings)\n  })\n\n  if (sameSearch.length > 0) {\n    // No loading effect needed here, only rendered result update\n    replaceShownResults(sameSearch[0])\n  } else {\n    // Show loading effect coz there will be network request(s)\n    isLoading.value = true\n    searchSettings.value = payload.searchSettings\n\n    switch (backendPreference.value) {\n      case 'local':\n        performSearchLocal(payload)\n        break\n      case 'invidious':\n        performSearchInvidious(payload, { resetSearchPage: true })\n        break\n    }\n  }\n\n  if (rememberSearchHistory.value) {\n    updateSearchHistoryEntry()\n  }\n}\n\nasync function performSearchLocal(payload) {\n  isLoading.value = true\n\n  try {\n    const { results, continuationData } = await getLocalSearchResults(\n      payload.query,\n      payload.searchSettings,\n      showFamilyFriendlyOnly.value\n    )\n\n    apiUsed.value = 'local'\n\n    shownResults.value = results\n    nextPageRef.value = continuationData\n\n    isLoading.value = false\n\n    const historyPayload = {\n      query: payload.query,\n      data: shownResults.value,\n      searchSettings: searchSettings.value,\n      nextPageRef: nextPageRef.value ? extractLocalCacheableSearchContinuation(nextPageRef.value) : null,\n      apiUsed: apiUsed.value\n    }\n\n    store.commit('addToSessionSearchHistory', historyPayload)\n\n    updateSubscriptionDetails(results)\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      performSearchInvidious(payload)\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function getNextpageLocal(payload) {\n  try {\n    const { results, continuationData } = await getLocalSearchContinuation(payload.options.nextPageRef)\n\n    if (results.length === 0) {\n      return\n    }\n\n    apiUsed.value = 'local'\n\n    shownResults.value = shownResults.value.concat(results)\n    nextPageRef.value = continuationData\n\n    const historyPayload = {\n      query: payload.query,\n      data: shownResults.value,\n      searchSettings: searchSettings.value,\n      nextPageRef: nextPageRef.value ? extractLocalCacheableSearchContinuation(nextPageRef.value) : null,\n      apiUsed: apiUsed.value\n    }\n\n    store.commit('addToSessionSearchHistory', historyPayload)\n\n    updateSubscriptionDetails(results)\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (backendPreference.value === 'local' && backendFallback.value) {\n      showToast(t('Falling back to Invidious API'))\n      performSearchInvidious(payload)\n    } else {\n      isLoading.value = false\n    }\n  }\n}\n\nasync function performSearchInvidious(payload, options = { resetSearchPage: false }) {\n  if (options.resetSearchPage) {\n    searchPage.value = 1\n  }\n\n  if (searchPage.value === 1) {\n    isLoading.value = true\n  }\n\n  try {\n    const results = await getInvidiousSearchResults(payload.query, searchPage.value, payload.searchSettings)\n    if (!results) {\n      return\n    }\n\n    apiUsed.value = 'invidious'\n\n    if (searchPage.value !== 1) {\n      shownResults.value = shownResults.value.concat(results)\n    } else {\n      shownResults.value = results\n    }\n\n    isLoading.value = false\n\n    searchPage.value++\n\n    const historyPayload = {\n      query: payload.query,\n      data: shownResults.value,\n      searchSettings: searchSettings.value,\n      searchPage: searchPage.value,\n      apiUsed: apiUsed.value\n    }\n\n    store.commit('addToSessionSearchHistory', historyPayload)\n\n    updateSubscriptionDetails(results)\n  } catch (err) {\n    console.error(err)\n\n    const errorMessage = t('Invidious API Error (Click to copy)')\n    showToast(`${errorMessage}: ${err}`, 10000, () => {\n      copyToClipboard(err)\n    })\n\n    if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {\n      showToast(t('Falling back to Local API'))\n      performSearchLocal(payload)\n    } else {\n      isLoading.value = false\n      // TODO: Show toast with error message\n    }\n  }\n}\n\nfunction nextPage() {\n  const payload = {\n    query: processedQuery.value,\n    searchSettings: searchSettings.value,\n    options: {\n      nextPageRef: nextPageRef.value\n    }\n  }\n\n  if (apiUsed.value === 'local') {\n    if (nextPageRef.value !== null) {\n      showToast(t('Search Filters[\"Fetching results. Please wait\"]'))\n      getNextpageLocal(payload)\n    } else {\n      showToast(t('Search Filters.There are no more results for this search'))\n    }\n  } else {\n    showToast(t('Search Filters[\"Fetching results. Please wait\"]'))\n    performSearchInvidious(payload)\n  }\n}\n\nfunction replaceShownResults(history) {\n  query.value = history.query\n  shownResults.value = history.data\n  searchSettings.value = history.searchSettings\n  apiUsed.value = history.apiUsed\n\n  if (history.nextPageRef != null) {\n    nextPageRef.value = history.nextPageRef\n  }\n\n  if (typeof (history.searchPage) !== 'undefined') {\n    searchPage.value = history.searchPage\n  }\n\n  // This is kept in case there is some race condition\n  isLoading.value = false\n}\n\n/**\n * @param {any[]} results\n */\nfunction updateSubscriptionDetails(results) {\n  /** @type {Set<string>} */\n  const subscribedChannelIds = store.getters.getSubscribedChannelIdSet\n\n  const channels = []\n\n  for (const result of results) {\n    if (result.type !== 'channel' || !subscribedChannelIds.has(result.id ?? result.authorId)) {\n      continue\n    }\n\n    if (result.dataSource === 'local') {\n      channels.push({\n        channelId: result.id,\n        channelName: result.name,\n        channelThumbnailUrl: result.thumbnail.replace(/^\\/\\//, 'https://')\n      })\n    } else {\n      channels.push({\n        channelId: result.authorId,\n        channelName: result.author,\n        channelThumbnailUrl: result.authorThumbnails[0].url.replace(/^\\/\\//, 'https://')\n      })\n    }\n  }\n\n  if (channels.length === 1) {\n    store.dispatch('updateSubscriptionDetails', channels[0])\n  } else if (channels.length > 1) {\n    store.dispatch('batchUpdateSubscriptionDetails', channels)\n  }\n}\n</script>\n\n<style scoped src=\"./SearchPage.css\" />\n"
  },
  {
    "path": "src/renderer/views/Settings/Settings.css",
    "content": ".settingsPage {\n  display: flex;\n  gap: 20px;\n}\n\n.settingsSections,\n.switchRow {\n  overflow-x: hidden;\n  max-inline-size: 90%;\n}\n\n.switchRow {\n  display: flex;\n  margin-inline-end: auto;\n  align-items: center;\n  margin-block-end: 5px;\n}\n\n.settingsToggle {\n  padding-block: 0;\n  margin-block: 0;\n}\n\n.section {\n  /* enables anchor link clicks to land with the section title in the top quarter of the page */\n  scroll-margin-top: 24vh;\n}\n\n@media only screen and (width >= 1015px) {\n  .section + .section {\n    padding-block-start: 20px;\n  }\n\n  .settingsSections:last-child {\n    /* Add enough blank space to have the last setting section be active on the FtSettingsMenu when scrolled to */\n    margin-block-end: calc(76vh - 150px);\n  }\n}\n\n@media only screen and (width <= 1200px) {\n  .settingsSections,\n  .switchRow {\n    max-inline-size: 100%;\n  }\n}\n\n@media only screen and (width <= 1015px) {\n  /* Needed to overcome routerView styling for margin-block */\n  .settingsPage.settingsPage {\n    margin-block: 0;\n    flex-direction: column;\n    gap: 10px;\n  }\n\n  .switchRow,\n  .settingsSections {\n    margin-inline: auto;\n  }\n\n  .switchRow {\n    display: none;\n  }\n\n  .settingsSections {\n    overflow-y: hidden;\n    margin-block-end: 80px;\n  }\n\n  .hideOnMobile {\n    display: none;\n  }\n\n  .returnToMenuMobileButton {\n    margin-block-start: 20px;\n    background-color: transparent;\n    color: inherit;\n    cursor: pointer;\n    border-style: none;\n    font-size: 30px;\n    line-height: 1em;\n  }\n\n  .returnToMenuMobileIcon {\n    inline-size: 1em;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Settings/Settings.vue",
    "content": "<template>\n  <div class=\"settingsPage\">\n    <template v-if=\"unlocked\">\n      <div v-show=\"settingsSectionTypeOpenInMobile != null\">\n        <button\n          class=\"returnToMenuMobileButton\"\n          :aria-label=\"t('Settings.Return to Settings Menu')\"\n          :title=\"t('Settings.Return to Settings Menu')\"\n          @click=\"returnToSettingsMenu\"\n        >\n          <FontAwesomeIcon\n            class=\"returnToMenuMobileIcon\"\n            :icon=\"['fas', 'angle-left']\"\n          />\n        </button>\n      </div>\n      <FtSettingsMenu\n        v-show=\"isInDesktopView || settingsSectionTypeOpenInMobile == null\"\n        ref=\"menuRef\"\n        :settings-sections=\"settingsSectionComponents\"\n        :active-section=\"activeSection\"\n        @navigate-to-section=\"navigateToSection\"\n      />\n      <div\n        v-show=\"isInDesktopView || settingsSectionTypeOpenInMobile != null\"\n        class=\"settingsContent\"\n      >\n        <div class=\"switchRow\">\n          <FtButton\n            v-if=\"USING_ELECTRON\"\n            :label=\"t('KeyboardShortcutPrompt.Show Keyboard Shortcuts')\"\n            :icon=\"['fas', 'keyboard']\"\n            @click=\"showKeyboardShortcutPrompt\"\n          />\n          <FtToggleSwitch\n            class=\"settingsToggle\"\n            :label=\"t('Settings.Sort Settings Sections (A-Z)')\"\n            :default-value=\"settingsSectionSortEnabled\"\n            @change=\"updateSettingsSectionSortEnabled\"\n          />\n        </div>\n        <div class=\"settingsSections\">\n          <component\n            :is=\"section.component\"\n            v-for=\"section in settingsSectionComponents\"\n            :key=\"section.type\"\n            ref=\"sectionRefs\"\n            class=\"section\"\n            :class=\"{ hideOnMobile: settingsSectionTypeOpenInMobile !== section.type }\"\n            :data-section=\"section.type\"\n          />\n        </div>\n      </div>\n    </template>\n    <PasswordDialog\n      v-else\n      @unlocked=\"handleUnlock\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport GeneralSettings from '../../components/GeneralSettings/GeneralSettings.vue'\nimport ThemeSettings from '../../components/ThemeSettings.vue'\nimport PlayerSettings from '../../components/PlayerSettings/PlayerSettings.vue'\nimport ExternalPlayerSettings from '../../components/ExternalPlayerSettings.vue'\nimport SubscriptionSettings from '../../components/SubscriptionSettings/SubscriptionSettings.vue'\nimport PrivacySettings from '../../components/PrivacySettings.vue'\nimport DataSettings from '../../components/DataSettings/DataSettings.vue'\nimport DistractionSettings from '../../components/DistractionSettings/DistractionSettings.vue'\nimport ProxySettings from '../../components/ProxySettings/ProxySettings.vue'\nimport SponsorBlockSettings from '../../components/SponsorBlockSettings.vue'\nimport ParentalControlSettings from '../../components/ParentalControlSettings.vue'\nimport ExperimentalSettings from '../../components/ExperimentalSettings/ExperimentalSettings.vue'\nimport PasswordSettings from '../../components/PasswordSettings/PasswordSettings.vue'\nimport PasswordDialog from '../../components/PasswordDialog/PasswordDialog.vue'\nimport FtToggleSwitch from '../../components/FtToggleSwitch/FtToggleSwitch.vue'\nimport FtButton from '../../components/FtButton/FtButton.vue'\nimport FtSettingsMenu from '../../components/FtSettingsMenu/FtSettingsMenu.vue'\n\nimport store from '../../store/index'\n\nconst USING_ELECTRON = !!process.env.IS_ELECTRON\nconst SETTINGS_MOBILE_WIDTH_THRESHOLD = 1015\n\nconst { locale, t } = useI18n()\n\nconst isInDesktopView = ref(true)\nconst settingsSectionTypeOpenInMobile = ref(null)\nconst activeSection = ref(null)\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst settingsSectionSortEnabled = computed(() => store.getters.getSettingsSectionSortEnabled)\n\nconst settingsComponentsData = computed(() => {\n  return [\n    {\n      type: 'theme',\n      title: t('Settings.Theme Settings.Theme Settings'),\n      icon: ['fas', 'display'],\n      component: ThemeSettings\n    },\n    {\n      type: 'player',\n      title: t('Settings.Player Settings.Player Settings'),\n      icon: ['fas', 'circle-play'],\n      component: PlayerSettings\n    },\n    ...(process.env.IS_ELECTRON\n      ? [{\n          type: 'external-player',\n          title: t('Settings.External Player Settings.External Player Settings'),\n          icon: ['fas', 'clapperboard'],\n          component: ExternalPlayerSettings\n        }]\n      : []),\n    {\n      type: 'subscription',\n      title: t('Settings.Subscription Settings.Subscription Settings'),\n      icon: ['fas', 'play'],\n      component: SubscriptionSettings\n    },\n    {\n      type: 'distraction',\n      title: t('Settings.Distraction Free Settings.Distraction Free Settings'),\n      icon: ['fas', 'eye-slash'],\n      component: DistractionSettings\n    },\n    {\n      type: 'parental-control',\n      title: t('Settings.Parental Control Settings.Parental Control Settings'),\n      icon: ['fas', 'user-lock'],\n      component: ParentalControlSettings\n    },\n    {\n      type: 'privacy',\n      title: t('Settings.Privacy Settings.Privacy Settings'),\n      icon: ['fas', 'lock'],\n      component: PrivacySettings\n    },\n    {\n      type: 'data',\n      title: t('Settings.Data Settings.Data Settings'),\n      icon: ['fas', 'database'],\n      component: DataSettings\n    },\n    ...(process.env.IS_ELECTRON\n      ? [\n          {\n            type: 'proxy',\n            title: t('Settings.Proxy Settings.Proxy Settings'),\n            icon: ['fas', 'network-wired'],\n            component: ProxySettings\n          }\n        ]\n      : []),\n    {\n      type: 'sponsor-block',\n      title: t('Settings.SponsorBlock Settings.SponsorBlock Settings'),\n      // TODO: replace with SponsorBlock icon\n      icon: ['fas', 'shield'],\n      component: SponsorBlockSettings\n    },\n    {\n      type: 'password',\n      title: t('Settings.Password Settings.Password Settings'),\n      icon: ['fas', 'key'],\n      component: PasswordSettings\n    },\n    ...(process.env.IS_ELECTRON\n      ? [{\n          type: 'experimental',\n          title: t('Settings.Experimental Settings.Experimental Settings'),\n          icon: ['fas', 'flask'],\n          component: ExperimentalSettings\n        }]\n      : []),\n  ]\n})\n\nconst collator = computed(() => {\n  return new Intl.Collator([locale.value, 'en'], { sensitivity: 'base' })\n})\n\nconst settingsSectionComponents = computed(() => {\n  let settingsSections = settingsComponentsData.value\n\n  if (settingsSectionSortEnabled.value) {\n    const collator_ = collator.value\n\n    settingsSections = settingsSections.toSorted((a, b) => {\n      return collator_.compare(a.title, b.title)\n    })\n  }\n\n  // ensure General Settings is placed first regardless of sorting\n  const generalSettingsEntry = {\n    type: 'general',\n    title: t('Settings.General Settings.General Settings'),\n    icon: ['fas', 'border-all'],\n    component: GeneralSettings\n  }\n\n  return [generalSettingsEntry, ...settingsSections]\n})\n\nconst unlocked = ref(store.getters.getSettingsPassword === '')\n\nif (unlocked.value) {\n  onMounted(handleMounted)\n}\n\nfunction handleUnlock() {\n  unlocked.value = true\n\n  nextTick(() => {\n    handleMounted()\n  })\n}\n\nonBeforeUnmount(() => {\n  document.removeEventListener('scroll', markScrolledToSectionAsActive)\n  window.removeEventListener('resize', handleResize)\n})\n\nfunction showKeyboardShortcutPrompt() {\n  store.dispatch('showKeyboardShortcutPrompt')\n}\n\n/**\n * @param {boolean} value\n */\nfunction updateSettingsSectionSortEnabled(value) {\n  store.dispatch('updateSettingsSectionSortEnabled', value)\n}\n\nfunction handleMounted() {\n  handleResize()\n  window.addEventListener('resize', handleResize)\n  document.addEventListener('scroll', markScrolledToSectionAsActive)\n\n  // mark first section as active before any scrolling has taken place\n  activeSection.value = settingsSectionComponents.value[0].type\n}\n\nconst sectionRefs = useTemplateRef('sectionRefs')\n\n/**\n * @param {string} sectionType\n */\nfunction navigateToSection(sectionType) {\n  if (isInDesktopView.value) {\n    nextTick(() => {\n      const sectionElement = sectionRefs.value.find(sectionRef => {\n        return sectionRef.$el.dataset.section === sectionType\n      })?.$el\n      sectionElement.scrollIntoView()\n\n      const sectionHeading = sectionElement.firstChild.firstChild\n      sectionHeading.tabIndex = 0\n      sectionHeading.focus()\n      sectionHeading.tabIndex = -1\n    })\n  } else {\n    settingsSectionTypeOpenInMobile.value = sectionType\n  }\n}\n\nconst menuRef = useTemplateRef('menuRef')\n\nfunction returnToSettingsMenu() {\n  const openSection = settingsSectionTypeOpenInMobile.value\n  settingsSectionTypeOpenInMobile.value = null\n\n  // focus the corresponding Settings Menu title\n  nextTick(() => {\n    return menuRef.value?.focusLink(openSection)\n  })\n}\n\n/* Set the current section to be shown as active in the Settings Menu\n* if it is the lowest section within the top quarter of the viewport (25vh) */\nfunction markScrolledToSectionAsActive() {\n  if (!isInDesktopView.value) {\n    activeSection.value = null\n    return\n  }\n\n  const scrollY = window.scrollY + window.innerHeight / 4\n\n  for (const sectionRef of sectionRefs.value) {\n    const sectionElement = sectionRef.$el\n\n    const sectionHeight = sectionElement.offsetHeight\n    const sectionTop = sectionElement.offsetTop\n\n    if (scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) {\n      activeSection.value = sectionElement.dataset.section\n      break\n    }\n  }\n}\n\nfunction handleResize() {\n  const wasNotInDesktopView = !isInDesktopView.value\n  isInDesktopView.value = window.innerWidth > SETTINGS_MOBILE_WIDTH_THRESHOLD\n\n  // navigate to section that was open in mobile or desktop view, if any\n  if (isInDesktopView.value && wasNotInDesktopView && settingsSectionTypeOpenInMobile.value != null) {\n    navigateToSection(settingsSectionTypeOpenInMobile.value)\n    settingsSectionTypeOpenInMobile.value = null\n  } else if (!isInDesktopView.value && !wasNotInDesktopView && activeSection.value) {\n    navigateToSection(activeSection.value)\n  }\n}\n</script>\n\n<style scoped src=\"./Settings.css\" />\n"
  },
  {
    "path": "src/renderer/views/SubscribedChannels/SubscribedChannels.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.count {\n  margin-block-start: 1rem;\n}\n\n.channels {\n  inline-size: 100%;\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));\n  gap: 2.5rem;\n  margin-block-start: 2rem;\n}\n\n.channel {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  row-gap: 0.75rem;\n  padding: 0.5rem;\n}\n\n.thumbnailContainer {\n  flex-grow: 0;\n  display: flex;\n  align-items: center;\n  color: inherit;\n}\n\n.channelThumbnail {\n  block-size: 120px;\n  border-radius: 50%;\n}\n\n.channelName {\n  flex-grow: 1;\n  color: inherit;\n  font-size: 1.1rem;\n  text-decoration: none;\n  text-align: center;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n  inline-size: 100%;\n  display: -webkit-box;\n  line-clamp: 3;\n  -webkit-line-clamp: 3;\n  -webkit-box-orient: vertical;\n  padding-block: 0;\n  padding-inline: 4px;\n}\n\n.unsubscribeContainer {\n  flex-grow: 0;\n  display: flex;\n  align-items: center;\n}\n\n.unsubscribeContainer .btn {\n  block-size: 80%;\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n\n  .channels {\n    gap: 1.5rem;\n  }\n\n  .channelThumbnail {\n    block-size: 80px;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/SubscribedChannels/SubscribedChannels.vue",
    "content": "<template>\n  <div>\n    <ft-card class=\"card\">\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'user-check']\"\n          class=\"headingIcon\"\n        />\n        {{ $t('Channels.Title') }}\n      </h2>\n      <ft-input\n        v-show=\"subscribedChannels.length > 1\"\n        ref=\"searchBarChannels\"\n        :placeholder=\"$t('Channels.Search bar placeholder')\"\n        :value=\"query\"\n        :show-clear-text-button=\"true\"\n        :show-action-button=\"false\"\n        :maxlength=\"255\"\n        @input=\"handleQueryChange\"\n        @clear=\"() => handleQueryChange('')\"\n      />\n      <ft-flex-box\n        v-if=\"activeSubscriptionList.length === 0\"\n      >\n        <p class=\"message\">\n          {{ $t('Channels.Empty') }}\n        </p>\n      </ft-flex-box>\n      <template v-else>\n        <ft-flex-box class=\"count\">\n          {{ $t('Channels.Count', { number: channelList.length }) }}\n        </ft-flex-box>\n        <ft-flex-box class=\"channels\">\n          <div\n            v-for=\"channel in channelList\"\n            :key=\"channel.id\"\n            class=\"channel\"\n          >\n            <router-link\n              tabindex=\"-1\"\n              class=\"thumbnailContainer\"\n              :to=\"`/channel/${channel.id}`\"\n            >\n              <img\n                v-if=\"channel.thumbnail != null\"\n                class=\"channelThumbnail\"\n                :src=\"thumbnailURL(channel.thumbnail)\"\n                alt=\"\"\n                @error.once=\"updateThumbnail(channel)\"\n              >\n              <font-awesome-icon\n                v-else\n                class=\"channelThumbnail\"\n                :icon=\"['fas', 'circle-user']\"\n              />\n            </router-link>\n            <router-link\n              class=\"channelName\"\n              dir=\"auto\"\n              :title=\"channel.name\"\n              :to=\"`/channel/${channel.id}`\"\n            >\n              {{ channel.name }}\n            </router-link>\n            <div\n              v-if=\"!hideUnsubscribeButton\"\n              class=\"unsubscribeContainer\"\n            >\n              <ft-subscribe-button\n                :channel-id=\"channel.id\"\n                :channel-name=\"channel.name\"\n                :channel-thumbnail=\"channel.thumbnail\"\n                :open-dropdown-on-subscribe=\"false\"\n              />\n            </div>\n          </div>\n        </ft-flex-box>\n      </template>\n    </ft-card>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onMounted, onBeforeUnmount, ref, watch, useTemplateRef } from 'vue'\nimport { isNavigationFailure, NavigationFailureType, useRoute, useRouter } from 'vue-router'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtInput from '../../components/FtInput/FtInput.vue'\nimport FtSubscribeButton from '../../components/FtSubscribeButton/FtSubscribeButton.vue'\nimport { invidiousGetChannelInfo, youtubeImageUrlToInvidious, invidiousImageUrlToInvidious } from '../../helpers/api/invidious'\nimport { getLocalChannel, parseLocalChannelHeader } from '../../helpers/api/local'\nimport { ctrlFHandler, debounce } from '../../helpers/utils'\nimport { useI18n } from '../../composables/use-i18n-polyfill.js'\nimport store from '../../store/index'\n\nconst route = useRoute()\nconst router = useRouter()\nconst { locale } = useI18n()\n\nconst re = {\n  url: /(.+=\\w)\\d+(.+)/,\n  ivToYt: /^.+ggpht\\/(.+)/\n}\nconst ytBaseURL = 'https://yt3.ggpht.com'\nconst thumbnailSize = 176\nlet errorCount = 0\n\nconst query = ref('')\nconst subscribedChannels = ref([])\nconst filteredChannels = ref([])\n\nconst searchBarChannels = useTemplateRef('searchBarChannels')\n\n/** @type {import('vue').ComputedRef<object>} */\nconst activeProfile = computed(() => {\n  return store.getters.getActiveProfile\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst activeProfileId = computed(() => {\n  return activeProfile.value._id\n})\n\n/** @type {import('vue').ComputedRef<Array>} */\nconst activeSubscriptionList = computed(() => {\n  return activeProfile.value.subscriptions\n})\n\n/** @type {import('vue').ComputedRef<Array>} */\nconst channelList = computed(() => {\n  if (query.value !== '') {\n    return filteredChannels.value\n  } else {\n    return subscribedChannels.value\n  }\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideUnsubscribeButton = computed(() => {\n  return store.getters.getHideUnsubscribeButton\n})\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst currentInvidiousInstanceUrl = computed(() => {\n  return store.getters.getCurrentInvidiousInstanceUrl\n})\n\nfunction getSubscription() {\n  subscribedChannels.value = activeSubscriptionList.value.slice().sort((a, b) => {\n    return a.name?.toLowerCase().localeCompare(b.name?.toLowerCase(), locale.value)\n  })\n}\n\nfunction filterChannels() {\n  if (query.value === '') {\n    filteredChannels.value = []\n    return\n  }\n\n  const escapedQuery = query.value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&')\n  const re = new RegExp(escapedQuery, 'i')\n  filteredChannels.value = subscribedChannels.value.filter(channel => {\n    return re.test(channel.name)\n  })\n}\n\nconst filterChannelsDebounce = debounce(filterChannels, 500)\n\nfunction thumbnailURL(originalURL) {\n  if (originalURL == null) { return null }\n  let newURL = originalURL\n  // Sometimes relative protocol URLs are passed in\n  if (originalURL.startsWith('//')) {\n    newURL = `https:${originalURL}`\n  }\n  const hostname = new URL(newURL).hostname\n  if (hostname === 'yt3.ggpht.com' || hostname === 'yt3.googleusercontent.com') {\n    if (backendPreference.value === 'invidious') { // YT to IV\n      newURL = youtubeImageUrlToInvidious(newURL, currentInvidiousInstanceUrl.value)\n    }\n  } else {\n    if (backendPreference.value === 'local') { // IV to YT\n      newURL = newURL.replace(re.ivToYt, `${ytBaseURL}/$1`)\n    } else { // IV to IV\n      newURL = invidiousImageUrlToInvidious(newURL, currentInvidiousInstanceUrl.value)\n    }\n  }\n\n  return newURL.replace(re.url, `$1${thumbnailSize}$2`)\n}\n\nfunction updateThumbnail(channel) {\n  errorCount += 1\n  if (backendPreference.value === 'local') {\n    // avoid too many concurrent requests\n    setTimeout(() => {\n      getLocalChannel(channel.id).then(response => {\n        if (!response.alert) {\n          store.dispatch('updateSubscriptionDetails', {\n            channelThumbnailUrl: thumbnailURL(parseLocalChannelHeader(response).thumbnailUrl),\n            channelName: channel.name,\n            channelId: channel.id\n          })\n        }\n      })\n    }, errorCount * 500)\n  } else {\n    setTimeout(() => {\n      invidiousGetChannelInfo(channel.id).then(response => {\n        store.dispatch('updateSubscriptionDetails', {\n          channelThumbnailUrl: thumbnailURL(response.authorThumbnails[0].url),\n          channelName: channel.name,\n          channelId: channel.id\n        })\n      })\n    }, errorCount * 500)\n  }\n}\n\nfunction handleQueryChange(val, filterNow = false) {\n  query.value = val\n\n  saveStateInRouter(val)\n\n  filterNow ? filterChannels() : filterChannelsDebounce()\n}\n\nasync function saveStateInRouter(query) {\n  if (query.value === '') {\n    await router.replace({ name: 'subscribedChannels' }).catch(failure => {\n      if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n        return\n      }\n\n      throw failure\n    })\n    return\n  }\n\n  await router.replace({\n    name: 'subscribedChannels',\n    query: { searchQueryText: query },\n  }).catch(failure => {\n    if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n      return\n    }\n\n    throw failure\n  })\n}\n\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchBarChannels.value)\n}\n\nwatch(activeProfileId, () => {\n  query.value = ''\n  getSubscription()\n})\n\nwatch(activeSubscriptionList, () => {\n  getSubscription()\n  filterChannels()\n})\n\n// region created\n\ngetSubscription()\n\nconst oldQuery = route.query.searchQueryText ?? ''\nif (oldQuery !== null && oldQuery !== '') {\n  // `handleQueryChange` must be called after `filterHistoryDebounce` assigned\n  handleQueryChange(oldQuery, true)\n}\n\n// endregion created\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n</script>\n<style scoped src=\"./SubscribedChannels.css\" />\n"
  },
  {
    "path": "src/renderer/views/Subscriptions/Subscriptions.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.tabs {\n  inline-size: 100%;\n  margin-block: -3px 10px;\n  color: var(--tertiary-text-color);\n}\n\n.selectedTab {\n  border-block-end: 3px solid var(--primary-color);\n  color: var(--primary-text-color);\n  font-weight: bold;\n  box-sizing: border-box;\n  margin-block-end: -3px;\n}\n\n.tab {\n  text-align: center;\n  padding: 15px;\n  font-size: 1.1em;\n  cursor: pointer;\n  align-self: flex-end;\n}\n\n.tab:hover {\n  font-weight: bold;\n}\n\n.subscriptionIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Subscriptions/Subscriptions.vue",
    "content": "<template>\n  <div>\n    <FtCard class=\"card\">\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'rss']\"\n          class=\"subscriptionIcon\"\n        />\n        {{ $t(\"Subscriptions.Subscriptions\") }}\n      </h2>\n      <FtFlexBox\n        class=\"tabs\"\n        role=\"tablist\"\n        :aria-label=\"$t('Subscriptions.Subscriptions Tabs')\"\n      >\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          v-if=\"!hideSubscriptionsVideos\"\n          ref=\"videosTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'videos'\"\n          aria-controls=\"subscriptionsPanel\"\n          :tabindex=\"currentTab === 'videos' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'videos' }\"\n          @click=\"changeTab('videos')\"\n          @keydown.space.enter.prevent=\"changeTab('videos')\"\n          @keydown.left.right=\"focusTab($event, 'videos')\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fa', 'video']\"\n            class=\"subscriptionIcon\"\n          />\n          {{ $t(\"Global.Videos\") }}\n        </div>\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          v-if=\"!hideSubscriptionsShorts\"\n          ref=\"shortsTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'shorts'\"\n          aria-controls=\"subscriptionsPanel\"\n          :tabindex=\"currentTab === 'shorts' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'shorts' }\"\n          @click=\"changeTab('shorts')\"\n          @keydown.space.enter.prevent=\"changeTab('shorts')\"\n          @keydown.left.right=\"focusTab($event, 'shorts')\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fa', 'clapperboard']\"\n            class=\"subscriptionIcon\"\n          />\n          {{ $t(\"Global.Shorts\") }}\n        </div>\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          v-if=\"!hideSubscriptionsLive\"\n          ref=\"liveTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'live'\"\n          aria-controls=\"subscriptionsPanel\"\n          :tabindex=\"currentTab === 'live' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'live' }\"\n          @click=\"changeTab('live')\"\n          @keydown.space.enter.prevent=\"changeTab('live')\"\n          @keydown.left.right=\"focusTab($event, 'live')\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fa', 'tower-broadcast']\"\n            class=\"subscriptionIcon\"\n          />\n          {{ $t(\"Global.Live\") }}\n        </div>\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          v-if=\"visibleTabs.includes('community')\"\n          ref=\"communityTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'community'\"\n          aria-controls=\"subscriptionsPanel\"\n          :tabindex=\"currentTab === 'community' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'community' }\"\n          @click=\"changeTab('community')\"\n          @keydown.space.enter.prevent=\"changeTab('community')\"\n          @keydown.left.right=\"focusTab($event, 'community')\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fa', 'message']\"\n            class=\"subscriptionIcon\"\n          />\n          {{ $t(\"Global.Posts\") }}\n        </div>\n      </FtFlexBox>\n      <SubscriptionsVideos\n        v-if=\"currentTab === 'videos'\"\n        id=\"subscriptionsPanel\"\n        role=\"tabpanel\"\n      />\n      <SubscriptionsShorts\n        v-else-if=\"currentTab === 'shorts'\"\n        id=\"subscriptionsPanel\"\n        role=\"tabpanel\"\n      />\n      <SubscriptionsLive\n        v-else-if=\"currentTab === 'live'\"\n        id=\"subscriptionsPanel\"\n        role=\"tabpanel\"\n      />\n      <SubscriptionsPosts\n        v-else-if=\"currentTab === 'community'\"\n        id=\"subscriptionsPanel\"\n        role=\"tabpanel\"\n      />\n      <p v-else>\n        {{ $t(\"Subscriptions.All Subscription Tabs Hidden\", {\n          subsection: $t('Settings.Distraction Free Settings.Sections.Subscriptions Page'),\n          settingsSection: $t('Settings.Distraction Free Settings.Distraction Free Settings')\n        }) }}\n      </p>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\n\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport SubscriptionsVideos from '../../components/SubscriptionsVideos.vue'\nimport SubscriptionsLive from '../../components/SubscriptionsLive.vue'\nimport SubscriptionsShorts from '../../components/SubscriptionsShorts.vue'\nimport SubscriptionsPosts from '../../components/SubscriptionsPosts.vue'\n\nimport store from '../../store/index'\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsVideos = computed(() => {\n  return store.getters.getHideSubscriptionsVideos\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsShorts = computed(() => {\n  return store.getters.getHideSubscriptionsShorts\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsLive = computed(() => {\n  return store.getters.getHideLiveStreams || store.getters.getHideSubscriptionsLive\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst hideSubscriptionsCommunity = computed(() => {\n  return store.getters.getHideSubscriptionsCommunity\n})\n\n/** @type {import('vue').ComputedRef<any[]>} */\nconst activeSubscriptionList = computed(() => {\n  return store.getters.getActiveProfile.subscriptions\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst useRssFeeds = computed(() => {\n  return store.getters.getUseRssFeeds\n})\n\n/** @type {import('vue').Ref<'videos' | 'shorts' | 'live' | 'community' | null>} */\nconst currentTab = ref('videos')\n\nwatch(currentTab, (value) => {\n  if (value !== null) {\n  // Save last used tab, restore when view mounted again\n    sessionStorage.setItem('Subscriptions/currentTab', value)\n  } else {\n    sessionStorage.removeItem('Subscriptions/currentTab')\n  }\n})\n\nconst visibleTabs = computed(() => {\n  /** @type {('videos' | 'shorts' | 'live' | 'community')[]} */\n  const tabs = []\n\n  if (!hideSubscriptionsVideos.value) {\n    tabs.push('videos')\n  }\n\n  if (!hideSubscriptionsShorts.value) {\n    tabs.push('shorts')\n  }\n\n  if (!hideSubscriptionsLive.value) {\n    tabs.push('live')\n  }\n\n  // community does not support rss\n  if (!hideSubscriptionsCommunity.value && !useRssFeeds.value && activeSubscriptionList.value.length < 125) {\n    tabs.push('community')\n  }\n\n  return tabs\n})\n\nwatch(visibleTabs, (value) => {\n  if (value.length === 0) {\n    currentTab.value = null\n  } else if (!value.includes(currentTab.value)) {\n    currentTab.value = value[0]\n  }\n})\n\nif (visibleTabs.value.length === 0) {\n  currentTab.value = null\n} else {\n  // Restore currentTab\n  const lastCurrentTabId = sessionStorage.getItem('Subscriptions/currentTab')\n  if (lastCurrentTabId !== null) {\n    changeTab(lastCurrentTabId)\n  } else if (!visibleTabs.value.includes(currentTab.value)) {\n    currentTab.value = visibleTabs.value[0]\n  }\n}\n\n/**\n * @param {'videos' | 'shorts' | 'live' | 'community'} tab\n */\nfunction changeTab(tab) {\n  if (tab === currentTab.value) {\n    return\n  }\n\n  if (visibleTabs.value.includes(tab)) {\n    currentTab.value = tab\n  } else {\n    // First visible tab or no tab\n    currentTab.value = visibleTabs.value.length > 0 ? visibleTabs.value[0] : null\n  }\n}\n\nconst videosTab = useTemplateRef('videosTab')\nconst liveTab = useTemplateRef('liveTab')\nconst shortsTab = useTemplateRef('shortsTab')\nconst communityTab = useTemplateRef('communityTab')\n\n/**\n * @param {KeyboardEvent} event\n * @param {'videos' | 'shorts' | 'live' | 'community'} focusedTab\n */\nfunction focusTab(event, focusedTab) {\n  if (event.altKey) {\n    return\n  }\n\n  event.preventDefault()\n\n  const visibleTabsCached = visibleTabs.value\n\n  if (visibleTabsCached.length === 1) {\n    store.commit('setOutlinesHidden', false)\n    return\n  }\n\n  let index = visibleTabsCached.indexOf(focusedTab)\n\n  if (event.key === 'ArrowLeft') {\n    index--\n  } else {\n    index++\n  }\n\n  if (index < 0) {\n    index = visibleTabsCached.length - 1\n  } else if (index > visibleTabsCached.length - 1) {\n    index = 0\n  }\n\n  switch (visibleTabsCached[index]) {\n    case 'videos':\n      videosTab.value?.focus()\n      break\n    case 'live':\n      liveTab.value?.focus()\n      break\n    case 'shorts':\n      shortsTab.value?.focus()\n      break\n    case 'community':\n      communityTab.value?.focus()\n      break\n  }\n\n  store.commit('setOutlinesHidden', false)\n}\n</script>\n\n<style scoped src=\"./Subscriptions.css\" />\n"
  },
  {
    "path": "src/renderer/views/Trending/Trending.css",
    "content": ".card {\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.trendingInfoTabs {\n  inline-size: 100%;\n  display: grid;\n  grid-template-columns: 1fr 1fr 1fr;\n  margin-block: -3px 10px;\n  color: var(--tertiary-text-color);\n}\n\n.selectedTab {\n  border-block-end: 3px solid var(--primary-color);\n  color: var(--primary-text-color);\n  font-weight: bold;\n  box-sizing: border-box;\n  margin-block-end: -3px;\n}\n\n.tab {\n  text-align: center;\n  padding: 15px;\n  font-size: 1.1em;\n  cursor: pointer;\n  align-self: flex-end;\n}\n\n.tab:hover {\n  font-weight: bold;\n}\n\n.trendingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Trending/Trending.vue",
    "content": "<template>\n  <div>\n    <FtCard\n      class=\"card\"\n    >\n      <h2>\n        <FontAwesomeIcon\n          :icon=\"['fas', 'fire']\"\n          class=\"trendingIcon\"\n        />\n        {{ $t(\"Trending.Trending\") }}\n      </h2>\n      <FtFlexBox\n        class=\"trendingInfoTabs\"\n        role=\"tablist\"\n        :aria-label=\"$t('Trending.Trending Tabs')\"\n      >\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          ref=\"gamingTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'gaming'\"\n          aria-controls=\"trendingPanel\"\n          :tabindex=\"currentTab === 'gaming' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'gaming' }\"\n          @click=\"changeTab('gaming')\"\n          @keydown.space.enter.prevent=\"changeTab('gaming')\"\n          @keydown.left=\"focusTab('podcasts', $event)\"\n          @keydown.right=\"focusTab('sports', $event)\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'gamepad']\"\n            class=\"trendingIcon\"\n          />\n          {{ $t(\"Trending.Gaming\") }}\n        </div>\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          ref=\"sportsTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'sports'\"\n          aria-controls=\"trendingPanel\"\n          :tabindex=\"currentTab === 'sports' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'sports' }\"\n          @click=\"changeTab('sports')\"\n          @keydown.space.enter.prevent=\"changeTab('sports')\"\n          @keydown.left=\"focusTab('gaming', $event)\"\n          @keydown.right=\"focusTab('podcasts', $event)\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'trophy']\"\n            class=\"trendingIcon\"\n          />\n          {{ t(\"Trending.Sports\") }}\n        </div>\n        <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -->\n        <div\n          ref=\"podcastsTab\"\n          class=\"tab\"\n          role=\"tab\"\n          :aria-selected=\"currentTab === 'podcasts'\"\n          aria-controls=\"trendingPanel\"\n          :tabindex=\"currentTab === 'podcasts' ? 0 : -1\"\n          :class=\"{ selectedTab: currentTab === 'podcasts' }\"\n          @click=\"changeTab('podcasts')\"\n          @keydown.space.enter.prevent=\"changeTab('podcasts')\"\n          @keydown.left=\"focusTab('sports', $event)\"\n          @keydown.right=\"focusTab('gaming', $event)\"\n        >\n          <FontAwesomeIcon\n            :icon=\"['fas', 'podcast']\"\n            class=\"trendingIcon\"\n          />\n          {{ t(\"Channel.Podcasts.Podcasts\") }}\n        </div>\n      </FtFlexBox>\n      <div\n        id=\"trendingPanel\"\n        role=\"tabpanel\"\n      >\n        <FtLoader\n          v-if=\"isLoading[currentTab]\"\n        />\n        <FtElementList\n          v-else\n          :data=\"shownResults\"\n        />\n      </div>\n    </FtCard>\n    <FtRefreshWidget\n      :disable-refresh=\"isLoading[currentTab]\"\n      :last-refresh-timestamp=\"lastTrendingRefreshTimestamp\"\n      :title=\"$t('Trending.Trending')\"\n      @click=\"getTrendingInfo(true)\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\n\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtRefreshWidget from '../../components/FtRefreshWidget/FtRefreshWidget.vue'\n\nimport store from '../../store/index'\n\nimport { copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils'\nimport { getLocalTrending } from '../../helpers/api/local'\nimport { KeyboardShortcuts } from '../../../constants'\n\nconst { t } = useI18n()\n\n/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */\nconst backendPreference = computed(() => {\n  return store.getters.getBackendPreference\n})\n\n/** @type {import('vue').ComputedRef<boolean>} */\nconst backendFallback = computed(() => {\n  return store.getters.getBackendFallback\n})\n\nconst lastTrendingRefreshTimestamp = computed(() => {\n  return getRelativeTimeFromDate(store.getters.getLastTrendingRefreshTimestamp[currentTab.value], true)\n})\n\n/** @type {import('vue').ComputedRef<string>} */\nconst region = computed(() => {\n  return store.getters.getRegion.toUpperCase()\n})\n\n/** @type {import('vue').ComputedRef<{ gaming: any[] | null, sports: any[] | null, podcasts: any[] | null }>} */\nconst trendingCache = computed(() => {\n  return store.getters.getTrendingCache\n})\n\nconst isLoading = ref({ gaming: false, sports: false, podcasts: false })\nconst shownResults = shallowRef([])\n\n/** @type {import('vue').Ref<'gaming' | 'sports' | 'podcasts'>} */\nconst currentTab = ref('gaming')\n\nconst cacheEntry = trendingCache.value[currentTab.value]\n\nif (cacheEntry && cacheEntry.length > 0) {\n  shownResults.value = cacheEntry\n} else {\n  onMounted(() => {\n    getTrendingInfo()\n  })\n}\n\nfunction getTrendingInfo(refresh = false) {\n  if (refresh) {\n    store.commit('clearTrendingCache', currentTab.value)\n  }\n\n  if (process.env.SUPPORTS_LOCAL_API && (backendFallback.value || backendPreference.value === 'local')) {\n    getTrendingInfoLocal()\n  }\n\n  store.commit('setLastTrendingRefreshTimestamp', { page: currentTab.value, timestamp: new Date() })\n}\n\nasync function getTrendingInfoLocal() {\n  isLoading.value[currentTab.value] = true\n\n  try {\n    const results = await getLocalTrending(region.value, currentTab.value)\n\n    shownResults.value = results\n    isLoading.value[currentTab.value] = false\n\n    store.commit('setTrendingCache', { value: results, page: currentTab.value })\n    nextTick(() => {\n      focusTab(currentTab.value)\n    })\n  } catch (error) {\n    console.error(error)\n    const errorMessage = t('Local API Error (Click to copy)')\n    showToast(`${errorMessage}: ${error}`, 10000, () => {\n      copyToClipboard(error)\n    })\n    isLoading.value[currentTab.value] = false\n  }\n}\n\nconst gamingTab = useTemplateRef('gamingTab')\nconst sportsTab = useTemplateRef('sportsTab')\nconst podcastsTab = useTemplateRef('podcastsTab')\n\n/**\n * @param {'gaming' | 'sports' | 'podcasts'} tab\n * @param {KeyboardEvent | undefined} event\n */\nfunction focusTab(tab, event = undefined) {\n  if (event) {\n    if (event.altKey) { return }\n\n    event.preventDefault()\n    store.dispatch('showOutlines')\n  }\n\n  switch (tab) {\n    case 'gaming':\n      gamingTab.value?.focus()\n      break\n    case 'sports':\n      sportsTab.value?.focus()\n      break\n    case 'podcasts':\n      podcastsTab.value?.focus()\n      break\n  }\n}\n\n/**\n * @param {'gaming' | 'sports' | 'podcasts'} tab\n */\nfunction changeTab(tab) {\n  if (tab === currentTab.value) {\n    return\n  }\n\n  currentTab.value = tab\n\n  const cacheEntry = trendingCache.value[currentTab.value]\n\n  if (cacheEntry && cacheEntry.length > 0) {\n    shownResults.value = cacheEntry\n  } else {\n    getTrendingInfo()\n  }\n}\n\n/**\n * @param {KeyboardEvent} event the keyboard event\n */\nfunction keyboardShortcutHandler(event) {\n  if (document.activeElement.classList.contains('ft-input')) {\n    return\n  }\n\n  // Avoid handling events due to user holding a key (not released)\n  // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat\n  if (event.repeat) { return }\n\n  switch (event.key.toLowerCase()) {\n    case 'f5':\n    case KeyboardShortcuts.APP.SITUATIONAL.REFRESH:\n      if (!isLoading.value[currentTab.value]) {\n        getTrendingInfo(true)\n      }\n      break\n  }\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n</script>\n\n<style scoped src=\"./Trending.css\" />\n"
  },
  {
    "path": "src/renderer/views/UserPlaylists/UserPlaylists.css",
    "content": ".card {\n  position: relative;\n  inline-size: 85%;\n  margin-block: 0 60px;\n  margin-inline: auto;\n}\n\n.headingText {\n  display: inline-block;\n}\n\n.newPlaylistButton {\n  margin-inline-start: 0.5em;\n  display: inline-block;\n  vertical-align: middle;\n}\n\n.searchInputsRow {\n  display: grid;\n\n  /* 2 columns */\n  grid-template-columns: 1fr auto;\n  column-gap: 16px;\n}\n\n@media only screen and (width <= 800px) {\n  .searchInputsRow {\n    /* Switch to 2 rows from 2 columns */\n    grid-template-columns: auto;\n    grid-template-rows: auto auto;\n  }\n}\n\n.optionsRow {\n  display: grid;\n  grid-template-columns: repeat(2, 1fr);\n  grid-template-rows: 1fr;\n  align-items: center;\n}\n\n@media only screen and (width <= 800px) {\n  .optionsRow {\n    /* Switch to 2 rows from 2 columns */\n    grid-template-columns: auto;\n    grid-template-rows: auto auto;\n    align-items: stretch;\n  }\n}\n\n.sortSelect {\n  /* Put it on the right */\n  margin-inline-start: auto;\n}\n\n.message {\n  color: var(--tertiary-text-color);\n}\n\n.headingIcon {\n  color: var(--primary-color);\n}\n\n@media only screen and (width <= 680px) {\n  .card {\n    inline-size: 90%;\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/UserPlaylists/UserPlaylists.vue",
    "content": "<template>\n  <div>\n    <FtCard\n      class=\"card\"\n    >\n      <div class=\"heading\">\n        <h2 class=\"headingText\">\n          <FontAwesomeIcon\n            :icon=\"['fas', 'bookmark']\"\n            class=\"headingIcon\"\n          />\n          {{ $t(\"User Playlists.Your Playlists\") }}\n        </h2>\n        <FtIconButton\n          :title=\"$t('User Playlists.Create New Playlist')\"\n          :icon=\"['fas', 'plus']\"\n          theme=\"secondary\"\n          class=\"newPlaylistButton\"\n          @click=\"createNewPlaylist\"\n        />\n        <div\n          v-if=\"fullData.length > 1\"\n          class=\"searchInputsRow\"\n        >\n          <FtInput\n            ref=\"searchBar\"\n            :placeholder=\"$t('User Playlists.Search bar placeholder')\"\n            :value=\"query\"\n            :show-clear-text-button=\"true\"\n            :show-action-button=\"false\"\n            :maxlength=\"255\"\n            @input=\"handleQueryChange\"\n            @clear=\"() => handleQueryChange('')\"\n          />\n        </div>\n        <div\n          class=\"optionsRow\"\n        >\n          <FtToggleSwitch\n            v-if=\"fullData.length > 1\"\n            :label=\"$t('User Playlists.Playlists with Matching Videos')\"\n            :compact=\"true\"\n            :default-value=\"doSearchPlaylistsWithMatchingVideos\"\n            @change=\"doSearchPlaylistsWithMatchingVideos = !doSearchPlaylistsWithMatchingVideos\"\n          />\n          <FtSelect\n            v-if=\"fullData.length > 1\"\n            class=\"sortSelect\"\n            :value=\"sortBy\"\n            :select-names=\"sortByNames\"\n            :select-values=\"SORT_BY_VALUES\"\n            :placeholder=\"$t('Global.Sort By')\"\n            :icon=\"sortByIcon\"\n            @change=\"updateUserPlaylistsSortBy\"\n          />\n        </div>\n      </div>\n      <FtFlexBox\n        v-if=\"fullData.length === 0\"\n      >\n        <p class=\"message\">\n          {{ $t(\"User Playlists['You have no playlists. Click on the create new playlist button to create a new one.']\") }}\n        </p>\n      </FtFlexBox>\n      <FtFlexBox\n        v-else-if=\"activeData.length === 0 && fullData.length > 0\"\n      >\n        <p class=\"message\">\n          {{ $t(\"User Playlists['Empty Search Message']\") }}\n        </p>\n      </FtFlexBox>\n      <FtElementList\n        v-else-if=\"activeData.length > 0\"\n        :data=\"activeData\"\n        data-type=\"playlist\"\n        :search-query-text=\"doSearchPlaylistsWithMatchingVideos ? lowerCaseQuery : ''\"\n        :use-channels-hidden-preference=\"false\"\n        :hide-forbidden-titles=\"false\"\n      />\n      <FtAutoLoadNextPageWrapper\n        v-if=\"showLoadMoreButton\"\n        @load-next-page=\"increaseLimit\"\n      >\n        <FtFlexBox>\n          <FtButton\n            label=\"Load More\"\n            background-color=\"var(--primary-color)\"\n            text-color=\"var(--text-with-main-color)\"\n            @click=\"increaseLimit\"\n          />\n        </FtFlexBox>\n      </FtAutoLoadNextPageWrapper>\n    </FtCard>\n  </div>\n</template>\n\n<script setup>\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'\nimport { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useI18n } from '../../composables/use-i18n-polyfill'\nimport { isNavigationFailure, NavigationFailureType, useRoute, useRouter } from 'vue-router'\n\nimport FtAutoLoadNextPageWrapper from '../../components/FtAutoLoadNextPageWrapper.vue'\nimport FtButton from '../../components/FtButton/FtButton.vue'\nimport FtCard from '../../components/ft-card/ft-card.vue'\nimport FtElementList from '../../components/FtElementList/FtElementList.vue'\nimport FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'\nimport FtIconButton from '../../components/FtIconButton/FtIconButton.vue'\nimport FtInput from '../../components/FtInput/FtInput.vue'\nimport FtSelect from '../../components/FtSelect/FtSelect.vue'\nimport FtToggleSwitch from '../../components/FtToggleSwitch/FtToggleSwitch.vue'\n\nimport store from '../../store/index'\n\nimport { ctrlFHandler, debounce, getIconForSortPreference } from '../../helpers/utils'\n\nconst { locale, t } = useI18n()\n\nconst sessionDataLimit = sessionStorage.getItem('UserPlaylists/dataLimit')\n\nconst dataLimit = ref(sessionDataLimit !== null ? parseInt(sessionDataLimit) : 100)\nconst searchDataLimit = ref(100)\nconst showLoadMoreButton = ref(false)\nconst query = ref('')\nconst doSearchPlaylistsWithMatchingVideos = ref(false)\nconst activeData = ref([])\n\nconst SORT_BY_OPTIONS = {\n  NameAscending: 'name_ascending',\n  NameDescending: 'name_descending',\n\n  LatestCreatedFirst: 'latest_created_first',\n  EarliestCreatedFirst: 'earliest_created_first',\n\n  LatestUpdatedFirst: 'latest_updated_first',\n  EarliestUpdatedFirst: 'earliest_updated_first',\n\n  LatestPlayedFirst: 'latest_played_first',\n  EarliestPlayedFirst: 'earliest_played_first',\n}\n\nconst SORT_BY_VALUES = Object.values(SORT_BY_OPTIONS)\n\nconst sortByNames = computed(() => {\n  return SORT_BY_VALUES.map((k) => {\n    switch (k) {\n      case SORT_BY_OPTIONS.NameAscending:\n        return t('User Playlists.Sort By.NameAscending')\n      case SORT_BY_OPTIONS.NameDescending:\n        return t('User Playlists.Sort By.NameDescending')\n      case SORT_BY_OPTIONS.LatestCreatedFirst:\n        return t('User Playlists.Sort By.LatestCreatedFirst')\n      case SORT_BY_OPTIONS.EarliestCreatedFirst:\n        return t('User Playlists.Sort By.EarliestCreatedFirst')\n      case SORT_BY_OPTIONS.LatestUpdatedFirst:\n        return t('User Playlists.Sort By.LatestUpdatedFirst')\n      case SORT_BY_OPTIONS.EarliestUpdatedFirst:\n        return t('User Playlists.Sort By.EarliestUpdatedFirst')\n      case SORT_BY_OPTIONS.LatestPlayedFirst:\n        return t('User Playlists.Sort By.LatestPlayedFirst')\n      case SORT_BY_OPTIONS.EarliestPlayedFirst:\n        return t('User Playlists.Sort By.EarliestPlayedFirst')\n      default:\n        console.error(`Unknown sortBy: ${k}`)\n        return k\n    }\n  })\n})\n\n/** @type {import('vue').ComputedRef<'name_ascending' | 'name_descending' | 'latest_created_first' | 'earliest_created_first' | 'latest_updated_first' | 'earliest_updated_first' | 'latest_played_first' | 'earliest_played_first'>} */\nconst sortBy = computed(() => store.getters.getUserPlaylistsSortBy)\n\nconst sortByIcon = computed(() => getIconForSortPreference(sortBy.value))\n\nconst cachedCollator = computed(() => new Intl.Collator([locale.value, 'en'], { sensitivity: 'base' }))\n\n/** @type {import('vue').ComputedRef<any[]>} */\nconst allPlaylists = computed(() => {\n  /** @type {any[]} */\n  const playlists = store.getters.getAllPlaylists\n\n  const sortBy_ = sortBy.value\n\n  if (!SORT_BY_VALUES.includes(sortBy_)) {\n    console.error(`Unknown sortBy: ${sortBy_}`)\n    return playlists\n  }\n\n  const collator = cachedCollator.value\n\n  return playlists.toSorted((a, b) => {\n    switch (sortBy_) {\n      case SORT_BY_OPTIONS.NameAscending:\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.NameDescending:\n        return collator.compare(b.playlistName, a.playlistName)\n      case SORT_BY_OPTIONS.LatestCreatedFirst:\n        if (a.createdAt > b.createdAt) { return -1 }\n        if (a.createdAt < b.createdAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.EarliestCreatedFirst:\n        if (a.createdAt < b.createdAt) { return -1 }\n        if (a.createdAt > b.createdAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.LatestUpdatedFirst:\n        if (a.lastUpdatedAt > b.lastUpdatedAt) { return -1 }\n        if (a.lastUpdatedAt < b.lastUpdatedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.EarliestUpdatedFirst:\n        if (a.lastUpdatedAt < b.lastUpdatedAt) { return -1 }\n        if (a.lastUpdatedAt > b.lastUpdatedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.LatestPlayedFirst:\n        if (a.lastPlayedAt == null && b.lastPlayedAt == null) {\n          return collator.compare(a.playlistName, b.playlistName)\n        }\n\n        // Never played playlist = move to last\n        if (a.lastPlayedAt == null) { return 1 }\n        if (b.lastPlayedAt == null) { return -1 }\n        if (a.lastPlayedAt > b.lastPlayedAt) { return -1 }\n        if (a.lastPlayedAt < b.lastPlayedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      case SORT_BY_OPTIONS.EarliestPlayedFirst:\n        // Never played playlist = first\n        if (a.lastPlayedAt == null && b.lastPlayedAt == null) {\n          return collator.compare(a.playlistName, b.playlistName)\n        }\n\n        // Never played playlist = move to first\n        if (a.lastPlayedAt == null) { return -1 }\n        if (b.lastPlayedAt == null) { return 1 }\n        if (a.lastPlayedAt < b.lastPlayedAt) { return -1 }\n        if (a.lastPlayedAt > b.lastPlayedAt) { return 1 }\n\n        return collator.compare(a.playlistName, b.playlistName)\n      default:\n        // should never happen as we detect this before calling toSorted\n        return 0\n    }\n  })\n})\n\nconst fullData = computed(() => {\n  return allPlaylists.value.length < dataLimit.value\n    ? allPlaylists.value\n    : allPlaylists.value.slice(0, dataLimit.value)\n})\n\nconst lowerCaseQuery = computed(() => query.value.toLowerCase())\n\nwatch(lowerCaseQuery, () => {\n  searchDataLimit.value = 100\n  filterPlaylistAsync()\n})\n\nwatch(doSearchPlaylistsWithMatchingVideos, () => {\n  searchDataLimit.value = 100\n  filterPlaylistAsync()\n  saveStateInRouter()\n})\n\nwatch(fullData, (value) => {\n  activeData.value = value\n  filterPlaylist()\n}, { deep: true })\n\n/**\n * @param {'name_ascending' | 'name_descending' | 'latest_created_first' | 'earliest_created_first' | 'latest_updated_first' | 'earliest_updated_first' | 'latest_played_first' | 'earliest_played_first'} value\n */\nfunction updateUserPlaylistsSortBy(value) {\n  store.dispatch('updateUserPlaylistsSortBy', value)\n}\n\n/**\n * @param {string} query_\n * @param {string} [limit]\n * @param {boolean} [doSearchPlaylistsWithMatchingVideos_]\n * @param {boolean} [filterNow=false]\n */\nfunction handleQueryChange(query_, limit = undefined, doSearchPlaylistsWithMatchingVideos_ = undefined, filterNow = false) {\n  query.value = query_\n\n  let newLimit = 100\n\n  if (limit !== undefined) {\n    const parsedLimit = parseInt(limit)\n\n    if (!isNaN(parsedLimit)) {\n      newLimit = parsedLimit\n    }\n  }\n\n  searchDataLimit.value = newLimit\n\n  if (doSearchPlaylistsWithMatchingVideos_ !== undefined) {\n    doSearchPlaylistsWithMatchingVideos.value = doSearchPlaylistsWithMatchingVideos_\n  }\n\n  saveStateInRouter()\n\n  if (filterNow) {\n    filterPlaylist()\n  } else {\n    filterPlaylistAsync()\n  }\n}\n\nfunction increaseLimit() {\n  if (query.value !== '') {\n    searchDataLimit.value += 100\n    saveStateInRouter()\n    filterPlaylist()\n  } else {\n    dataLimit.value += 100\n    sessionStorage.setItem('UserPlaylists/dataLimit', dataLimit.value.toFixed(0))\n  }\n}\n\nfunction filterPlaylist() {\n  const lowerCaseQuery_ = lowerCaseQuery.value\n\n  if (lowerCaseQuery_ === '') {\n    activeData.value = fullData.value\n    showLoadMoreButton.value = allPlaylists.value.length > activeData.value.length\n  } else {\n    const findMatchingVideos = doSearchPlaylistsWithMatchingVideos.value\n\n    const filteredPlaylists = allPlaylists.value.filter((playlist) => {\n      if (typeof playlist.playlistName !== 'string') { return false }\n\n      if (\n        findMatchingVideos &&\n        playlist.videos.some((v) => {\n          return v.author?.toLowerCase().includes(lowerCaseQuery_) || v.title.toLowerCase().includes(lowerCaseQuery_)\n        })\n      ) {\n        return true\n      }\n\n      return playlist.playlistName.toLowerCase().includes(lowerCaseQuery_)\n    })\n\n    const searchDataLimit_ = searchDataLimit.value\n\n    showLoadMoreButton.value = filteredPlaylists.length > searchDataLimit_\n    activeData.value = filteredPlaylists.length < searchDataLimit_ ? filteredPlaylists : filteredPlaylists.slice(0, searchDataLimit_)\n  }\n}\n\nconst filterPlaylistAsync = debounce(filterPlaylist, 500)\n\nfunction createNewPlaylist() {\n  store.dispatch('showCreatePlaylistPrompt', { title: '' })\n}\n\nconst router = useRouter()\n\nasync function saveStateInRouter() {\n  const query_ = query.value\n\n  let location\n\n  if (query_ === '') {\n    location = { path: '/userplaylists' }\n  } else {\n    location = {\n      path: '/userplaylists',\n      query: {\n        query: query_,\n        searchDataLimit: searchDataLimit.value.toFixed(0)\n      }\n    }\n\n    if (doSearchPlaylistsWithMatchingVideos.value) {\n      location.query.doSearchPlaylistsWithMatchingVideos = 'true'\n    }\n  }\n\n  try {\n    await router.replace(location)\n  } catch (failure) {\n    if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n      return\n    }\n\n    throw failure\n  }\n}\n\nconst route = useRoute()\n\nconst oldQuery = route.query.query\nif (oldQuery != null && oldQuery !== '') {\n  handleQueryChange(\n    oldQuery,\n    route.query.searchDataLimit,\n    route.query.doSearchPlaylistsWithMatchingVideos === 'true',\n    true\n  )\n} else {\n  // Only display unfiltered data when no query used last time\n  filterPlaylist()\n}\n\nconst searchBar = useTemplateRef('searchBar')\n\n/**\n * @param {KeyboardEvent} event\n */\nfunction keyboardShortcutHandler(event) {\n  ctrlFHandler(event, searchBar.value)\n}\n\nonMounted(() => {\n  document.addEventListener('keydown', keyboardShortcutHandler)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('keydown', keyboardShortcutHandler)\n})\n</script>\n\n<style scoped src=\"./UserPlaylists.css\" />\n"
  },
  {
    "path": "src/renderer/views/Watch/Watch.js",
    "content": "import { defineComponent } from 'vue'\nimport { isNavigationFailure, NavigationFailureType } from 'vue-router'\nimport { mapActions, mapMutations } from 'vuex'\nimport shaka from 'shaka-player'\nimport { Utils, YTNodes } from 'youtubei.js'\nimport FtLoader from '../../components/FtLoader/FtLoader.vue'\nimport FtShakaVideoPlayer from '../../components/ft-shaka-video-player/ft-shaka-video-player.vue'\nimport WatchVideoInfo from '../../components/WatchVideoInfo/WatchVideoInfo.vue'\nimport WatchVideoChapters from '../../components/WatchVideoChapters/WatchVideoChapters.vue'\nimport WatchVideoDescription from '../../components/WatchVideoDescription/WatchVideoDescription.vue'\nimport CommentSection from '../../components/CommentSection/CommentSection.vue'\nimport WatchVideoLiveChat from '../../components/WatchVideoLiveChat/WatchVideoLiveChat.vue'\nimport WatchVideoPlaylist from '../../components/watch-video-playlist/watch-video-playlist.vue'\nimport WatchVideoRecommendations from '../../components/WatchVideoRecommendations/WatchVideoRecommendations.vue'\nimport FtAgeRestricted from '../../components/FtAgeRestricted/FtAgeRestricted.vue'\nimport packageDetails from '../../../../package.json'\nimport {\n  buildVTTFileLocally,\n  copyToClipboard,\n  extractNumberFromString,\n  formatDurationAsTimestamp,\n  formatNumber,\n  showToast\n} from '../../helpers/utils'\nimport {\n  getLocalVideoInfo,\n  mapLocalLegacyFormat,\n  parseLocalSubscriberCount,\n  parseLocalTextRuns,\n  parseLocalWatchNextVideo\n} from '../../helpers/api/local'\nimport {\n  convertInvidiousToLocalFormat,\n  generateInvidiousDashManifestLocally,\n  getProxyUrl,\n  invidiousGetVideoInformation,\n  mapInvidiousLegacyFormat,\n  youtubeImageUrlToInvidious\n} from '../../helpers/api/invidious'\nimport { sortCaptions } from '../../helpers/player/utils'\nimport { MANIFEST_TYPE_SABR } from '../../helpers/player/SabrManifestParser'\n\n/**\n * @typedef {{\n *   url: string,\n *   poToken: string,\n *   ustreamerConfig: string,\n *   clientInfo: {\n *     clientName: number,\n *     clientVersion: string,\n *     osName: string,\n *     osVersion: string\n *   }\n * }} SabrData\n */\n\nconst MANIFEST_TYPE_DASH = 'application/dash+xml'\nconst MANIFEST_TYPE_HLS = 'application/x-mpegurl'\n\nexport default defineComponent({\n  name: 'Watch',\n  components: {\n    'ft-loader': FtLoader,\n    'ft-shaka-video-player': FtShakaVideoPlayer,\n    'watch-video-info': WatchVideoInfo,\n    'watch-video-chapters': WatchVideoChapters,\n    'watch-video-description': WatchVideoDescription,\n    CommentSection,\n    'watch-video-live-chat': WatchVideoLiveChat,\n    'watch-video-playlist': WatchVideoPlaylist,\n    'watch-video-recommendations': WatchVideoRecommendations,\n    'ft-age-restricted': FtAgeRestricted\n  },\n  beforeRouteLeave: async function (to, from, next) {\n    this.handleRouteChange()\n    window.removeEventListener('beforeunload', this.handleWatchProgressAutoSave)\n    document.removeEventListener('keydown', this.resetAutoplayInterruptionTimeout)\n    document.removeEventListener('click', this.resetAutoplayInterruptionTimeout)\n\n    if (this.$refs.player) {\n      await this.destroyPlayer()\n    }\n\n    next()\n  },\n  data: function () {\n    return {\n      startNextVideoInFullscreen: false,\n      startNextVideoInFullwindow: false,\n      startNextVideoInPip: false,\n      isLoading: true,\n      firstLoad: true,\n      useTheatreMode: false,\n      videoPlayerLoaded: false,\n      isFamilyFriendly: false,\n      isLive: false,\n      liveChat: null,\n      isLiveContent: false,\n      isUpcoming: false,\n      isPostLiveDvr: false,\n      isUnlisted: false,\n      upcomingTimestamp: null,\n      upcomingTimeLeft: null,\n      /** @type {'dash' | 'audio' | 'legacy'} */\n      activeFormat: 'legacy',\n      thumbnail: '',\n      videoId: '',\n      videoTitle: '',\n      videoDescription: '',\n      videoDescriptionHtml: '',\n      license: '',\n      videoViewCount: 0,\n      videoLikeCount: 0,\n      videoDislikeCount: 0,\n      videoLengthSeconds: 0,\n      videoChapters: [],\n      videoCurrentChapterIndex: 0,\n      /** @type {'chapters' | 'keyMoments'} */\n      videoChaptersKind: 'chapters',\n      channelName: '',\n      channelThumbnail: '',\n      channelId: '',\n      channelSubscriptionCountText: '',\n      videoPublished: 0,\n      premiereDate: undefined,\n      videoStoryboardSrc: '',\n      /** @type {string|null} */\n      manifestSrc: null,\n      /** @type {(MANIFEST_TYPE_DASH|MANIFEST_TYPE_HLS|MANIFEST_TYPE_SABR)} */\n      manifestMimeType: MANIFEST_TYPE_DASH,\n      /** @type {SabrData | null} */\n      sabrData: null,\n      legacyFormats: [],\n      captions: [],\n      /** @type {'EQUIRECTANGULAR' | 'EQUIRECTANGULAR_THREED_TOP_BOTTOM' | 'MESH'| null} */\n      vrProjection: null,\n      autoplayNextRecommendedVideo: false,\n      autoplayNextPlaylistVideo: false,\n      recommendedVideos: [],\n      watchingPlaylist: false,\n      playlistId: '',\n      playlistType: '',\n      playlistItemId: null,\n      /** @type {number|null} */\n      timestamp: null,\n      // This should never be saved into history\n      /** @type {number|null} */\n      oneTimeTimestamp: null,\n      playNextTimeout: null,\n      playNextCountDownIntervalId: null,\n      blockVideoAutoplay: false,\n      autoplayInterruptionTimeout: null,\n      playabilityStatus: '',\n      totalAdTimeSeconds: 0,\n      adEndTimeUnixMs: 0,\n\n      onMountedRun: false,\n\n      // error handling/messages\n      /** @type {string|null} */\n      errorMessage: null,\n      /** @type {string[]|null} */\n      customErrorIcon: null,\n      videoGenreIsMusic: false,\n      /** @type {Date|null} */\n      streamingDataExpiryDate: null,\n      currentPlaybackRate: null,\n    }\n  },\n  computed: {\n    historyEntry: function () {\n      return this.$store.getters.getHistoryCacheById[this.videoId]\n    },\n    historyEntryExists: function () {\n      return typeof this.historyEntry !== 'undefined'\n    },\n    rememberHistory: function () {\n      return this.$store.getters.getRememberHistory\n    },\n    watchedProgressSavingEnabled: function () {\n      return this.$store.getters.getWatchedProgressSavingMode !== 'never'\n    },\n    autosaveWatchedProgress: function () {\n      return this.$store.getters.getWatchedProgressSavingMode === 'auto'\n    },\n    saveVideoHistoryWithLastViewedPlaylist: function () {\n      return this.$store.getters.getSaveVideoHistoryWithLastViewedPlaylist\n    },\n    backendPreference: function () {\n      return this.$store.getters.getBackendPreference\n    },\n    backendFallback: function () {\n      return this.$store.getters.getBackendFallback\n    },\n    currentInvidiousInstanceUrl: function () {\n      return this.$store.getters.getCurrentInvidiousInstanceUrl\n    },\n    proxyVideos: function () {\n      return this.$store.getters.getProxyVideos\n    },\n    defaultAutoplayInterruptionIntervalHours: function () {\n      return this.$store.getters.getDefaultAutoplayInterruptionIntervalHours\n    },\n    defaultInterval: function () {\n      return this.$store.getters.getDefaultInterval\n    },\n    defaultViewingMode: function () {\n      return this.$store.getters.getDefaultViewingMode\n    },\n    defaultVideoFormat: function () {\n      return this.$store.getters.getDefaultVideoFormat\n    },\n    autoplayEnabled: function () {\n      return this.watchingPlaylist ? this.autoplayNextPlaylistVideo : this.autoplayNextRecommendedVideo\n    },\n    thumbnailPreference: function () {\n      return this.$store.getters.getThumbnailPreference\n    },\n    autoplayNextRecommendedVideoByDefault: function () {\n      return this.$store.getters.getPlayNextVideo\n    },\n    autoplayNextPlaylistVideoByDefault: function () {\n      return this.$store.getters.getAutoplayPlaylists\n    },\n    hideRecommendedVideos: function () {\n      return this.$store.getters.getHideRecommendedVideos\n    },\n    hideLiveChat: function () {\n      return this.$store.getters.getHideLiveChat\n    },\n    hideComments: function () {\n      return this.$store.getters.getHideComments\n    },\n    hideVideoDescription: function () {\n      return this.$store.getters.getHideVideoDescription\n    },\n    showFamilyFriendlyOnly: function () {\n      return this.$store.getters.getShowFamilyFriendlyOnly\n    },\n    hideChannelSubscriptions: function () {\n      return this.$store.getters.getHideChannelSubscriptions\n    },\n    hideVideoLikesAndDislikes: function () {\n      return this.$store.getters.getHideVideoLikesAndDislikes\n    },\n    theatrePossible: function () {\n      return !this.hideRecommendedVideos || (!this.hideLiveChat && this.isLive) || this.watchingPlaylist\n    },\n    autoplayPossible: function () {\n      return (!this.watchingPlaylist && !this.hideRecommendedVideos && !!this.nextRecommendedVideo) ||\n      (this.watchingPlaylist && !this.$refs.watchVideoPlaylist?.shouldStopDueToPlaylistEnd)\n    },\n    currentLocale: function () {\n      return this.$i18n.locale\n    },\n    hideChapters: function () {\n      return this.$store.getters.getHideChapters\n    },\n    channelsHidden() {\n      return JSON.parse(this.$store.getters.getChannelsHidden).map((ch) => {\n        // Legacy support\n        if (typeof ch === 'string') {\n          return { name: ch, preferredName: '', icon: '' }\n        }\n        return ch\n      })\n    },\n    forbiddenTitles() {\n      return JSON.parse(this.$store.getters.getForbiddenTitles.toLowerCase())\n    },\n    isUserPlaylistRequested: function () {\n      return this.$route.query.playlistType === 'user'\n    },\n    userPlaylistsReady: function () {\n      return this.$store.getters.getPlaylistsReady\n    },\n    selectedUserPlaylist: function () {\n      if (this.playlistId == null || this.playlistId === '') { return null }\n      if (!this.isUserPlaylistRequested) { return null }\n\n      return this.$store.getters.getPlaylist(this.playlistId)\n    },\n    nextRecommendedVideo: function () {\n      return this.recommendedVideos.find((video) =>\n        !this.isHiddenVideo(this.forbiddenTitles, this.channelsHidden, video)\n      )\n    },\n    startTimeSeconds: function () {\n      if (this.isLoading || this.isLive) {\n        return null\n      }\n\n      if (this.oneTimeTimestamp !== null && this.oneTimeTimestamp < this.videoLengthSeconds) {\n        return this.oneTimeTimestamp\n      } else if (this.timestamp !== null && this.timestamp < this.videoLengthSeconds) {\n        return this.timestamp\n      } else if (this.watchedProgressSavingEnabled && this.historyEntryExists) {\n        // For UX consistency, no progress reading if writing disabled\n\n        /** @type {number} */\n        const watchProgress = this.historyEntry.watchProgress\n\n        if (watchProgress > 0 && watchProgress < this.videoLengthSeconds - 2) {\n          return watchProgress\n        }\n      }\n\n      return null\n    },\n\n    canSaveWatchProgress() {\n      if (this.isUpcoming || this.isLive) { return false }\n\n      // `this.$refs.player?.hasLoaded` cannot be used in computed property\n      return !this.isLoading\n    },\n  },\n  watch: {\n    async $route() {\n      await this.reloadView()\n    },\n    userPlaylistsReady() {\n      this.onMountedDependOnLocalStateLoading()\n    },\n  },\n  created: function () {\n    this.videoId = this.$route.params.id\n    this.activeFormat = this.defaultVideoFormat\n    // So that the value for this session remains unchanged even if setting changed\n    this.autoplayNextRecommendedVideo = this.autoplayNextRecommendedVideoByDefault\n    this.autoplayNextPlaylistVideo = this.autoplayNextPlaylistVideoByDefault\n\n    this.checkIfTimestamp()\n    this.currentPlaybackRate = this.$store.getters.getDefaultPlayback\n  },\n  mounted: function () {\n    this.onMountedDependOnLocalStateLoading()\n  },\n  methods: {\n    async reloadView() {\n      await this.handleRouteChange()\n\n      if (this.$refs.player) {\n        await this.destroyPlayer()\n      }\n\n      // react to route changes...\n      this.videoId = this.$route.params.id\n\n      this.firstLoad = true\n      this.videoPlayerLoaded = false\n      this.errorMessage = null\n      this.customErrorIcon = null\n      this.activeFormat = this.defaultVideoFormat\n      this.sabrData = null\n      this.videoStoryboardSrc = ''\n      this.captions = []\n      this.vrProjection = null\n      this.videoCurrentChapterIndex = 0\n      this.videoGenreIsMusic = false\n\n      this.checkIfTimestamp()\n      this.checkIfPlaylist()\n\n      switch (this.backendPreference) {\n        case 'local':\n          await this.getVideoInformationLocal()\n          break\n        case 'invidious':\n          this.getVideoInformationInvidious()\n          break\n      }\n    },\n    onMountedDependOnLocalStateLoading() {\n      // Prevent running twice\n      if (this.onMountedRun) { return }\n      // Stuff that require user playlists to be ready\n      if (this.isUserPlaylistRequested && !this.userPlaylistsReady) { return }\n\n      this.onMountedRun = true\n\n      this.checkIfPlaylist()\n\n      // this has to be below checkIfPlaylist() as theatrePossible needs to know if there is a playlist or not\n      this.setViewingModeOnFirstLoad()\n\n      if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') {\n        this.getVideoInformationInvidious()\n      } else {\n        this.getVideoInformationLocal()\n      }\n\n      document.removeEventListener('keydown', this.resetAutoplayInterruptionTimeout)\n      document.removeEventListener('click', this.resetAutoplayInterruptionTimeout)\n      document.addEventListener('keydown', this.resetAutoplayInterruptionTimeout)\n      document.addEventListener('click', this.resetAutoplayInterruptionTimeout)\n\n      window.addEventListener('beforeunload', this.handleWatchProgressAutoSave)\n      this.resetAutoplayInterruptionTimeout()\n    },\n\n    setViewingModeOnFirstLoad: function () {\n      switch (this.defaultViewingMode) {\n        case 'theatre':\n          this.useTheatreMode = this.theatrePossible\n          break\n        case 'fullscreen':\n          this.startNextVideoInFullscreen = true\n          break\n        case 'fullwindow':\n          this.startNextVideoInFullwindow = true\n          break\n        case 'pip':\n          this.startNextVideoInPip = true\n      }\n    },\n\n    changeTimestamp: function (timestamp) {\n      const player = this.$refs.player\n\n      if (!this.isLoading && player?.hasLoaded) {\n        player.setCurrentTime(timestamp)\n      }\n    },\n\n    getVideoInformationLocal: async function () {\n      if (this.firstLoad) {\n        this.isLoading = true\n      }\n\n      try {\n        const videoInfo = await getLocalVideoInfo(this.videoId)\n        const { info: result, poToken, clientInfo, adEndTimeUnixMs } = videoInfo\n\n        this.adEndTimeUnixMs = adEndTimeUnixMs\n\n        this.isFamilyFriendly = result.basic_info.is_family_safe\n\n        const recommendedVideos = result.watch_next_feed\n          ?.filter((item) => {\n            return item.type === 'CompactVideo' || item.type === 'CompactMovie' ||\n              (item.type === 'LockupView' && item.content_type === 'VIDEO')\n          })\n          .map(parseLocalWatchNextVideo) ?? []\n\n        // place watched recommended videos last\n        this.recommendedVideos = [\n          ...recommendedVideos.filter((video) => !this.isRecommendedVideoWatched(video.videoId)),\n          ...recommendedVideos.filter((video) => this.isRecommendedVideoWatched(video.videoId))\n        ]\n\n        if (this.showFamilyFriendlyOnly && !this.isFamilyFriendly) {\n          this.isLoading = false\n          this.handleVideoEnded()\n          return\n        }\n\n        // extract localised title first and fall back to the not localised one\n        this.videoTitle = result.primary_info?.title.text?.trim() ?? result.basic_info.title?.trim()\n        this.videoViewCount = result.basic_info.view_count ?? (result.primary_info.view_count ? extractNumberFromString(result.primary_info.view_count.text) : null)\n        this.license = result.secondary_info.metadata.rows.find(element => element.title?.text === 'License')?.contents[0]?.text\n\n        this.channelId = result.basic_info.channel_id ?? result.secondary_info.owner?.author.id\n        this.channelName = result.basic_info.author ?? result.secondary_info.owner?.author.name\n\n        if (result.secondary_info.owner?.author) {\n          this.channelThumbnail = result.secondary_info.owner.author.best_thumbnail?.url ?? ''\n        } else {\n          this.channelThumbnail = ''\n        }\n\n        this.videoGenreIsMusic = result.basic_info.category === 'Music'\n\n        this.updateSubscriptionDetails({\n          channelThumbnailUrl: this.channelThumbnail.length === 0 ? null : this.channelThumbnail,\n          channelName: this.channelName,\n          channelId: this.channelId\n        })\n\n        if (result.page[0].microformat?.publish_date) {\n          // `result.page[0].microformat.publish_date` example value: `2023-08-12T08:59:59-07:00`\n          this.videoPublished = Date.parse(result.page[0].microformat.publish_date)\n        } else {\n          // text date Jan 1, 2000, not as accurate but better than nothing\n          this.videoPublished = Date.parse(result.primary_info.published)\n        }\n\n        if (result.secondary_info?.description.runs) {\n          try {\n            this.videoDescription = parseLocalTextRuns(result.secondary_info.description.runs)\n          } catch (error) {\n            console.error('Failed to extract the localised description, falling back to the standard one.', error, JSON.stringify(result.secondary_info.description.runs))\n            this.videoDescription = result.basic_info.short_description\n          }\n        } else {\n          this.videoDescription = result.basic_info.short_description\n        }\n\n        switch (this.thumbnailPreference) {\n          case 'start':\n            this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres1.jpg`\n            break\n          case 'middle':\n            this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres2.jpg`\n            break\n          case 'end':\n            this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres3.jpg`\n            break\n          default:\n            this.thumbnail = result.basic_info.thumbnail?.[0].url ?? `https://i.ytimg.com/vi/${this.videoId}/maxresdefault.jpg`\n            break\n        }\n\n        if (this.hideVideoLikesAndDislikes) {\n          this.videoLikeCount = null\n          this.videoDislikeCount = null\n        } else {\n          this.videoLikeCount = isNaN(result.basic_info.like_count) ? 0 : result.basic_info.like_count\n\n          // YouTube doesn't return dislikes anymore\n          this.videoDislikeCount = 0\n        }\n\n        this.isLive = !!result.basic_info.is_live\n        this.isUpcoming = !!result.basic_info.is_upcoming\n        this.isLiveContent = !!result.basic_info.is_live_content\n        this.isPostLiveDvr = !!result.basic_info.is_post_live_dvr\n        this.isUnlisted = !!result.basic_info.is_unlisted\n\n        const subCount = !result.secondary_info.owner.subscriber_count.isEmpty() ? parseLocalSubscriberCount(result.secondary_info.owner.subscriber_count.text) : NaN\n\n        if (!isNaN(subCount)) {\n          this.channelSubscriptionCountText = formatNumber(subCount, subCount >= 10000 ? { notation: 'compact' } : undefined)\n        } else {\n          this.channelSubscriptionCountText = ''\n        }\n\n        let chapters = []\n        if (!this.hideChapters) {\n          const rawChapters = result.player_overlays?.decorated_player_bar?.player_bar?.markers_map\n            ?.find(marker => marker.marker_key === 'DESCRIPTION_CHAPTERS')?.value.chapters\n\n          if (rawChapters) {\n            for (const chapter of rawChapters) {\n              const start = chapter.time_range_start_millis / 1000\n\n              chapters.push({\n                title: chapter.title.text,\n                timestamp: formatDurationAsTimestamp(start),\n                startSeconds: start,\n                endSeconds: 0,\n                thumbnail: chapter.thumbnail[0]\n              })\n            }\n          } else {\n            /** @type {import('youtubei.js').YTNodes.MacroMarkersList | null | undefined} */\n            const macroMarkersList = result.page[1]?.engagement_panels\n              ?.find(pannel => pannel.panel_identifier === 'engagement-panel-macro-markers-auto-chapters')?.content\n\n            if (macroMarkersList) {\n              for (const item of macroMarkersList.contents) {\n                if (item instanceof YTNodes.MacroMarkersListItem) {\n                  chapters.push({\n                    title: item.title.text,\n                    timestamp: item.time_description.text,\n                    startSeconds: Utils.timeToSeconds(item.time_description.text),\n                    endSeconds: 0,\n                    thumbnail: item.thumbnail[0]\n                  })\n                }\n              }\n              this.videoChaptersKind = 'keyMoments'\n            } else {\n              chapters = this.extractChaptersFromDescription(result.basic_info.short_description ?? result.secondary_info.description.text)\n            }\n          }\n\n          if (chapters.length > 0) {\n            this.addChaptersEndSeconds(chapters, result.basic_info.duration)\n\n            // prevent vue from adding reactivity which isn't needed\n            // as the chapter objects are read-only after this anyway\n            // the chapters are checked for every timeupdate event that the player emits\n            // this should lessen the performance and memory impact of the chapters\n            chapters.forEach(Object.freeze)\n          }\n        }\n\n        this.videoChapters = chapters\n\n        const playabilityStatus = result.playability_status\n        this.playabilityStatus = playabilityStatus.status\n\n        // The apostrophe is intentionally that one (char code 8217), because that is the one YouTube uses\n        const BOT_MESSAGE = 'Sign in to confirm you’re not a bot'\n\n        const isDrmProtected = result.streaming_data?.adaptive_formats.some(format => format.drm_families || format.drm_track_type)\n\n        if (playabilityStatus.status === 'UNPLAYABLE' || playabilityStatus.status === 'LOGIN_REQUIRED' || isDrmProtected) {\n          if (playabilityStatus.error_screen?.offer_id === 'sponsors_only_video') {\n            // Members-only videos can only be watched while logged into a Google account that is a paid channel member\n            // so there is no point trying any other backends as it will always fail\n            this.errorMessage = this.$t('Video.MembersOnly')\n            this.customErrorIcon = ['fas', 'money-check-dollar']\n            this.isLoading = false\n            this.updateTitle()\n            return\n          } else if (playabilityStatus.reason === 'Sign in to confirm your age' || (result.has_trailer && result.getTrailerInfo() === null)) {\n            // Age-restricted videos can only be watched while logged into a Google account that is age-verified\n            // so there is no point trying any other backends as it will always fail\n            this.errorMessage = this.$t('Video.AgeRestricted')\n            this.isLoading = false\n            this.updateTitle()\n            return\n          } else if (isDrmProtected) {\n            // DRM protected videos (e.g. movies) cannot be played in FreeTube,\n            // as they require the proprietary and closed source Wideview CDM which is understandably not included in standard Electron builds\n            this.errorMessage = this.$t('Video.DRMProtected')\n            this.isLoading = false\n            this.updateTitle()\n            return\n          }\n\n          let errorText\n\n          if (playabilityStatus.reason === BOT_MESSAGE || playabilityStatus.reason === 'Please sign in') {\n            errorText = this.$t('Video.IP block')\n          } else {\n            errorText = `[${playabilityStatus.status}] ${playabilityStatus.reason}`\n\n            if (playabilityStatus.error_screen?.subreason) {\n              errorText += `: ${playabilityStatus.error_screen.subreason.text}`\n            }\n          }\n\n          if (this.backendFallback) {\n            throw new Error(errorText)\n          } else {\n            this.errorMessage = errorText\n            this.isLoading = false\n            this.updateTitle()\n            return\n          }\n        }\n\n        if (!this.hideLiveChat && (this.isLive || this.isUpcoming) && result.livechat) {\n          this.liveChat = result.getLiveChat()\n        } else {\n          this.liveChat = null\n        }\n\n        if ((this.isLive || this.isPostLiveDvr) && !this.isUpcoming) {\n          let useRemoteManifest = true\n\n          if (this.isPostLiveDvr) {\n            // I wasn't able to get SABR working with Post-Live-DVR yet, so for the moment we'll use YouTube's provided DASH manifest instead.\n            // It only contains the last 4 hours of the stream, instead of starting from the beginning but that is better than nothing.\n            if (\n              result.streaming_data.adaptive_formats[0]?.url ||\n              result.streaming_data.adaptive_formats[0]?.signature_cipher ||\n              result.streaming_data.adaptive_formats[0]?.cipher\n            ) {\n              try {\n                this.manifestSrc = await this.createLocalDashManifest(result, true)\n                this.manifestMimeType = MANIFEST_TYPE_DASH\n                useRemoteManifest = false\n              } catch (error) {\n                console.error(`Failed to generate DASH manifest for this Post Live DVR video ${this.videoId}, falling back to using YouTube's provided one...`, error)\n              }\n            }\n          }\n\n          if (useRemoteManifest) {\n            if (result.streaming_data.dash_manifest_url) {\n              this.manifestSrc = result.streaming_data.dash_manifest_url\n              this.manifestMimeType = MANIFEST_TYPE_DASH\n            } else {\n              this.manifestSrc = result.streaming_data.hls_manifest_url\n              this.manifestMimeType = MANIFEST_TYPE_HLS\n            }\n          }\n\n          this.streamingDataExpiryDate = result.streaming_data.expires\n\n          if (this.activeFormat === 'legacy') {\n            this.activeFormat = 'dash'\n          }\n        } else if (this.isUpcoming) {\n          const upcomingTimestamp = result.basic_info.start_timestamp\n\n          if (upcomingTimestamp) {\n            const timestampOptions = {\n              month: 'long',\n              day: 'numeric',\n              hour: 'numeric',\n              minute: '2-digit'\n            }\n            const now = new Date()\n            if (now.getFullYear() < upcomingTimestamp.getFullYear()) {\n              Object.defineProperty(timestampOptions, 'year', {\n                value: 'numeric'\n              })\n            }\n            this.upcomingTimestamp = Intl.DateTimeFormat(this.currentLocale, timestampOptions).format(upcomingTimestamp)\n\n            let upcomingTimeLeft = upcomingTimestamp - now\n\n            // Convert from ms to second to minute\n            upcomingTimeLeft = (upcomingTimeLeft / 1000) / 60\n            let timeUnit = 'minute'\n\n            // Youtube switches to showing time left in minutes at 120 minutes remaining\n            if (upcomingTimeLeft > 120) {\n              upcomingTimeLeft /= 60\n              timeUnit = 'hour'\n            }\n\n            if (timeUnit === 'hour' && upcomingTimeLeft > 24) {\n              upcomingTimeLeft /= 24\n              timeUnit = 'day'\n            }\n\n            // Value after decimal not to be displayed\n            // e.g. > 2 days = display as `2 days`\n            upcomingTimeLeft = Math.floor(upcomingTimeLeft)\n\n            // Displays when less than a minute remains\n            // Looks better than `Premieres in x seconds`\n            if (upcomingTimeLeft < 1) {\n              this.upcomingTimeLeft = this.$t('Video.Published.In less than a minute').toLowerCase()\n            } else {\n              // TODO a I18n entry for time format might be needed here\n              this.upcomingTimeLeft = new Intl.RelativeTimeFormat(this.currentLocale).format(upcomingTimeLeft, timeUnit)\n            }\n\n            this.premiereDate = upcomingTimestamp\n          } else {\n            this.upcomingTimestamp = null\n            this.upcomingTimeLeft = null\n            this.premiereDate = undefined\n          }\n        }\n\n        if ((!this.isUpcoming && !this.isLive && !this.isPostLiveDvr) || (this.isUpcoming && this.playabilityStatus === 'OK')) {\n          this.videoLengthSeconds = result.basic_info.duration\n          if (result.streaming_data) {\n            this.streamingDataExpiryDate = result.streaming_data.expires\n\n            if (result.streaming_data.formats.length > 0) {\n              this.legacyFormats = result.streaming_data.formats.map(mapLocalLegacyFormat)\n            }\n\n            if (result.captions) {\n              const captionTracks = result.captions?.caption_tracks?.map((caption) => {\n                const url = new URL(caption.base_url)\n                url.searchParams.set('fmt', 'vtt')\n\n                return {\n                  id: caption.vss_id,\n                  url: url.toString(),\n                  label: caption.name.text,\n                  language: caption.language_code,\n                  mimeType: 'text/vtt'\n                }\n              }) ?? []\n\n              if (captionTracks.length > 0) {\n                const languagesSet = new Set([this.currentLocale, this.currentLocale.split('-')[0]])\n\n                // special cases\n                switch (this.currentLocale) {\n                  case 'nn':\n                  case 'nb-NO':\n                    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n                    // \"no\" is the macro language for \"nb\" and \"nn\"\n                    languagesSet.add('no')\n                    break\n                  case 'he':\n                    // according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n                    // \"iw\" is the old/original code for Hewbrew, these days it's \"he\"\n                    languagesSet.add('iw')\n                    break\n                }\n\n                if (!captionTracks.some(captionTrack => languagesSet.has(captionTrack.language))) {\n                  const translatedCaptionTrack = this.getTranslatedLocaleCaption(result.captions, languagesSet)\n\n                  if (translatedCaptionTrack) {\n                    captionTracks.push(translatedCaptionTrack)\n                  }\n                }\n              }\n\n              this.captions = sortCaptions(captionTracks)\n            }\n          } else {\n            // video might be region locked or something else. This leads to no formats being available\n            showToast(\n              this.$t('This video is unavailable because of missing formats. This can happen due to country unavailability.'),\n              7000\n            )\n            this.handleVideoEnded()\n            return\n          }\n\n          let storyboard\n\n          if (result.storyboards?.type === 'PlayerStoryboardSpec') {\n            /** @type {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData[]} */\n            let source = result.storyboards.boards\n            if (window.innerWidth < 500) {\n              source = source.filter((board) => board.thumbnail_height <= 90)\n            }\n\n            storyboard = source.at(-1)\n            this.videoStoryboardSrc = this.createLocalStoryboardUrls(storyboard)\n          }\n\n          if (result.streaming_data?.adaptive_formats.length > 0) {\n            this.vrProjection = result.streaming_data.adaptive_formats\n              .find(format => {\n                return format.has_video &&\n                  typeof format.projection_type === 'string' &&\n                  format.projection_type !== 'RECTANGULAR'\n              })\n              ?.projection_type ?? null\n\n            if (\n              videoInfo.info.streaming_data?.server_abr_streaming_url &&\n              videoInfo.info.player_config.media_common_config.media_ustreamer_request_config\n            ) {\n              const storyboards = storyboard\n                ? [{\n                    templateUrl: storyboard.template_url,\n                    mimeType: 'image/webp',\n                    columns: storyboard.columns,\n                    rows: storyboard.rows,\n                    thumbnailCount: storyboard.thumbnail_count,\n                    thumbnailWidth: storyboard.thumbnail_width,\n                    thumbnailHeight: storyboard.thumbnail_height,\n                    storyboardCount: storyboard.storyboard_count,\n                    interval: storyboard.interval > 0 ? storyboard.interval / 1000 : 0\n                  }]\n                : []\n\n              this.manifestSrc = this.createLocalSabrManifest(result, poToken, clientInfo, storyboards)\n              this.manifestMimeType = MANIFEST_TYPE_SABR\n            } else if (\n              result.streaming_data.adaptive_formats[0]?.url ||\n              result.streaming_data.adaptive_formats[0]?.signature_cipher ||\n              result.streaming_data.adaptive_formats[0]?.cipher\n            ) {\n              this.manifestSrc = await this.createLocalDashManifest(result)\n              this.manifestMimeType = MANIFEST_TYPE_DASH\n            } else {\n              this.manifestSrc = null\n              this.enableLegacyFormat()\n            }\n          } else {\n            this.manifestSrc = null\n            this.enableLegacyFormat()\n          }\n        }\n\n        this.isLoading = false\n        this.updateTitle()\n      } catch (err) {\n        const errorMessage = this.$t('Local API Error (Click to copy)')\n        showToast(`${errorMessage}: ${err}`, 10000, () => {\n          copyToClipboard(err)\n        })\n        console.error(err)\n        if (this.backendPreference === 'local' && this.backendFallback && !err.toString().includes('private')) {\n          showToast(this.$t('Falling back to Invidious API'))\n          this.getVideoInformationInvidious()\n        } else {\n          this.isLoading = false\n        }\n      }\n    },\n\n    getVideoInformationInvidious: function () {\n      if (this.firstLoad) {\n        this.isLoading = true\n      }\n\n      invidiousGetVideoInformation(this.videoId)\n        .then(async result => {\n          if (result.error) {\n            throw new Error(result.error)\n          }\n\n          this.videoTitle = result.title\n          this.videoViewCount = result.viewCount\n\n          const subCount = parseLocalSubscriberCount(result.subCountText)\n          if (!isNaN(subCount)) {\n            this.channelSubscriptionCountText = formatNumber(subCount, subCount >= 10000 ? { notation: 'compact' } : undefined)\n          } else {\n            this.channelSubscriptionCountText = ''\n          }\n\n          if (this.hideVideoLikesAndDislikes) {\n            this.videoLikeCount = null\n            this.videoDislikeCount = null\n          } else {\n            this.videoLikeCount = result.likeCount\n            this.videoDislikeCount = result.dislikeCount\n          }\n\n          this.videoGenreIsMusic = result.genre === 'Music'\n\n          this.channelId = result.authorId\n          this.channelName = result.author\n          const channelThumb = result.authorThumbnails[1]\n          this.channelThumbnail = channelThumb ? youtubeImageUrlToInvidious(channelThumb.url, this.currentInvidiousInstanceUrl) : ''\n          this.updateSubscriptionDetails({\n            channelThumbnailUrl: channelThumb?.url,\n            channelName: result.author,\n            channelId: result.authorId\n          })\n\n          this.videoPublished = result.published * 1000\n          this.videoDescriptionHtml = result.descriptionHtml\n          const recommendedVideos = result.recommendedVideos\n\n          // The recommended videos currently use yyyy-mm-ddThh:mm:ss for the published timestamp\n          // whereas the rest of the API uses unix timestamps, correct that here\n          recommendedVideos.forEach((video) => {\n            if (typeof video.published === 'string') {\n              video.published = Date.parse(video.published)\n            }\n          })\n\n          // place watched recommended videos last\n          this.recommendedVideos = [\n            ...recommendedVideos.filter((video) => !this.isRecommendedVideoWatched(video.videoId)),\n            ...recommendedVideos.filter((video) => this.isRecommendedVideoWatched(video.videoId))\n          ]\n          this.isLive = result.liveNow\n          this.isFamilyFriendly = result.isFamilyFriendly\n          this.isPostLiveDvr = !!result.isPostLiveDvr\n          this.isUnlisted = !result.isListed\n\n          this.captions = sortCaptions(result.captions.map(caption => {\n            return {\n              url: this.currentInvidiousInstanceUrl + caption.url,\n              label: caption.label,\n              language: caption.language_code,\n              mimeType: 'text/vtt'\n            }\n          }))\n\n          if (!this.isLive && !this.isPostLiveDvr) {\n            this.videoStoryboardSrc = `${this.currentInvidiousInstanceUrl}/api/v1/storyboards/${this.videoId}?height=90`\n          }\n\n          switch (this.thumbnailPreference) {\n            case 'start':\n              this.thumbnail = `${this.currentInvidiousInstanceUrl}/vi/${this.videoId}/maxres1.jpg`\n              break\n            case 'middle':\n              this.thumbnail = `${this.currentInvidiousInstanceUrl}/vi/${this.videoId}/maxres2.jpg`\n              break\n            case 'end':\n              this.thumbnail = `${this.currentInvidiousInstanceUrl}/vi/${this.videoId}/maxres3.jpg`\n              break\n            default:\n              this.thumbnail = result.videoThumbnails[0].url\n              break\n          }\n\n          let chapters = []\n          if (!this.hideChapters) {\n            chapters = this.extractChaptersFromDescription(result.description)\n\n            if (chapters.length > 0) {\n              this.addChaptersEndSeconds(chapters, result.lengthSeconds)\n\n              // prevent vue from adding reactivity which isn't needed\n              // as the chapter objects are read-only after this anyway\n              // the chapters are checked for every timeupdate event that the player emits\n              // this should lessen the performance and memory impact of the chapters\n              chapters.forEach(Object.freeze)\n            }\n          }\n          this.videoChapters = chapters\n\n          if (this.isLive || this.isPostLiveDvr) {\n            // The live DASH manifest is currently unusable as it returns 403s after 1 minute of playback\n            // so we have to use the HLS one for now.\n            // Leaving the code here commented out in case we can use it again in the future\n            // const url = `${this.currentInvidiousInstanceUrl}/api/manifest/dash/id/${this.videoId}`\n\n            // // Proxying doesn't work for live or post live DVR DASH, so use HLS instead\n            // // https://github.com/iv-org/invidious/pull/4589\n            // if (this.proxyVideos) {\n\n            this.streamingDataExpiryDate = this.extractExpiryDateFromStreamingUrl(result.adaptiveFormats[0].url)\n\n            let hlsManifestUrl = result.hlsUrl\n\n            if (this.proxyVideos) {\n              const url = new URL(hlsManifestUrl)\n              url.searchParams.set('local', 'true')\n              hlsManifestUrl = url.toString()\n            }\n\n            this.manifestSrc = hlsManifestUrl\n            this.manifestMimeType = MANIFEST_TYPE_HLS\n\n            // The HLS manifests only contain combined audio+video streams, so we can't do audio only\n            if (this.activeFormat === 'audio') {\n              this.activeFormat = 'dash'\n            }\n            // } else {\n            //   this.manifestSrc = url\n            //   this.manifestMimeType = MANIFEST_TYPE_DASH\n            // }\n\n            this.legacyFormats = []\n\n            if (this.activeFormat === 'legacy') {\n              this.activeFormat = 'dash'\n            }\n          } else {\n            this.videoLengthSeconds = result.lengthSeconds\n\n            this.streamingDataExpiryDate = this.extractExpiryDateFromStreamingUrl(result.adaptiveFormats[0].url)\n\n            this.legacyFormats = result.formatStreams.map(mapInvidiousLegacyFormat)\n\n            if (!process.env.SUPPORTS_LOCAL_API || this.proxyVideos) {\n              this.legacyFormats.forEach(format => {\n                format.url = getProxyUrl(format.url)\n              })\n            }\n\n            this.vrProjection = result.adaptiveFormats\n              .find(stream => {\n                return typeof stream.projectionType === 'string' &&\n                  stream.projectionType !== 'RECTANGULAR'\n              })\n              ?.projectionType ?? null\n\n            this.manifestSrc = await this.createInvidiousDashManifest(result)\n            this.manifestMimeType = MANIFEST_TYPE_DASH\n          }\n\n          this.updateTitle()\n\n          this.isLoading = false\n        })\n        .catch(err => {\n          console.error(err)\n          const errorMessage = this.$t('Invidious API Error (Click to copy)')\n          showToast(`${errorMessage}: ${err}`, 10000, () => {\n            copyToClipboard(err)\n          })\n          console.error(err)\n          if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) {\n            showToast(this.$t('Falling back to Local API'))\n            this.getVideoInformationLocal()\n          } else {\n            this.isLoading = false\n          }\n        })\n    },\n\n    extractExpiryDateFromStreamingUrl: function (url) {\n      const expireString = new URL(url).searchParams.get('expire')\n\n      return new Date(parseInt(expireString) * 1000)\n    },\n\n    /**\n     * @param {string?} description\n     */\n    extractChaptersFromDescription: function (description) {\n      if (description == null) { return [] }\n\n      /** @type {{title: string, timestamp: string, startSeconds: number, endSeconds: number}[]} */\n      const chapters = []\n\n      // HH:MM:SS Text\n      // MM:SS Text\n      // HH:MM:SS - Text // separator is one of '-', '–', '•', '—'\n      // MM:SS - Text\n      // HH:MM:SS - HH:MM:SS - Text // end timestamp is ignored, separator is one of '-', '–', '—'\n      // HH:MM - HH:MM - Text // end timestamp is ignored\n      const chapterMatches = description.matchAll(/^(?<timestamp>((?<hours>\\d+):)?(?<minutes>\\d+):(?<seconds>\\d+))(\\s*[–—-]\\s*(?:\\d+:){1,2}\\d+)?\\s+([–—•-]\\s*)?(?<title>.+)$/gm)\n\n      for (const { groups } of chapterMatches) {\n        let start = 60 * Number(groups.minutes) + Number(groups.seconds)\n\n        if (groups.hours) {\n          start += 3600 * Number(groups.hours)\n        }\n\n        // replace previous chapter with current one if they have an identical start time\n        if (chapters.length > 0 && chapters[chapters.length - 1].startSeconds === start) {\n          chapters.pop()\n        }\n\n        chapters.push({\n          title: groups.title.trim(),\n          timestamp: groups.timestamp,\n          startSeconds: start,\n          endSeconds: 0\n        })\n      }\n\n      return chapters\n    },\n\n    addChaptersEndSeconds: function (chapters, videoLengthSeconds) {\n      for (let i = 0; i < chapters.length - 1; i++) {\n        chapters[i].endSeconds = chapters[i + 1].startSeconds\n      }\n      chapters.at(-1).endSeconds = videoLengthSeconds\n    },\n\n    /**\n     * @param {number} currentSeconds\n     */\n    updateCurrentChapter: function (currentSeconds) {\n      const chapters = this.videoChapters\n\n      if (this.hideChapters || chapters.length === 0) {\n        return\n      }\n\n      const currentChapterStart = chapters[this.videoCurrentChapterIndex].startSeconds\n\n      if (currentSeconds !== currentChapterStart) {\n        let i = currentSeconds < currentChapterStart ? 0 : this.videoCurrentChapterIndex\n\n        for (; i < chapters.length; i++) {\n          if (currentSeconds < chapters[i].endSeconds) {\n            this.videoCurrentChapterIndex = i\n            break\n          }\n        }\n      }\n    },\n\n    addToHistory: function (watchProgress) {\n      const videoData = {\n        videoId: this.videoId,\n        title: this.videoTitle,\n        author: this.channelName,\n        authorId: this.channelId,\n        published: this.videoPublished,\n        description: this.videoDescription,\n        viewCount: this.videoViewCount,\n        lengthSeconds: this.videoLengthSeconds,\n        watchProgress: watchProgress,\n        timeWatched: Date.now(),\n        isLive: false,\n        type: 'video',\n      }\n\n      this.updateHistory(videoData)\n    },\n\n    handleWatchProgressManualSave() {\n      // Should be called by manual action, settings should be checked in UI\n      this._saveWatchProgress()\n      showToast(this.$t('Video.Watched Progress Saved'))\n    },\n    handleWatchProgressAutoSave() {\n      if (!this.rememberHistory || !this.autosaveWatchedProgress) { return }\n      this._saveWatchProgress()\n    },\n    handleWatchProgressAutoSaveWhenProgressEnabled() {\n      if (!this.rememberHistory || !this.watchedProgressSavingEnabled) { return }\n      this._saveWatchProgress()\n    },\n    _saveWatchProgress() {\n      if (!this.canSaveWatchProgress) { return }\n      if (!this.$refs.player?.hasLoaded) { return }\n\n      const currentTime = this.getWatchedProgress()\n      const payload = {\n        videoId: this.videoId,\n        watchProgress: currentTime\n      }\n      this.updateWatchProgress(payload)\n    },\n\n    handlePlaylistPersisting: function () {\n      // Only save playlist ID if enabled, and it's not special video types\n      if (!(this.rememberHistory && this.saveVideoHistoryWithLastViewedPlaylist)) { return }\n      if (this.isUpcoming || this.isLive) { return }\n\n      this.updateLastViewedPlaylist({\n        videoId: this.videoId,\n        // Whether there is a playlist ID or not, save it\n        lastViewedPlaylistId: this.playlistId,\n        lastViewedPlaylistType: this.playlistType,\n        lastViewedPlaylistItemId: this.playlistItemId,\n      })\n    },\n\n    isRecommendedVideoWatched: function (videoId) {\n      return !!this.$store.getters.getHistoryCacheById[videoId]\n    },\n\n    handleVideoLoaded: function () {\n      // Only used one time = remove after use\n      this.oneTimeTimestamp = null\n\n      // will trigger again if you switch formats or change legacy quality\n      // Check isUpcoming to avoid marking upcoming videos as watched if the user has only watched the trailer\n      if (!this.videoPlayerLoaded && !this.isUpcoming) {\n        this.videoPlayerLoaded = true\n\n        if (this.rememberHistory) {\n          if (this.timestamp) {\n            this.addToHistory(this.timestamp)\n          } else if (this.historyEntryExists) {\n            this.addToHistory(this.historyEntry.watchProgress)\n          } else {\n            this.addToHistory(0)\n          }\n\n          // Must be called AFTER history entry inserted\n          // Otherwise the value is not saved for first time watched videos\n          this.handlePlaylistPersisting()\n        }\n\n        this.updateLocalPlaylistLastPlayedAtSometimes()\n      }\n    },\n\n    checkIfPlaylist: function () {\n      if (this.$route.query == null) {\n        this.watchingPlaylist = false\n        return\n      }\n\n      this.playlistId = this.$route.query.playlistId\n      this.playlistItemId = this.$route.query.playlistItemId\n\n      if (this.playlistId == null || this.playlistId.length === 0) {\n        this.playlistType = ''\n        this.playlistItemId = null\n        this.watchingPlaylist = false\n        return\n      }\n\n      // `playlistId` present\n      if (this.selectedUserPlaylist != null) {\n        // If playlist ID matches a user playlist, it must be user playlist\n        this.playlistType = 'user'\n        this.watchingPlaylist = true\n        return\n      }\n\n      // Still possible to be a user playlist from history\n      // (but user playlist could be already removed)\n      this.playlistType = this.$route.query.playlistType\n      if (this.playlistType !== 'user') {\n        // Remote playlist\n        this.playlistItemId = null\n        this.watchingPlaylist = true\n        return\n      }\n\n      // At this point `playlistType === 'user'`\n      // But the playlist might be already removed\n      if (this.selectedUserPlaylist == null) {\n        // Clear playlist data so that watch history will be properly updated\n        this.playlistId = ''\n        this.playlistType = ''\n        this.playlistItemId = null\n      }\n      this.watchingPlaylist = this.selectedUserPlaylist != null\n    },\n\n    checkIfTimestamp: function () {\n      const oneTimeTimestamp = parseInt(this.$route.query.oneTimeTimestamp)\n      this.oneTimeTimestamp = isNaN(oneTimeTimestamp) || oneTimeTimestamp < 0 ? null : oneTimeTimestamp\n\n      const timestamp = parseInt(this.$route.query.timestamp)\n      this.timestamp = isNaN(timestamp) || timestamp < 0 ? null : timestamp\n    },\n\n    handleFormatChange: function (format) {\n      switch (format) {\n        case 'dash':\n          this.enableDashFormat()\n          break\n        case 'legacy':\n          this.enableLegacyFormat()\n          break\n        case 'audio':\n          this.enableAudioFormat()\n          break\n      }\n    },\n\n    enableDashFormat: function () {\n      if (this.activeFormat === 'dash') {\n        return\n      }\n\n      if (this.manifestSrc === null) {\n        showToast(this.$t('Change Format.Dash formats are not available for this video'))\n        return\n      }\n\n      this.activeFormat = 'dash'\n    },\n\n    enableLegacyFormat: function () {\n      if (this.activeFormat === 'legacy') {\n        return\n      }\n\n      if (this.isLive || this.isPostLiveDvr || this.legacyFormats.length === 0) {\n        showToast(this.$t('Change Format.Legacy formats are not available for this video'))\n        return\n      }\n\n      this.activeFormat = 'legacy'\n    },\n\n    enableAudioFormat: function () {\n      if (this.activeFormat === 'audio') {\n        return\n      }\n\n      if (this.manifestSrc === null ||\n        ((this.isLive || this.isPostLiveDvr) &&\n        // The WEB HLS manifests only contain combined audio and video files, so we can't do audio only\n        // The IOS HLS manifests have audio-only streams\n          this.manifestMimeType === MANIFEST_TYPE_HLS && !this.manifestSrc.includes('/demuxed/1'))) {\n        showToast(this.$t('Change Format.Audio formats are not available for this video'))\n        return\n      }\n\n      this.activeFormat = 'audio'\n    },\n\n    handleVideoEnded: function () {\n      this.handleWatchProgressAutoSaveWhenProgressEnabled()\n      if (!this.autoplayEnabled) {\n        return\n      }\n\n      if (this.blockVideoAutoplay) {\n        showToast(this.$t('Autoplay Interruption Timer',\n          this.defaultAutoplayInterruptionIntervalHours,\n          {\n            autoplayInterruptionIntervalHours: this.defaultAutoplayInterruptionIntervalHours\n          }),\n        3_600_000\n        )\n        this.resetAutoplayInterruptionTimeout()\n        return\n      }\n\n      if (this.watchingPlaylist && this.$refs.watchVideoPlaylist?.shouldStopDueToPlaylistEnd) {\n        // Let `watchVideoPlaylist` handle end of playlist, no countdown needed\n        this.$refs.watchVideoPlaylist.playNextVideo()\n        return\n      }\n\n      let nextVideoId = null\n      if (!this.watchingPlaylist) {\n        nextVideoId = this.nextRecommendedVideo?.videoId\n        if (!nextVideoId) {\n          return\n        }\n      }\n\n      const nextVideoInterval = this.defaultInterval\n      this.playNextTimeout = setTimeout(() => {\n        const player = this.$refs.player\n\n        if (player?.isPaused()) {\n          if (this.watchingPlaylist) {\n            this.$refs.watchVideoPlaylist.playNextVideo()\n          } else {\n            this.$router.push({\n              path: `/watch/${nextVideoId}`\n            })\n            showToast(this.$t('Playing Next Video'))\n          }\n        }\n        this.playNextTimeout = null\n      }, nextVideoInterval * 1000)\n\n      if (nextVideoInterval > 0) {\n        // No countdown for 0s interval\n        showToast(\n          ({ remainingMs }) => {\n            const countDownTimeLeftInSecond = remainingMs / 1000\n            return this.$t('Playing Next Video Interval', { nextVideoInterval: countDownTimeLeftInSecond }, countDownTimeLeftInSecond)\n          },\n          // So that we don't see last countdown text like 0/N\n          nextVideoInterval * 1000,\n          this.abortAutoplayCountdown,\n        )\n      }\n    },\n\n    // Skip to the next video if in a playlist\n    // else next recommended video if autoplay enabled\n    handleSkipToNext: function () {\n      if (this.watchingPlaylist) {\n        this.$refs.watchVideoPlaylist?.playNextVideo()\n      } else if (!this.hideRecommendedVideos && this.nextRecommendedVideo) {\n        this.$router.push({\n          path: `/watch/${this.nextRecommendedVideo.videoId}`\n        })\n        showToast(this.$t('Playing Next Video'))\n      }\n    },\n\n    // Skip to the previous video in a playlist\n    handleSkipToPrev: function () {\n      this.$refs.watchVideoPlaylist?.playPreviousVideo()\n    },\n\n    abortAutoplayCountdown: function (hideToast = false) {\n      clearTimeout(this.playNextTimeout)\n      clearInterval(this.playNextCountDownIntervalId)\n      this.playNextTimeout = null\n\n      if (!hideToast) {\n        showToast(this.$t('Canceled next video autoplay'))\n      }\n    },\n\n    handleRouteChange: function () {\n      this.abortAutoplayCountdown(true)\n      this.videoChapters = []\n      this.videoChaptersKind = 'chapters'\n\n      this.handleWatchProgressAutoSave()\n    },\n\n    /**\n     * @param {import('shaka-player/dist/shaka-player.ui').default.util.Error} error\n     */\n    handlePlayerError: function (error) {\n      // the error is logged to the console inside the player so we don't have to do it here\n\n      const { Code } = shaka.util.Error\n\n      if (error.code === Code.HTTP_ERROR) {\n        if (error.data[1]?.message === 'Failed to fetch' && !navigator.onLine) {\n          // Internet connection was lost, do nothing on our side as\n          // shaka-player will keep trying until the internet connection returns and resume playback automatically when it does\n          return\n        }\n      } else if (error.code === Code.BAD_HTTP_STATUS) {\n        switch (error.data[1]) {\n          case 429:\n            this.handleWatchProgressAutoSaveWhenProgressEnabled()\n\n            this.errorMessage = '[BAD_HTTP_STATUS: 429] Ratelimited'\n            return\n          case 403:\n            this.handleWatchProgressAutoSaveWhenProgressEnabled()\n\n            if (new Date() > this.streamingDataExpiryDate) {\n              this.errorMessage = '[BAD_HTTP_STATUS: 403] YouTube watch session expired. Please reopen this video.'\n              this.customErrorIcon = ['fas', 'clock']\n              return\n            }\n\n            if (this.videoGenreIsMusic) {\n              this.errorMessage = '[BAD_HTTP_STATUS: 403] Potential causes: IP block, streaming URL deciphering failed or music video geo-block'\n            } else {\n              this.errorMessage = '[BAD_HTTP_STATUS: 403] Potential causes: IP block or streaming URL deciphering failed'\n            }\n            return\n        }\n      } else if (error.code === Code.VIDEO_ERROR) {\n        if (this.activeFormat === 'legacy') {\n          if (new Date() > this.streamingDataExpiryDate) {\n            this.handleWatchProgressAutoSaveWhenProgressEnabled()\n\n            this.errorMessage = '[VIDEO_ERROR] YouTube watch session expired. Please reopen this video.'\n            this.customErrorIcon = ['fas', 'clock']\n            return\n          }\n        }\n      }\n\n      if (this.isLive || this.isPostLiveDvr) {\n        // live streams don't have legacy formats, so only switch between dash and audio\n\n        if (this.activeFormat === 'dash') {\n          console.error('Unable to play DASH formats. Reverting to audio formats...')\n          this.enableAudioFormat()\n        } else {\n          console.error('Unable to play audio formats. Reverting to DASH formats...')\n          this.enableDashFormat()\n        }\n      } else {\n        // loop through formats DASH -> legacy -> audio -> DASH\n\n        switch (this.activeFormat) {\n          case 'dash':\n            console.error('Unable to play DASH formats. Reverting to legacy formats...')\n            this.enableLegacyFormat()\n            break\n          case 'legacy':\n            console.error('Unable to play legacy formats. Reverting to audio formats...')\n            this.enableAudioFormat()\n            break\n          case 'audio':\n            console.error('Unable to play audio formats. Reverting to DASH formats...')\n            this.enableDashFormat()\n            break\n        }\n      }\n    },\n\n    /**\n     * @param {import('youtubei.js').YT.VideoInfo} videoInfo\n     * @param {boolean} includeThumbnails\n     */\n    createLocalDashManifest: async function (videoInfo, includeThumbnails = false) {\n      const xmlData = await videoInfo.toDash({\n        manifest_options: {\n          include_thumbnails: includeThumbnails,\n        },\n      })\n\n      return `data:application/dash+xml;charset=UTF-8,${encodeURIComponent(xmlData)}`\n    },\n\n    /**\n     * @param {import('youtubei.js').IParsedResponse} videoInfo\n     * @param {string} poToken\n     * @param {SabrData['clientInfo']} clientInfo\n     * @param {import('../../helpers/player/SabrManifestParser').SabrManifest['storyboards']} storyboards\n     */\n    createLocalSabrManifest: function (videoInfo, poToken, clientInfo, storyboards) {\n      const url = new URL(videoInfo.streaming_data.server_abr_streaming_url)\n      url.searchParams.set('alr', 'yes')\n      url.searchParams.set('cpn', videoInfo.cpn)\n\n      this.sabrData = {\n        url: url.toString(),\n        poToken,\n        ustreamerConfig: videoInfo.player_config.media_common_config.media_ustreamer_request_config.video_playback_ustreamer_config,\n        clientInfo\n      }\n\n      /** @type {import('../../helpers/player/SabrManifestParser').SabrManifest} */\n      const sabrManifest = {\n        // Different formats have different durations and\n        // use of slightly longer duration in PresentationTimeline causes player to stuck at the end\n        duration: Math.min(...videoInfo.streaming_data.adaptive_formats.map(f => f.approx_duration_ms)) / 1000,\n        formats: videoInfo.streaming_data.adaptive_formats.map((format) => ({\n          itag: format.itag,\n          lastModified: format.last_modified_ms,\n          mimeType: format.mime_type,\n          xtags: format.xtags,\n          bitrate: format.bitrate,\n          initRange: format.init_range,\n          indexRange: format.index_range,\n          width: format.width,\n          height: format.height,\n          frameRate: format.fps,\n          quality: format.quality,\n          language: format.language,\n          audioSampleRate: format.audio_sample_rate,\n          audioChannels: format.audio_channels,\n          isDrc: format.is_drc,\n          isVoiceBoost: format.is_vb,\n          isOriginal: format.is_original,\n          isDubbed: format.is_dubbed,\n          isAutoDubbed: format.is_auto_dubbed,\n          isDescriptive: format.is_descriptive,\n          isSecondary: format.is_secondary,\n          spatialAudio: !!format.spatial_audio_type,\n          label: format.audio_track?.display_name,\n          colorTransferCharacteristics: format.color_info?.transfer_characteristics,\n          colorPrimaries: format.color_info?.primaries\n        })),\n        captions: this.captions,\n        storyboards\n      }\n\n      return `data:${MANIFEST_TYPE_SABR},${encodeURIComponent(JSON.stringify(sabrManifest))}`\n    },\n\n    createInvidiousDashManifest: async function (result) {\n      let url = `${this.currentInvidiousInstanceUrl}/api/manifest/dash/id/${this.videoId}`\n\n      // If we are in Electron,\n      // we can use YouTube.js' DASH manifest generator to generate the manifest.\n      // Using YouTube.js' gives us support for multiple audio tracks (currently not supported by Invidious)\n      if (process.env.SUPPORTS_LOCAL_API) {\n        const adaptiveFormats = await this.getAdaptiveFormatsInvidious(result)\n\n        /** @type {import('youtubei.js').Misc.Format[]} */\n        const formats = []\n\n        /** @type {import('youtubei.js').Misc.Format[]} */\n        const audioFormats = []\n\n        let hasMultipleAudioTracks = false\n\n        for (const format of adaptiveFormats) {\n          const localFormat = convertInvidiousToLocalFormat(format)\n\n          if (localFormat.has_audio) {\n            audioFormats.push(localFormat)\n\n            if (localFormat.is_dubbed || localFormat.is_descriptive || localFormat.is_secondary || localFormat.is_auto_dubbed) {\n              hasMultipleAudioTracks = true\n            }\n          }\n\n          formats.push(localFormat)\n        }\n\n        if (hasMultipleAudioTracks) {\n          // match YouTube's local API response with English\n          const languageNames = new Intl.DisplayNames('en-US', { type: 'language', languageDisplay: 'standard' })\n          for (const format of audioFormats) {\n            this.generateAudioTrackFieldInvidious(format, languageNames)\n          }\n        }\n\n        const manifest = await generateInvidiousDashManifestLocally(formats)\n\n        url = `data:application/dash+xml;charset=UTF-8,${encodeURIComponent(manifest)}`\n      } else if (this.proxyVideos) {\n        url += '?local=true'\n      }\n\n      return url\n    },\n\n    /**\n     * @param {import('youtubei.js').Misc.Format} format\n     * @param {Intl.DisplayNames} languageNames\n     */\n    generateAudioTrackFieldInvidious: function (format, languageNames) {\n      let type\n\n      // use the same id numbers as YouTube (except -1, when we aren't sure what it is)\n      let idNumber\n\n      if (format.is_descriptive) {\n        type = ' descriptive'\n        idNumber = 2\n      } else if (format.is_dubbed) {\n        type = ''\n        idNumber = 3\n      } else if (format.is_original) {\n        type = ' original'\n        idNumber = 4\n      } else if (format.is_secondary) {\n        type = ' secondary'\n        idNumber = 6\n      } else if (format.is_auto_dubbed) {\n        type = ''\n        idNumber = 10\n      } else {\n        type = ' alternative'\n        idNumber = -1\n      }\n\n      const languageName = languageNames.of(format.language)\n\n      format.audio_track = {\n        audio_is_default: !!format.is_original,\n        id: `${format.language}.${idNumber}`,\n        display_name: `${languageName}${type}`\n      }\n    },\n\n    getAdaptiveFormatsInvidious: async function (existingInfoResult = null) {\n      let result\n      if (existingInfoResult) {\n        result = existingInfoResult\n      } else {\n        result = await invidiousGetVideoInformation(this.videoId)\n      }\n\n      result.adaptiveFormats.forEach((format) => {\n        format.bitrate = parseInt(format.bitrate)\n\n        // audio streams don't have a size property\n        if (typeof format.size === 'string') {\n          const [stringWidth, stringHeight] = format.size.split('x')\n\n          format.width = parseInt(stringWidth)\n          format.height = parseInt(stringHeight)\n        }\n      })\n\n      return result.adaptiveFormats\n    },\n\n    /**\n     * @param {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData} storyboardInfo\n     * @returns {string}\n     */\n    createLocalStoryboardUrls: function (storyboardInfo) {\n      const results = buildVTTFileLocally(storyboardInfo, this.videoLengthSeconds)\n\n      return `data:text/vtt;charset=utf-8,${encodeURIComponent(results)}`\n    },\n\n    /**\n     * @param {import('youtubei.js').YTNodes.PlayerCaptionsTracklist} captions\n     * @param {Set<string>} userLanguages\n     * @returns {null|{ url: string, label: string, language: string, mimeType: string, isAutotranslated: boolean }}\n     */\n    getTranslatedLocaleCaption: function (captions, userLanguages) {\n      // check if we can translate to the users language\n      const translationLanguage = captions.translation_languages.find(language => userLanguages.has(language.language_code))\n\n      let translationName, translationCode\n      // otherwise just fallback to the FreeTube display language and hope that YouTube will be able to handle it\n      if (!translationLanguage) {\n        translationName = this.$t('Locale Name')\n        translationCode = userLanguages.values().next().value\n      } else {\n        translationName = translationLanguage.language_name.text\n        translationCode = translationLanguage.language_code\n      }\n\n      let trackToTranslate\n\n      const autoGeneratedCaptionTrack = captions.caption_tracks.find(track => track.kind === 'asr')\n      if (autoGeneratedCaptionTrack) {\n        // Check if there is a user uploaded caption track in the language of the video, as that is more trustworthy than auto-generated captions\n        const userUploadedCaptionTrack = captions.caption_tracks.find(track => track.kind !== 'asr' && track.language_code === autoGeneratedCaptionTrack.language_code)\n\n        // Fallback to the auto-generated track if there is no user uploaded one that matches the video language\n        trackToTranslate = userUploadedCaptionTrack ?? autoGeneratedCaptionTrack\n      } else {\n        // if there is no auto-generated track choose the first translatable track\n        trackToTranslate = captions.caption_tracks.find(track => track.is_translatable) ?? captions.caption_tracks[0]\n      }\n\n      const url = new URL(trackToTranslate.base_url)\n      // Requesting fmt=vtt with the tlang parameter set returns HTTP 429 errors, but requesting srt instead seems to work\n      url.searchParams.set('fmt', 'srt')\n      url.searchParams.set('tlang', translationCode)\n\n      const label = this.$t('Video.Player.TranslatedCaptionTemplate', {\n        language: translationName,\n        originalLanguage: trackToTranslate.name.text\n      })\n\n      return {\n        id: `${trackToTranslate.vss_id}.${translationCode}`,\n        url: url.toString(),\n        label,\n        language: translationCode,\n        mimeType: 'text/srt',\n        isAutotranslated: true\n      }\n    },\n\n    pausePlayer: function () {\n      const player = this.$refs.player\n\n      if (player && !player.isPaused()) {\n        player.pause()\n      }\n    },\n\n    getWatchedProgress: function () {\n      const player = this.$refs.player\n\n      if (!this.isLoading && player?.hasLoaded) {\n        return player.getCurrentTime()\n      }\n\n      return 0\n    },\n\n    getTimestamp: function () {\n      return Math.floor(this.getWatchedProgress())\n    },\n\n    getPlaylistIndex: function () {\n      return this.$refs.watchVideoPlaylist\n        ? this.getPlaylistReverse()\n          ? this.$refs.watchVideoPlaylist.playlistItems.length - this.$refs.watchVideoPlaylist.currentVideoIndexOneBased\n          : this.$refs.watchVideoPlaylist.currentVideoIndexZeroBased\n        : -1\n    },\n\n    getPlaylistReverse: function () {\n      return this.$refs.watchVideoPlaylist ? this.$refs.watchVideoPlaylist.reversePlaylist : false\n    },\n\n    getPlaylistShuffle: function () {\n      return this.$refs.watchVideoPlaylist ? this.$refs.watchVideoPlaylist.shuffleEnabled : false\n    },\n\n    getPlaylistLoop: function () {\n      return this.$refs.watchVideoPlaylist ? this.$refs.watchVideoPlaylist.loopEnabled : false\n    },\n\n    updateTitle: function () {\n      this.setAppTitle(`${this.videoTitle} - ${packageDetails.productName}`)\n    },\n\n    isHiddenVideo: function (forbiddenTitles, channelsHidden, video) {\n      return channelsHidden.some(ch => ch.name === video.authorId) ||\n        channelsHidden.some(ch => ch.name === video.author) ||\n        forbiddenTitles.some((text) => video.title?.toLowerCase().includes(text)) ||\n        forbiddenTitles.some((text) => video.author?.toLowerCase().includes(text))\n    },\n\n    toggleAutoplay: function() {\n      if (this.autoplayEnabled && this.playNextTimeout) {\n        this.abortAutoplayCountdown()\n      }\n\n      if (this.watchingPlaylist) {\n        this.autoplayNextPlaylistVideo = !this.autoplayEnabled\n      } else {\n        this.autoplayNextRecommendedVideo = !this.autoplayEnabled\n      }\n    },\n\n    updateLocalPlaylistLastPlayedAtSometimes() {\n      if (this.selectedUserPlaylist == null) { return }\n\n      const playlist = this.selectedUserPlaylist\n      this.updatePlaylistLastPlayedAt({ _id: playlist._id })\n    },\n\n    resetAutoplayInterruptionTimeout() {\n      clearTimeout(this.autoplayInterruptionTimeout)\n      this.autoplayInterruptionTimeout = setTimeout(() => { this.blockVideoAutoplay = true }, this.defaultAutoplayInterruptionIntervalHours * 3_600_000)\n      this.blockVideoAutoplay = false\n    },\n\n    updatePlaybackRate(newRate) {\n      this.currentPlaybackRate = newRate\n    },\n\n    destroyPlayer: async function() {\n      const uiState = await this.$refs.player.destroyPlayer()\n      this.startNextVideoInFullscreen = uiState.startNextVideoInFullscreen\n      this.startNextVideoInFullwindow = uiState.startNextVideoInFullwindow\n      this.startNextVideoInPip = uiState.startNextVideoInPip\n    },\n\n    async onPlayerReloadRequested() {\n      showToast('Reloading player according to SABR request')\n\n      const timestamp = this.getTimestamp()\n      if (timestamp > 0) {\n        // Reload at the middle should restart at current timestamp\n        try {\n          await this.$router.replace({\n            path: this.$route.path,\n            query: { ...this.$route.query, oneTimeTimestamp: timestamp },\n          })\n        } catch (failure) {\n          if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {\n            // Already on route with same timestamp, allow reloadView to run instead\n          } else {\n            throw failure\n          }\n        }\n      }\n      await this.reloadView()\n    },\n\n    ...mapActions([\n      'updateHistory',\n      'updateWatchProgress',\n      'updateLastViewedPlaylist',\n      'updatePlaylistLastPlayedAt',\n      'updateSubscriptionDetails',\n    ]),\n\n    ...mapMutations([\n      'setAppTitle'\n    ])\n  }\n})\n"
  },
  {
    "path": "src/renderer/views/Watch/Watch.scss",
    "content": "@mixin dual-column-template {\n  grid-template: 'video video sidebar' 0fr 'info info sidebar' auto 'info info sidebar' 1fr / 1fr 1fr 1fr;\n}\n\n@mixin theatre-mode-template {\n  grid-template: 'video video video' auto 'info info sidebar' auto 'info info sidebar' auto / 1fr 1fr 1fr;\n}\n\n@mixin single-column-template {\n  grid-template: 'video' auto 'info' auto 'sidebar' auto / auto;\n}\n\n.ageRestricted {\n  @include single-column-template;\n\n  display: inline-block;\n  max-inline-size: calc(80vh * 1.78);\n\n  @media only screen and (width >= 1051px) {\n    inline-size: 300%;\n  }\n}\n\n.premiereDate {\n  align-items: center;\n  background-color: rgb(0 0 0 / 80%);\n  border-radius: 5px;\n  inset-block-end: 12px;\n  color: #fff;\n  display: flex;\n  block-size: 60px;\n  inset-inline-start: 12px;\n  padding-block: 0;\n  padding-inline: 12px;\n  position: absolute;\n\n  .premiereIcon {\n    float: inline-start;\n    font-size: 25px;\n    margin-block: 0;\n    margin-inline: 12px;\n  }\n\n  .premiereText {\n    margin-block: 0;\n    margin-inline: 12px;\n    min-inline-size: 200px;\n\n    .premiereTextTimestamp {\n      font-size: 0.85em;\n      font-weight: bold;\n    }\n  }\n}\n\n.premiereDate.trailer {\n  margin-block-start: 8px;\n  position: static;\n}\n\n.videoLayout {\n  @include dual-column-template;\n\n  align-items: start;\n  display: grid;\n\n  &.isLoading,\n  &.noSidebar {\n    @include single-column-template;\n  }\n\n  .videoArea {\n    grid-area: video;\n\n    .videoAreaMargin {\n      margin-block: 0 16px;\n      margin-inline: 0;\n    }\n\n    .videoPlayer {\n      grid-column: 1;\n      margin-block: 0;\n      margin-inline: auto;\n      max-inline-size: calc(80vh * 1.78);\n      position: relative;\n\n      .videoThumbnail {\n        inline-size: 100%;\n      }\n\n      .errorContainer {\n        position: absolute;\n        inset: 30px;\n        display: grid;\n        place-content: center;\n      }\n\n      .errorWrapper {\n        display: flex;\n        flex-direction: row;\n        align-items: center;\n        gap: 20px;\n        padding: 10px;\n        border-radius: 20px;\n        background-color: rgb(0 0 0 / 90%);\n        color: #fff;\n      }\n\n      .errorIcon {\n        font-size: 80px;\n      }\n\n      .errorMessage {\n        margin: 0;\n      }\n\n      @media only screen and (width <= 680px) {\n        .errorContainer {\n          inset: 10px;\n        }\n\n        .errorWrapper {\n          gap: 10px;\n        }\n\n        .errorIcon {\n          font-size: 60px;\n        }\n      }\n    }\n  }\n\n  .watchVideo {\n    grid-column: 1;\n    margin-block: 0 16px;\n    margin-inline: 0;\n  }\n\n  .infoArea {\n    grid-area: info;\n    position: relative;\n    z-index: 2;\n  }\n\n  .sidebarArea {\n    grid-area: sidebar;\n\n    @media only screen and (width >= 1051px) {\n      min-inline-size: 380px;\n    }\n\n    @at-root .noSidebar#{&} {\n      grid-area: auto;\n    }\n  }\n\n  .watchVideoPlaylist,\n  .watchVideoSidebar,\n  .theatrePlaylist {\n    margin-block: 0 16px;\n    margin-inline: 8px;\n  }\n\n  .watchVideoSidebar,\n  .watchVideoPlaylist {\n    block-size: 500px;\n  }\n\n  .watchVideoPlaylist {\n    :deep(.videoThumbnail) {\n      margin-block: auto;\n    }\n\n    @media (width <= 768px) {\n      block-size: auto;\n    }\n  }\n\n  .watchVideoRecommendations,\n  .theatreRecommendations {\n    margin-block: 0 16px;\n    margin-inline: 0;\n\n    @media only screen and (width >= 1051px) {\n      margin-block: 0 16px;\n      margin-inline: 8px;\n    }\n  }\n\n  @media only screen and (width <= 1350px) {\n    @include theatre-mode-template;\n  }\n\n  @media only screen and (width >= 1051px) {\n    &.useTheatreMode {\n      @include theatre-mode-template;\n    }\n  }\n\n  @media only screen and (width <= 1050px) {\n    @include single-column-template;\n  }\n\n  @media only screen and (width >= 1051px) {\n    .infoArea {\n      scroll-margin-block-start: 76px;\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/views/Watch/Watch.vue",
    "content": "<template>\n  <div\n    class=\"videoLayout\"\n    :class=\"{\n      isLoading,\n      useTheatreMode: useTheatreMode && !isLoading,\n      noSidebar: !theatrePossible\n    }\"\n  >\n    <ft-loader\n      v-if=\"isLoading\"\n      :fullscreen=\"true\"\n    />\n    <div\n      v-if=\"(isFamilyFriendly || !showFamilyFriendlyOnly)\"\n      class=\"videoArea\"\n    >\n      <div class=\"videoAreaMargin\">\n        <ft-shaka-video-player\n          v-if=\"!isLoading && (!isUpcoming || playabilityStatus === 'OK') && !errorMessage\"\n          ref=\"player\"\n          :manifest-src=\"manifestSrc\"\n          :manifest-mime-type=\"manifestMimeType\"\n          :sabr-data=\"sabrData\"\n          :legacy-formats=\"legacyFormats\"\n          :start-time=\"startTimeSeconds\"\n          :captions=\"captions\"\n          :storyboard-src=\"videoStoryboardSrc\"\n          :format=\"activeFormat\"\n          :thumbnail=\"thumbnail\"\n          :video-id=\"videoId\"\n          :chapters=\"videoChapters\"\n          :current-chapter-index=\"videoCurrentChapterIndex\"\n          :title=\"videoTitle\"\n          :theatre-possible=\"theatrePossible\"\n          :use-theatre-mode=\"useTheatreMode\"\n          :autoplay-possible=\"autoplayPossible\"\n          :autoplay-enabled=\"autoplayEnabled\"\n          :watching-playlist=\"watchingPlaylist\"\n          :vr-projection=\"vrProjection\"\n          :start-in-fullscreen=\"startNextVideoInFullscreen\"\n          :start-in-fullwindow=\"startNextVideoInFullwindow\"\n          :start-in-pip=\"startNextVideoInPip\"\n          :current-playback-rate=\"currentPlaybackRate\"\n          :delay-load-until-unix=\"adEndTimeUnixMs\"\n          class=\"videoPlayer\"\n          @error=\"handlePlayerError\"\n          @loaded=\"handleVideoLoaded\"\n          @timeupdate=\"updateCurrentChapter\"\n          @ended=\"handleVideoEnded\"\n          @toggle-theatre-mode=\"useTheatreMode = !useTheatreMode\"\n          @toggle-autoplay=\"toggleAutoplay\"\n          @playback-rate-updated=\"updatePlaybackRate\"\n          @skip-to-next=\"handleSkipToNext\"\n          @skip-to-prev=\"handleSkipToPrev\"\n          @player-reload-requested=\"onPlayerReloadRequested\"\n        />\n        <div\n          v-if=\"!isLoading && (isUpcoming || errorMessage)\"\n          class=\"videoPlayer\"\n        >\n          <img\n            v-if=\"!isUpcoming || playabilityStatus !== 'OK'\"\n            :src=\"thumbnail\"\n            class=\"videoThumbnail\"\n            alt=\"\"\n          >\n          <div\n            v-if=\"isUpcoming\"\n            class=\"premiereDate\"\n            :class=\"{trailer: isUpcoming && playabilityStatus === 'OK'}\"\n          >\n            <font-awesome-icon\n              :icon=\"['fas', 'satellite-dish']\"\n              class=\"premiereIcon\"\n            />\n            <p\n              v-if=\"upcomingTimestamp !== null\"\n              class=\"premiereText\"\n            >\n              <span\n                class=\"premiereTextTimeLeft\"\n              >\n                {{ $t(\"Video.Premieres\") }} {{ upcomingTimeLeft }}\n              </span>\n              <br>\n              <span\n                class=\"premiereTextTimestamp\"\n              >\n                {{ upcomingTimestamp }}\n              </span>\n            </p>\n            <p\n              v-else\n              class=\"premiereText\"\n            >\n              {{ $t(\"Video.Starting soon, please refresh the page to check again\") }}\n            </p>\n          </div>\n          <div\n            v-else-if=\"errorMessage\"\n            class=\"errorContainer\"\n          >\n            <div\n              class=\"errorWrapper\"\n            >\n              <font-awesome-icon\n                :icon=\"customErrorIcon || ['fas', 'exclamation-circle']\"\n                aria-hidden=\"true\"\n                class=\"errorIcon\"\n              />\n              <p\n                class=\"errorMessage\"\n              >\n                {{ errorMessage }}\n              </p>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n    <ft-age-restricted\n      v-if=\"(!isLoading && !isFamilyFriendly && showFamilyFriendlyOnly)\"\n      class=\"ageRestricted\"\n    />\n    <div\n      v-if=\"(isFamilyFriendly || !showFamilyFriendlyOnly)\"\n      class=\"infoArea\"\n    >\n      <watch-video-info\n        v-if=\"!isLoading\"\n        :id=\"videoId\"\n        :title=\"videoTitle\"\n        :channel-id=\"channelId\"\n        :channel-name=\"channelName\"\n        :channel-thumbnail=\"channelThumbnail\"\n        :published=\"videoPublished\"\n        :premiere-date=\"premiereDate\"\n        :subscription-count-text=\"channelSubscriptionCountText\"\n        :like-count=\"videoLikeCount\"\n        :dislike-count=\"videoDislikeCount\"\n        :view-count=\"videoViewCount\"\n        :get-timestamp=\"getTimestamp\"\n        :is-live-content=\"isLiveContent\"\n        :is-live=\"isLive\"\n        :is-upcoming=\"isUpcoming\"\n        :playlist-id=\"playlistId\"\n        :get-playlist-index=\"getPlaylistIndex\"\n        :get-playlist-reverse=\"getPlaylistReverse\"\n        :get-playlist-shuffle=\"getPlaylistShuffle\"\n        :get-playlist-loop=\"getPlaylistLoop\"\n        :length-seconds=\"videoLengthSeconds\"\n        :video-thumbnail=\"thumbnail\"\n        :in-user-playlist=\"!!selectedUserPlaylist\"\n        :is-unlisted=\"isUnlisted\"\n        :can-save-watched-progress=\"canSaveWatchProgress\"\n        class=\"watchVideo\"\n        :class=\"{ theatreWatchVideo: useTheatreMode }\"\n        @change-format=\"handleFormatChange\"\n        @pause-player=\"pausePlayer\"\n        @save-watched-progress=\"handleWatchProgressManualSave\"\n      />\n      <watch-video-chapters\n        v-if=\"!hideChapters && !isLoading && videoChapters.length > 0\"\n        :chapters=\"videoChapters\"\n        :current-chapter-index=\"videoCurrentChapterIndex\"\n        :kind=\"videoChaptersKind\"\n        class=\"watchVideo\"\n        :class=\"{ theatreWatchVideo: useTheatreMode }\"\n        @timestamp-event=\"changeTimestamp\"\n      />\n      <watch-video-description\n        v-if=\"!isLoading && !hideVideoDescription\"\n        :description=\"videoDescription\"\n        :description-html=\"videoDescriptionHtml\"\n        :license=\"license\"\n        class=\"watchVideo\"\n        :class=\"{ theatreWatchVideo: useTheatreMode }\"\n        @timestamp-event=\"changeTimestamp\"\n      />\n      <CommentSection\n        v-if=\"!isLoading && !isLive && !hideComments\"\n        :id=\"videoId\"\n        class=\"watchVideo\"\n        :class=\"{ theatreWatchVideo: useTheatreMode }\"\n        :channel-thumbnail=\"channelThumbnail\"\n        :channel-name=\"channelName\"\n        :video-player-ready=\"videoPlayerLoaded\"\n        @timestamp-event=\"changeTimestamp\"\n      />\n    </div>\n    <div\n      v-if=\"(isFamilyFriendly || !showFamilyFriendlyOnly)\"\n      class=\"sidebarArea\"\n    >\n      <watch-video-live-chat\n        v-if=\"!isLoading && !hideLiveChat && (isLive || isUpcoming)\"\n        :live-chat=\"liveChat\"\n        :video-id=\"videoId\"\n        :channel-id=\"channelId\"\n        class=\"watchVideoSideBar watchVideoPlaylist\"\n        :class=\"{ theatrePlaylist: useTheatreMode }\"\n      />\n      <watch-video-playlist\n        v-if=\"watchingPlaylist\"\n        v-show=\"!isLoading\"\n        ref=\"watchVideoPlaylist\"\n        :watch-view-loading=\"isLoading\"\n        :playlist-id=\"playlistId\"\n        :playlist-type=\"playlistType\"\n        :video-id=\"videoId\"\n        :playlist-item-id=\"playlistItemId\"\n        class=\"watchVideoSideBar watchVideoPlaylist\"\n        :class=\"{ theatrePlaylist: useTheatreMode }\"\n        @pause-player=\"pausePlayer\"\n      />\n      <watch-video-recommendations\n        v-if=\"!isLoading && !hideRecommendedVideos\"\n        :data=\"recommendedVideos\"\n        class=\"watchVideoSideBar watchVideoRecommendations\"\n        :class=\"{\n          theatreRecommendations: useTheatreMode,\n          watchVideoRecommendationsLowerCard: watchingPlaylist || isLive,\n          watchVideoRecommendationsNoCard: !watchingPlaylist || !isLive\n        }\"\n        @pause-player=\"pausePlayer\"\n      />\n    </div>\n  </div>\n</template>\n\n<script src=\"./Watch.js\" />\n<style scoped src=\"./Watch.scss\" lang=\"scss\" />\n"
  },
  {
    "path": "static/.gitkeep",
    "content": ""
  },
  {
    "path": "static/external-player-map.json",
    "content": "[\n    {\n        \"name\": \"None\",\n        \"value\": \"\",\n        \"cmdArguments\": null\n    },\n    {\n        \"name\": \"mpv\",\n        \"value\": \"mpv\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"mpv\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": \"\",\n            \"startOffset\": \"--start=\",\n            \"playbackRate\": \"--speed=\",\n            \"playlistIndex\": \"--playlist-start=\",\n            \"playlistReverse\": null,\n            \"playlistShuffle\": \"--shuffle\",\n            \"playlistLoop\": \"--loop-playlist\"\n        }\n    },\n    {\n        \"name\": \"VLC\",\n        \"value\": \"vlc\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"vlc\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": null,\n            \"startOffset\": \"--start-time=\",\n            \"playbackRate\": \"--rate=\",\n            \"playlistIndex\": null,\n            \"playlistReverse\": null,\n            \"playlistShuffle\": \"--random\",\n            \"playlistLoop\": \"--loop\"\n        }\n    },\n    {\n        \"name\": \"IINA\",\n        \"value\": \"iina\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"iina\",\n            \"defaultCustomArguments\": [\"--no-stdin\"],\n            \"videoUrl\": \"\",\n            \"playlistUrl\": \"\",\n            \"startOffset\": \"--mpv-start=\",\n            \"playbackRate\": \"--mpv-speed=\",\n            \"playlistIndex\": \"--mpv-playlist-start=\",\n            \"playlistReverse\": null,\n            \"playlistShuffle\": \"--mpv-shuffle\",\n            \"playlistLoop\": \"--mpv-loop-playlist\"\n        }\n    },\n      {\n        \"name\": \"SMPlayer\",\n        \"value\": \"smplayer\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"smplayer\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": \"\",\n            \"startOffset\": \"-start\",\n            \"playbackRate\": null,\n            \"playlistIndex\": null,\n            \"playlistReverse\": null,\n            \"playlistShuffle\": null,\n            \"playlistLoop\": null\n        }\n    },\n    {\n        \"name\": \"MPC-BE\",\n        \"value\": \"mpc-be\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"mpc-be64\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": \"\",\n            \"startOffset\": \"/start\",\n            \"playbackRate\": null,\n            \"playlistIndex\": null,\n            \"playlistReverse\": null,\n            \"playlistShuffle\": null,\n            \"playlistLoop\": null\n        }\n    },\n    {\n        \"name\": \"MPC-HC\",\n        \"value\": \"mpc-hc\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"mpc-hc64\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": \"\",\n            \"startOffset\": \"/start\",\n            \"playbackRate\": null,\n            \"playlistIndex\": null,\n            \"playlistReverse\": null,\n            \"playlistShuffle\": null,\n            \"playlistLoop\": null\n        }\n    },\n    {\n        \"name\": \"PotPlayer\",\n        \"value\": \"potplayer\",\n        \"cmdArguments\": {\n            \"defaultExecutable\": \"potplayermini64\",\n            \"defaultCustomArguments\": null,\n            \"videoUrl\": \"\",\n            \"playlistUrl\": null,\n            \"startOffset\": \"/seek=\",\n            \"playbackRate\": null,\n            \"playlistIndex\": null,\n            \"playlistReverse\": null,\n            \"playlistShuffle\": null,\n            \"playlistLoop\": null\n        }\n    },\n    {\n      \"name\": \"Clapper\",\n      \"value\": \"clapper\",\n      \"cmdArguments\": {\n          \"defaultExecutable\": \"clapper\",\n          \"defaultCustomArguments\": null,\n          \"videoUrl\": \"\",\n          \"playlistUrl\": null,\n          \"startOffset\": null,\n          \"playbackRate\": null,\n          \"playlistIndex\": null,\n          \"playlistReverse\": null,\n          \"playlistShuffle\": null,\n          \"playlistLoop\": null\n        }\n    },\n    {\n      \"name\": \"Celluloid\",\n      \"value\": \"celluloid\",\n      \"cmdArguments\": {\n          \"defaultExecutable\": \"celluloid\",\n          \"defaultCustomArguments\": null,\n          \"videoUrl\": \"\",\n          \"playlistUrl\": \"\",\n          \"startOffset\": \"--mpv-start=\",\n          \"playbackRate\": \"--mpv-speed=\",\n          \"playlistIndex\": \"--mpv-playlist-start=\",\n          \"playlistReverse\": null,\n          \"playlistShuffle\": \"--mpv-shuffle\",\n          \"playlistLoop\": \"--mpv-loop-playlist\"\n        }\n    },\n    {\n      \"name\": \"Haruna\",\n      \"value\": \"haruna\",\n      \"cmdArguments\": {\n          \"defaultExecutable\": \"haruna\",\n          \"defaultCustomArguments\": null,\n          \"videoUrl\": \"\",\n          \"playlistUrl\": \"\",\n          \"startOffset\": null,\n          \"playbackRate\": null,\n          \"playlistIndex\": null,\n          \"playlistReverse\": null,\n          \"playlistShuffle\": null,\n          \"playlistLoop\": null\n        }\n    }\n]\n"
  },
  {
    "path": "static/geolocations/ar.json",
    "content": "{\"names\":[\"أذربيجان\",\"أسبانيا\",\"أستراليا\",\"إستونيا\",\"إسرائيل\",\"الأرجنتين\",\"الأردن\",\"الإكوادور\",\"الإمارات العربية المتحدة\",\"البحرين\",\"البرازيل\",\"البرتغال\",\"البوسنة والهرسك\",\"الجبل الأسود\",\"الجزائر\",\"الدنمارك\",\"السلفادور\",\"السنغال\",\"السويد\",\"العراق\",\"الفيليبين\",\"الكويت\",\"ألمانيا\",\"المجر\",\"المغرب\",\"المكسيك\",\"المملكة العربية السعودية\",\"المملكة المتحدة\",\"النرويج\",\"النمسا\",\"الهند\",\"الولايات المتحدة\",\"اليابان\",\"اليمن\",\"اليونان\",\"إندونيسيا\",\"أورغواي\",\"أوغندا\",\"أوكرانيا\",\"أيرلندا\",\"أيسلندا\",\"إيطاليا\",\"بابوا غينيا الجديدة\",\"باراغواي\",\"باكستان\",\"بلجيكا\",\"بلغاريا\",\"بنغلاديش\",\"بنما\",\"بورتوريكو\",\"بولندا\",\"بوليفيا\",\"بيرو\",\"بيلاروسيا\",\"تايلاند\",\"تايوان\",\"تركيا\",\"تشيكيا\",\"تشيلي\",\"تنزانيا\",\"تونس\",\"جامايكا\",\"جمهورية الدومينكان\",\"جنوب إفريقيا\",\"جورجيا\",\"روسيا\",\"رومانيا\",\"زيمبابوي\",\"سريلانكا\",\"سلوفاكيا\",\"سلوفينيا\",\"سنغافورة\",\"سويسرا\",\"شمال مقدونيا\",\"صربيا\",\"عُمان\",\"غانا\",\"غواتيمالا\",\"فرنسا\",\"فنزويلا\",\"فنلندا\",\"فيتنام\",\"قبرص\",\"قطر\",\"كازاخستان\",\"كرواتيا\",\"كمبوديا\",\"كندا\",\"كوريا الجنوبية\",\"كوستاريكا\",\"كولومبيا\",\"كينيا\",\"لاتفيا\",\"لاوس\",\"لبنان\",\"لوكسمبورغ\",\"ليبيا\",\"ليتوانيا\",\"ليشتنشتاين\",\"مالطة\",\"ماليزيا\",\"مصر\",\"مولدوفا\",\"نيبال\",\"نيجيريا\",\"نيكاراغوا\",\"نيوزيلندا\",\"هندوراس\",\"هولندا\",\"هونغ كونغ\"],\"codes\":[\"AZ\",\"ES\",\"AU\",\"EE\",\"IL\",\"AR\",\"JO\",\"EC\",\"AE\",\"BH\",\"BR\",\"PT\",\"BA\",\"ME\",\"DZ\",\"DK\",\"SV\",\"SN\",\"SE\",\"IQ\",\"PH\",\"KW\",\"DE\",\"HU\",\"MA\",\"MX\",\"SA\",\"GB\",\"NO\",\"AT\",\"IN\",\"US\",\"JP\",\"YE\",\"GR\",\"ID\",\"UY\",\"UG\",\"UA\",\"IE\",\"IS\",\"IT\",\"PG\",\"PY\",\"PK\",\"BE\",\"BG\",\"BD\",\"PA\",\"PR\",\"PL\",\"BO\",\"PE\",\"BY\",\"TH\",\"TW\",\"TR\",\"CZ\",\"CL\",\"TZ\",\"TN\",\"JM\",\"DO\",\"ZA\",\"GE\",\"RU\",\"RO\",\"ZW\",\"LK\",\"SK\",\"SI\",\"SG\",\"CH\",\"MK\",\"RS\",\"OM\",\"GH\",\"GT\",\"FR\",\"VE\",\"FI\",\"VN\",\"CY\",\"QA\",\"KZ\",\"HR\",\"KH\",\"CA\",\"KR\",\"CR\",\"CO\",\"KE\",\"LV\",\"LA\",\"LB\",\"LU\",\"LY\",\"LT\",\"LI\",\"MT\",\"MY\",\"EG\",\"MD\",\"NP\",\"NG\",\"NI\",\"NZ\",\"HN\",\"NL\",\"HK\"]}"
  },
  {
    "path": "static/geolocations/be.json",
    "content": "{\"names\":[\"Аб’ядн. Арабскія Эміраты\",\"Азербайджан\",\"Алжыр\",\"Аман\",\"Аргенціна\",\"Аўстралія\",\"Аўстрыя\",\"Балгарыя\",\"Балівія\",\"Бангладэш\",\"Бахрэйн\",\"Беларусь\",\"Бельгія\",\"Боснія і Герцагавіна\",\"Бразілія\",\"В’етнам\",\"Венгрыя\",\"Венесуэла\",\"Вялікабрытанія\",\"Гана\",\"Гандурас\",\"Ганконг\",\"Гватэмала\",\"Германія\",\"Грузія\",\"Грэцыя\",\"Дамініканская Рэспубліка\",\"Данія\",\"Егіпет\",\"Емен\",\"Зімбабвэ\",\"Злучаныя Штаты Амерыкі\",\"Іарданія\",\"Ізраіль\",\"Інданезія\",\"Індыя\",\"Ірак\",\"Ірландыя\",\"Ісландыя\",\"Іспанія\",\"Італія\",\"Казахстан\",\"Калумбія\",\"Камбоджа\",\"Канада\",\"Катар\",\"Кенія\",\"Кіпр\",\"Коста-Рыка\",\"Кувейт\",\"Лаос\",\"Латвія\",\"Ліван\",\"Лівія\",\"Літва\",\"Ліхтэнштэйн\",\"Люксембург\",\"Малайзія\",\"Малдова\",\"Мальта\",\"Марока\",\"Мексіка\",\"Нарвегія\",\"Непал\",\"Нігерыя\",\"Нідэрланды\",\"Нікарагуа\",\"Новая Зеландыя\",\"Пакістан\",\"Панама\",\"Папуа – Новая Гвінея\",\"Парагвай\",\"Партугалія\",\"Паўднёвая Афрыка\",\"Паўднёвая Карэя\",\"Паўночная Македонія\",\"Перу\",\"Польшча\",\"Пуэрта-Рыка\",\"Расія\",\"Румынія\",\"Саудаўская Аравія\",\"Сенегал\",\"Сербія\",\"Сінгапур\",\"Славакія\",\"Славенія\",\"Тайвань\",\"Тайланд\",\"Танзанія\",\"Туніс\",\"Турцыя\",\"Уганда\",\"Украіна\",\"Уругвай\",\"Філіпіны\",\"Фінляндыя\",\"Францыя\",\"Харватыя\",\"Чарнагорыя\",\"Чылі\",\"Чэхія\",\"Швейцарыя\",\"Швецыя\",\"Шры-Ланка\",\"Эквадор\",\"Эль-Сальвадор\",\"Эстонія\",\"Ямайка\",\"Японія\"],\"codes\":[\"AE\",\"AZ\",\"DZ\",\"OM\",\"AR\",\"AU\",\"AT\",\"BG\",\"BO\",\"BD\",\"BH\",\"BY\",\"BE\",\"BA\",\"BR\",\"VN\",\"HU\",\"VE\",\"GB\",\"GH\",\"HN\",\"HK\",\"GT\",\"DE\",\"GE\",\"GR\",\"DO\",\"DK\",\"EG\",\"YE\",\"ZW\",\"US\",\"JO\",\"IL\",\"ID\",\"IN\",\"IQ\",\"IE\",\"IS\",\"ES\",\"IT\",\"KZ\",\"CO\",\"KH\",\"CA\",\"QA\",\"KE\",\"CY\",\"CR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LT\",\"LI\",\"LU\",\"MY\",\"MD\",\"MT\",\"MA\",\"MX\",\"NO\",\"NP\",\"NG\",\"NL\",\"NI\",\"NZ\",\"PK\",\"PA\",\"PG\",\"PY\",\"PT\",\"ZA\",\"KR\",\"MK\",\"PE\",\"PL\",\"PR\",\"RU\",\"RO\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"TW\",\"TH\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"PH\",\"FI\",\"FR\",\"HR\",\"ME\",\"CL\",\"CZ\",\"CH\",\"SE\",\"LK\",\"EC\",\"SV\",\"EE\",\"JM\",\"JP\"]}"
  },
  {
    "path": "static/geolocations/bg.json",
    "content": "{\"names\":[\"Австралия\",\"Австрия\",\"Азербайджан\",\"Алжир\",\"Аржентина\",\"Бангладеш\",\"Бахрейн\",\"Беларус\",\"Белгия\",\"Боливия\",\"Босна и Херцеговина\",\"Бразилия\",\"България\",\"Великобритания\",\"Венесуела\",\"Виетнам\",\"Гана\",\"Гватемала\",\"Германия\",\"Грузия\",\"Гърция\",\"Дания\",\"Доминиканска република\",\"Египет\",\"Еквадор\",\"Естония\",\"Зимбабве\",\"Израел\",\"Индия\",\"Индонезия\",\"Ирак\",\"Ирландия\",\"Исландия\",\"Испания\",\"Италия\",\"Йемен\",\"Йордания\",\"Казахстан\",\"Камбоджа\",\"Канада\",\"Катар\",\"Кения\",\"Кипър\",\"Колумбия\",\"Коста Рика\",\"Кувейт\",\"Лаос\",\"Латвия\",\"Либия\",\"Ливан\",\"Литва\",\"Лихтенщайн\",\"Люксембург\",\"Малайзия\",\"Малта\",\"Мароко\",\"Мексико\",\"Молдова\",\"Непал\",\"Нигерия\",\"Нидерландия\",\"Никарагуа\",\"Нова Зеландия\",\"Норвегия\",\"Обединени арабски емирства\",\"Оман\",\"Пакистан\",\"Панама\",\"Папуа Нова Гвинея\",\"Парагвай\",\"Перу\",\"Полша\",\"Португалия\",\"Пуерто Рико\",\"Румъния\",\"Русия\",\"Салвадор\",\"Саудитска Арабия\",\"Северна Македония\",\"Сенегал\",\"Сингапур\",\"Словакия\",\"Словения\",\"Съединени щати\",\"Сърбия\",\"Тайван\",\"Тайланд\",\"Танзания\",\"Тунис\",\"Турция\",\"Уганда\",\"Украйна\",\"Унгария\",\"Уругвай\",\"Филипини\",\"Финландия\",\"Франция\",\"Хондурас\",\"Хонконг\",\"Хърватска\",\"Черна гора\",\"Чехия\",\"Чили\",\"Швейцария\",\"Швеция\",\"Шри Ланка\",\"Южна Африка\",\"Южна Корея\",\"Ямайка\",\"Япония\"],\"codes\":[\"AU\",\"AT\",\"AZ\",\"DZ\",\"AR\",\"BD\",\"BH\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"GB\",\"VE\",\"VN\",\"GH\",\"GT\",\"DE\",\"GE\",\"GR\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"ZW\",\"IL\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"ES\",\"IT\",\"YE\",\"JO\",\"KZ\",\"KH\",\"CA\",\"QA\",\"KE\",\"CY\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LY\",\"LB\",\"LT\",\"LI\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"NG\",\"NL\",\"NI\",\"NZ\",\"NO\",\"AE\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"RO\",\"RU\",\"SV\",\"SA\",\"MK\",\"SN\",\"SG\",\"SK\",\"SI\",\"US\",\"RS\",\"TW\",\"TH\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"HU\",\"UY\",\"PH\",\"FI\",\"FR\",\"HN\",\"HK\",\"HR\",\"ME\",\"CZ\",\"CL\",\"CH\",\"SE\",\"LK\",\"ZA\",\"KR\",\"JM\",\"JP\"]}"
  },
  {
    "path": "static/geolocations/ca.json",
    "content": "{\"names\":[\"Alemanya\",\"Algèria\",\"Aràbia Saudita\",\"Argentina\",\"Austràlia\",\"Àustria\",\"Azerbaidjan\",\"Bahrain\",\"Bangladesh\",\"Belarús\",\"Bèlgica\",\"Bolívia\",\"Bòsnia i Hercegovina\",\"Brasil\",\"Bulgària\",\"Cambodja\",\"Canadà\",\"Colòmbia\",\"Corea del Sud\",\"Costa Rica\",\"Croàcia\",\"Dinamarca\",\"Egipte\",\"El Salvador\",\"Emirats Àrabs Units\",\"Equador\",\"Eslovàquia\",\"Eslovènia\",\"Espanya\",\"Estats Units\",\"Estònia\",\"Filipines\",\"Finlàndia\",\"França\",\"Geòrgia\",\"Ghana\",\"Grècia\",\"Guatemala\",\"Hondures\",\"Hong Kong\",\"Hongria\",\"Iemen\",\"Índia\",\"Indonèsia\",\"Iraq\",\"Irlanda\",\"Islàndia\",\"Israel\",\"Itàlia\",\"Jamaica\",\"Japó\",\"Jordània\",\"Kazakhstan\",\"Kenya\",\"Kuwait\",\"Lao\",\"Letònia\",\"Líban\",\"Líbia\",\"Liechtenstein\",\"Lituània\",\"Luxemburg\",\"Macedònia del Nord\",\"Malàisia\",\"Malta\",\"Marroc\",\"Mèxic\",\"Moldàvia\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigèria\",\"Noruega\",\"Nova Zelanda\",\"Oman\",\"Països Baixos\",\"Pakistan\",\"Panamà\",\"Papua Nova Guinea\",\"Paraguai\",\"Perú\",\"Polònia\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Regne Unit\",\"República Dominicana\",\"Romania\",\"Rússia\",\"Senegal\",\"Sèrbia\",\"Singapur\",\"Sri Lanka\",\"Sud-àfrica\",\"Suècia\",\"Suïssa\",\"Tailàndia\",\"Taiwan\",\"Tanzània\",\"Tunísia\",\"Turquia\",\"Txèquia\",\"Ucraïna\",\"Uganda\",\"Uruguai\",\"Veneçuela\",\"Vietnam\",\"Xile\",\"Xipre\",\"Zimbàbue\"],\"codes\":[\"DE\",\"DZ\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EG\",\"SV\",\"AE\",\"EC\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"YE\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"NL\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"ZA\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"CZ\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"CL\",\"CY\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/cs.json",
    "content": "{\"names\":[\"Alžírsko\",\"Argentina\",\"Austrálie\",\"Ázerbájdžán\",\"Bahrajn\",\"Bangladéš\",\"Belgie\",\"Bělorusko\",\"Bolívie\",\"Bosna a Hercegovina\",\"Brazílie\",\"Bulharsko\",\"Černá Hora\",\"Česko\",\"Dánsko\",\"Dominikánská republika\",\"Egypt\",\"Ekvádor\",\"Estonsko\",\"Filipíny\",\"Finsko\",\"Francie\",\"Ghana\",\"Gruzie\",\"Guatemala\",\"Honduras\",\"Hongkong\",\"Chile\",\"Chorvatsko\",\"Indie\",\"Indonésie\",\"Irák\",\"Irsko\",\"Island\",\"Itálie\",\"Izrael\",\"Jamajka\",\"Japonsko\",\"Jemen\",\"Jihoafrická republika\",\"Jižní Korea\",\"Jordánsko\",\"Kambodža\",\"Kanada\",\"Katar\",\"Kazachstán\",\"Keňa\",\"Kolumbie\",\"Kostarika\",\"Kuvajt\",\"Kypr\",\"Laos\",\"Libanon\",\"Libye\",\"Lichtenštejnsko\",\"Litva\",\"Lotyšsko\",\"Lucembursko\",\"Maďarsko\",\"Malajsie\",\"Malta\",\"Maroko\",\"Mexiko\",\"Moldavsko\",\"Německo\",\"Nepál\",\"Nigérie\",\"Nikaragua\",\"Nizozemsko\",\"Norsko\",\"Nový Zéland\",\"Omán\",\"Pákistán\",\"Panama\",\"Papua Nová Guinea\",\"Paraguay\",\"Peru\",\"Polsko\",\"Portoriko\",\"Portugalsko\",\"Rakousko\",\"Rumunsko\",\"Rusko\",\"Řecko\",\"Salvador\",\"Saúdská Arábie\",\"Senegal\",\"Severní Makedonie\",\"Singapur\",\"Slovensko\",\"Slovinsko\",\"Spojené arabské emiráty\",\"Spojené království\",\"Spojené státy\",\"Srbsko\",\"Srí Lanka\",\"Španělsko\",\"Švédsko\",\"Švýcarsko\",\"Tanzánie\",\"Thajsko\",\"Tchaj-wan\",\"Tunisko\",\"Turecko\",\"Uganda\",\"Ukrajina\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"ME\",\"CZ\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GE\",\"GT\",\"HN\",\"HK\",\"CL\",\"HR\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IT\",\"IL\",\"JM\",\"JP\",\"YE\",\"ZA\",\"KR\",\"JO\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"CR\",\"KW\",\"CY\",\"LA\",\"LB\",\"LY\",\"LI\",\"LT\",\"LV\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"DE\",\"NP\",\"NG\",\"NI\",\"NL\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"AT\",\"RO\",\"RU\",\"GR\",\"SV\",\"SA\",\"SN\",\"MK\",\"SG\",\"SK\",\"SI\",\"AE\",\"GB\",\"US\",\"RS\",\"LK\",\"ES\",\"SE\",\"CH\",\"TZ\",\"TH\",\"TW\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/da.json",
    "content": "{\"names\":[\"Algeriet\",\"Argentina\",\"Aserbajdsjan\",\"Australien\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgien\",\"Bolivia\",\"Bosnien-Hercegovina\",\"Brasilien\",\"Bulgarien\",\"Cambodja\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Cypern\",\"Danmark\",\"Den Dominikanske Republik\",\"Ecuador\",\"Egypten\",\"El Salvador\",\"Estland\",\"Filippinerne\",\"Finland\",\"Forenede Arabiske Emirater\",\"Frankrig\",\"Georgien\",\"Ghana\",\"Grækenland\",\"Guatemala\",\"Honduras\",\"Hongkong\",\"Indien\",\"Indonesien\",\"Irak\",\"Irland\",\"Island\",\"Israel\",\"Italien\",\"Jamaica\",\"Japan\",\"Jordan\",\"Kasakhstan\",\"Kenya\",\"Kroatien\",\"Kuwait\",\"Laos\",\"Letland\",\"Libanon\",\"Libyen\",\"Liechtenstein\",\"Litauen\",\"Luxembourg\",\"Malaysia\",\"Malta\",\"Marokko\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Nederlandene\",\"Nepal\",\"New Zealand\",\"Nicaragua\",\"Nigeria\",\"Norge\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Ny Guinea\",\"Paraguay\",\"Peru\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Republikken Nordmakedonien\",\"Rumænien\",\"Rusland\",\"Saudi-Arabien\",\"Schweiz\",\"Senegal\",\"Serbien\",\"Singapore\",\"Slovakiet\",\"Slovenien\",\"Spanien\",\"Sri Lanka\",\"Storbritannien og Nordirland\",\"Sverige\",\"Sydafrika\",\"Sydkorea\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tjekkiet\",\"Tunesien\",\"Tyrkiet\",\"Tyskland\",\"Uganda\",\"Ukraine\",\"Ungarn\",\"Uruguay\",\"USA\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabwe\",\"Østrig\"],\"codes\":[\"DZ\",\"AR\",\"AZ\",\"AU\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CO\",\"CR\",\"CY\",\"DK\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"PH\",\"FI\",\"AE\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"HR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NL\",\"NP\",\"NZ\",\"NI\",\"NG\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"MK\",\"RO\",\"RU\",\"SA\",\"CH\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"GB\",\"SE\",\"ZA\",\"KR\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"DE\",\"UG\",\"UA\",\"HU\",\"UY\",\"US\",\"VE\",\"VN\",\"YE\",\"ZW\",\"AT\"]}"
  },
  {
    "path": "static/geolocations/de-DE.json",
    "content": "{\"names\":[\"Ägypten\",\"Algerien\",\"Argentinien\",\"Aserbaidschan\",\"Australien\",\"Bahrain\",\"Bangladesch\",\"Belarus\",\"Belgien\",\"Bolivien\",\"Bosnien und Herzegowina\",\"Brasilien\",\"Bulgarien\",\"Chile\",\"Costa Rica\",\"Dänemark\",\"Deutschland\",\"Dominikanische Republik\",\"Ecuador\",\"El Salvador\",\"Estland\",\"Finnland\",\"Frankreich\",\"Georgien\",\"Ghana\",\"Griechenland\",\"Guatemala\",\"Honduras\",\"Hongkong\",\"Indien\",\"Indonesien\",\"Irak\",\"Irland\",\"Island\",\"Israel\",\"Italien\",\"Jamaika\",\"Japan\",\"Jemen\",\"Jordanien\",\"Kambodscha\",\"Kanada\",\"Kasachstan\",\"Katar\",\"Kenia\",\"Kolumbien\",\"Kroatien\",\"Kuwait\",\"Laos\",\"Lettland\",\"Libanon\",\"Libyen\",\"Liechtenstein\",\"Litauen\",\"Luxemburg\",\"Malaysia\",\"Malta\",\"Marokko\",\"Mexiko\",\"Montenegro\",\"Nepal\",\"Neuseeland\",\"Nicaragua\",\"Niederlande\",\"Nigeria\",\"Nordmazedonien\",\"Norwegen\",\"Oman\",\"Österreich\",\"Pakistan\",\"Panama\",\"Papua-Neuguinea\",\"Paraguay\",\"Peru\",\"Philippinen\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Republik Moldau\",\"Rumänien\",\"Russland\",\"Saudi-Arabien\",\"Schweden\",\"Schweiz\",\"Senegal\",\"Serbien\",\"Simbabwe\",\"Singapur\",\"Slowakei\",\"Slowenien\",\"Spanien\",\"Sri Lanka\",\"Südafrika\",\"Südkorea\",\"Taiwan\",\"Tansania\",\"Thailand\",\"Tschechien\",\"Tunesien\",\"Türkei\",\"Uganda\",\"Ukraine\",\"Ungarn\",\"Uruguay\",\"USA\",\"Venezuela\",\"Vereinigte Arabische Emirate\",\"Vereinigtes Königreich\",\"Vietnam\",\"Zypern\"],\"codes\":[\"EG\",\"DZ\",\"AR\",\"AZ\",\"AU\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CL\",\"CR\",\"DK\",\"DE\",\"DO\",\"EC\",\"SV\",\"EE\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"KZ\",\"QA\",\"KE\",\"CO\",\"HR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"ME\",\"NP\",\"NZ\",\"NI\",\"NL\",\"NG\",\"MK\",\"NO\",\"OM\",\"AT\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PH\",\"PL\",\"PT\",\"PR\",\"MD\",\"RO\",\"RU\",\"SA\",\"SE\",\"CH\",\"SN\",\"RS\",\"ZW\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"ZA\",\"KR\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"HU\",\"UY\",\"US\",\"VE\",\"AE\",\"GB\",\"VN\",\"CY\"]}"
  },
  {
    "path": "static/geolocations/el.json",
    "content": "{\"names\":[\"Αζερμπαϊτζάν\",\"Αίγυπτος\",\"Αλγερία\",\"Αργεντινή\",\"Αυστραλία\",\"Αυστρία\",\"Βέλγιο\",\"Βενεζουέλα\",\"Βιετνάμ\",\"Βολιβία\",\"Βόρεια Μακεδονία\",\"Βοσνία και Ερζεγοβίνη\",\"Βουλγαρία\",\"Βραζιλία\",\"Γαλλία\",\"Γερμανία\",\"Γεωργία\",\"Γκάνα\",\"Γουατεμάλα\",\"Δανία\",\"Δομινικανή Δημοκρατία\",\"Ελ Σαλβαδόρ\",\"Ελβετία\",\"Ελλάδα\",\"Εσθονία\",\"Ζιμπάμπουε\",\"Ηνωμένα Αραβικά Εμιράτα\",\"Ηνωμένες Πολιτείες\",\"Ηνωμένο Βασίλειο\",\"Ιαπωνία\",\"Ινδία\",\"Ινδονησία\",\"Ιορδανία\",\"Ιράκ\",\"Ιρλανδία\",\"Ισημερινός\",\"Ισλανδία\",\"Ισπανία\",\"Ισραήλ\",\"Ιταλία\",\"Καζακστάν\",\"Καμπότζη\",\"Καναδάς\",\"Κατάρ\",\"Κένυα\",\"Κολομβία\",\"Κόστα Ρίκα\",\"Κουβέιτ\",\"Κροατία\",\"Κύπρος\",\"Λάος\",\"Λετονία\",\"Λευκορωσία\",\"Λίβανος\",\"Λιβύη\",\"Λιθουανία\",\"Λιχτενστάιν\",\"Λουξεμβούργο\",\"Μαλαισία\",\"Μάλτα\",\"Μαρόκο\",\"Μαυροβούνιο\",\"Μεξικό\",\"Μολδαβία\",\"Μπαγκλαντές\",\"Μπαχρέιν\",\"Νέα Ζηλανδία\",\"Νεπάλ\",\"Νιγηρία\",\"Νικαράγουα\",\"Νορβηγία\",\"Νότια Αφρική\",\"Νότια Κορέα\",\"Ολλανδία\",\"Ομάν\",\"Ονδούρα\",\"Ουγγαρία\",\"Ουγκάντα\",\"Ουκρανία\",\"Ουρουγουάη\",\"Πακιστάν\",\"Παναμάς\",\"Παπούα Νέα Γουινέα\",\"Παραγουάη\",\"Περού\",\"Πολωνία\",\"Πορτογαλία\",\"Πουέρτο Ρίκο\",\"Ρουμανία\",\"Ρωσία\",\"Σαουδική Αραβία\",\"Σενεγάλη\",\"Σερβία\",\"Σιγκαπούρη\",\"Σλοβακία\",\"Σλοβενία\",\"Σουηδία\",\"Σρι Λάνκα\",\"Ταϊβάν\",\"Ταϊλάνδη\",\"Τανζανία\",\"Τζαμάικα\",\"Τουρκία\",\"Τσεχία\",\"Τυνησία\",\"Υεμένη\",\"Φιλιππίνες\",\"Φινλανδία\",\"Χιλή\",\"Χονγκ Κονγκ\"],\"codes\":[\"AZ\",\"EG\",\"DZ\",\"AR\",\"AU\",\"AT\",\"BE\",\"VE\",\"VN\",\"BO\",\"MK\",\"BA\",\"BG\",\"BR\",\"FR\",\"DE\",\"GE\",\"GH\",\"GT\",\"DK\",\"DO\",\"SV\",\"CH\",\"GR\",\"EE\",\"ZW\",\"AE\",\"US\",\"GB\",\"JP\",\"IN\",\"ID\",\"JO\",\"IQ\",\"IE\",\"EC\",\"IS\",\"ES\",\"IL\",\"IT\",\"KZ\",\"KH\",\"CA\",\"QA\",\"KE\",\"CO\",\"CR\",\"KW\",\"HR\",\"CY\",\"LA\",\"LV\",\"BY\",\"LB\",\"LY\",\"LT\",\"LI\",\"LU\",\"MY\",\"MT\",\"MA\",\"ME\",\"MX\",\"MD\",\"BD\",\"BH\",\"NZ\",\"NP\",\"NG\",\"NI\",\"NO\",\"ZA\",\"KR\",\"NL\",\"OM\",\"HN\",\"HU\",\"UG\",\"UA\",\"UY\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"SE\",\"LK\",\"TW\",\"TH\",\"TZ\",\"JM\",\"TR\",\"CZ\",\"TN\",\"YE\",\"PH\",\"FI\",\"CL\",\"HK\"]}"
  },
  {
    "path": "static/geolocations/en-GB.json",
    "content": "{\"names\":[\"Algeria\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaijan\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgium\",\"Bolivia\",\"Bosnia and Herzegovina\",\"Brazil\",\"Bulgaria\",\"Cambodia\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Croatia\",\"Cyprus\",\"Czechia\",\"Denmark\",\"Dominican Republic\",\"Ecuador\",\"Egypt\",\"El Salvador\",\"Estonia\",\"Finland\",\"France\",\"Georgia\",\"Germany\",\"Ghana\",\"Greece\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungary\",\"Iceland\",\"India\",\"Indonesia\",\"Iraq\",\"Ireland\",\"Israel\",\"Italy\",\"Jamaica\",\"Japan\",\"Jordan\",\"Kazakhstan\",\"Kenya\",\"Kuwait\",\"Laos\",\"Latvia\",\"Lebanon\",\"Libya\",\"Liechtenstein\",\"Lithuania\",\"Luxembourg\",\"Malaysia\",\"Malta\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Morocco\",\"Nepal\",\"Netherlands\",\"New Zealand\",\"Nicaragua\",\"Nigeria\",\"North Macedonia\",\"Norway\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua New Guinea\",\"Paraguay\",\"Peru\",\"Philippines\",\"Poland\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Romania\",\"Russia\",\"Saudi Arabia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"South Africa\",\"South Korea\",\"Spain\",\"Sri Lanka\",\"Sweden\",\"Switzerland\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tunisia\",\"Turkey\",\"Uganda\",\"Ukraine\",\"United Arab Emirates\",\"United Kingdom\",\"United States\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CO\",\"CR\",\"HR\",\"CY\",\"CZ\",\"DK\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"FI\",\"FR\",\"GE\",\"DE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"IS\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MX\",\"MD\",\"ME\",\"MA\",\"NP\",\"NL\",\"NZ\",\"NI\",\"NG\",\"MK\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PH\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ZA\",\"KR\",\"ES\",\"LK\",\"SE\",\"CH\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"UG\",\"UA\",\"AE\",\"GB\",\"US\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/en-US.json",
    "content": "{\"names\":[\"Algeria\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaijan\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgium\",\"Bolivia\",\"Bosnia and Herzegovina\",\"Brazil\",\"Bulgaria\",\"Cambodia\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Croatia\",\"Cyprus\",\"Czechia\",\"Denmark\",\"Dominican Republic\",\"Ecuador\",\"Egypt\",\"El Salvador\",\"Estonia\",\"Finland\",\"France\",\"Georgia\",\"Germany\",\"Ghana\",\"Greece\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungary\",\"Iceland\",\"India\",\"Indonesia\",\"Iraq\",\"Ireland\",\"Israel\",\"Italy\",\"Jamaica\",\"Japan\",\"Jordan\",\"Kazakhstan\",\"Kenya\",\"Kuwait\",\"Laos\",\"Latvia\",\"Lebanon\",\"Libya\",\"Liechtenstein\",\"Lithuania\",\"Luxembourg\",\"Malaysia\",\"Malta\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Morocco\",\"Nepal\",\"Netherlands\",\"New Zealand\",\"Nicaragua\",\"Nigeria\",\"North Macedonia\",\"Norway\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua New Guinea\",\"Paraguay\",\"Peru\",\"Philippines\",\"Poland\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Romania\",\"Russia\",\"Saudi Arabia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"South Africa\",\"South Korea\",\"Spain\",\"Sri Lanka\",\"Sweden\",\"Switzerland\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tunisia\",\"Turkey\",\"Uganda\",\"Ukraine\",\"United Arab Emirates\",\"United Kingdom\",\"United States\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CO\",\"CR\",\"HR\",\"CY\",\"CZ\",\"DK\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"FI\",\"FR\",\"GE\",\"DE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"IS\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MX\",\"MD\",\"ME\",\"MA\",\"NP\",\"NL\",\"NZ\",\"NI\",\"NG\",\"MK\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PH\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ZA\",\"KR\",\"ES\",\"LK\",\"SE\",\"CH\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"UG\",\"UA\",\"AE\",\"GB\",\"US\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/es-AR.json",
    "content": "{\"names\":[\"Alemania\",\"Arabia Saudita\",\"Argelia\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaiyán\",\"Bahrein\",\"Bangladés\",\"Bélgica\",\"Bielorrusia\",\"Bolivia\",\"Bosnia y Herzegovina\",\"Brasil\",\"Bulgaria\",\"Camboya\",\"Canadá\",\"Chile\",\"Chipre\",\"Colombia\",\"Corea del Sur\",\"Costa Rica\",\"Croacia\",\"Dinamarca\",\"Ecuador\",\"Egipto\",\"El Líbano\",\"El Salvador\",\"Emiratos Árabes Unidos\",\"Eslovaquia\",\"Eslovenia\",\"España\",\"Estados Unidos\",\"Estonia\",\"Filipinas\",\"Finlandia\",\"Francia\",\"Georgia\",\"Ghana\",\"Grecia\",\"Guatemala\",\"Holanda\",\"Honduras\",\"Hong Kong\",\"Hungría\",\"Indonesia\",\"Iraq\",\"Irlanda\",\"Islandia\",\"Israel\",\"Italia\",\"Jamaica\",\"Japón\",\"Jordania\",\"Kazajstán\",\"Kenia\",\"Kuwait\",\"La India\",\"Laos\",\"Letonia\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxemburgo\",\"Macedonia del Norte\",\"Malasia\",\"Malta\",\"Marruecos\",\"México\",\"Moldavia\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Noruega\",\"Nueva Zelanda\",\"Omán\",\"Pakistán\",\"Panamá\",\"Papúa-Nueva Guinea\",\"Paraguay\",\"Perú\",\"Polonia\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Reino Unido\",\"República Checa\",\"República Dominicana\",\"Rumania\",\"Rusia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Sri Lanka\",\"Sudáfrica\",\"Suecia\",\"Suiza\",\"Tailandia\",\"Taiwán\",\"Tanzania\",\"Túnez\",\"Türkiye\",\"Ucrania\",\"Uganda\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabue\"],\"codes\":[\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"EG\",\"LB\",\"SV\",\"AE\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"NL\",\"HN\",\"HK\",\"HU\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"IN\",\"LA\",\"LV\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"CZ\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"ZA\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/es-MX.json",
    "content": "{\"names\":[\"Alemania\",\"Arabia Saudita\",\"Argelia\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaiyán\",\"Bahrein\",\"Bangladés\",\"Bélgica\",\"Bielorrusia\",\"Bolivia\",\"Bosnia y Herzegovina\",\"Brasil\",\"Bulgaria\",\"Camboya\",\"Canadá\",\"Chile\",\"Chipre\",\"Colombia\",\"Corea del Sur\",\"Costa Rica\",\"Croacia\",\"Dinamarca\",\"Ecuador\",\"Egipto\",\"El Líbano\",\"El Salvador\",\"Emiratos Árabes Unidos\",\"Eslovaquia\",\"Eslovenia\",\"España\",\"Estados Unidos\",\"Estonia\",\"Filipinas\",\"Finlandia\",\"Francia\",\"Georgia\",\"Ghana\",\"Grecia\",\"Guatemala\",\"Holanda\",\"Honduras\",\"Hong Kong\",\"Hungría\",\"Indonesia\",\"Iraq\",\"Irlanda\",\"Islandia\",\"Israel\",\"Italia\",\"Jamaica\",\"Japón\",\"Jordania\",\"Kazajstán\",\"Kenia\",\"Kuwait\",\"La India\",\"Laos\",\"Letonia\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxemburgo\",\"Macedonia del Norte\",\"Malasia\",\"Malta\",\"Marruecos\",\"México\",\"Moldavia\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Noruega\",\"Nueva Zelanda\",\"Omán\",\"Pakistán\",\"Panamá\",\"Papúa-Nueva Guinea\",\"Paraguay\",\"Perú\",\"Polonia\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Reino Unido\",\"República Checa\",\"República Dominicana\",\"Rumania\",\"Rusia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Sri Lanka\",\"Sudáfrica\",\"Suecia\",\"Suiza\",\"Tailandia\",\"Taiwán\",\"Tanzania\",\"Túnez\",\"Türkiye\",\"Ucrania\",\"Uganda\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabue\"],\"codes\":[\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"EG\",\"LB\",\"SV\",\"AE\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"NL\",\"HN\",\"HK\",\"HU\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"IN\",\"LA\",\"LV\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"CZ\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"ZA\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/es.json",
    "content": "{\"names\":[\"Alemania\",\"Arabia Saudí\",\"Argelia\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaiyán\",\"Bangladesh\",\"Baréin\",\"Bélgica\",\"Bielorrusia\",\"Bolivia\",\"Bosnia y Herzegovina\",\"Brasil\",\"Bulgaria\",\"Camboya\",\"Canadá\",\"Chequia\",\"Chile\",\"Chipre\",\"Colombia\",\"Corea del Sur\",\"Costa Rica\",\"Croacia\",\"Dinamarca\",\"Ecuador\",\"Egipto\",\"El Líbano\",\"El Salvador\",\"Emiratos Árabes Unidos\",\"Eslovaquia\",\"Eslovenia\",\"España\",\"Estados Unidos\",\"Estonia\",\"Filipinas\",\"Finlandia\",\"Francia\",\"Georgia\",\"Ghana\",\"Grecia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungría\",\"Indonesia\",\"Iraq\",\"Irlanda\",\"Islandia\",\"Israel\",\"Italia\",\"Jamaica\",\"Japón\",\"Jordania\",\"Kazajistán\",\"Kenia\",\"Kuwait\",\"La India\",\"Laos\",\"Letonia\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxemburgo\",\"Macedonia del Norte\",\"Malasia\",\"Malta\",\"Marruecos\",\"México\",\"Moldavia\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Noruega\",\"Nueva Zelanda\",\"Omán\",\"Países Bajos\",\"Pakistán\",\"Panamá\",\"Papúa-Nueva Guinea\",\"Paraguay\",\"Perú\",\"Polonia\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Reino Unido\",\"República Dominicana\",\"Rumanía\",\"Rusia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Sri Lanka\",\"Sudáfrica\",\"Suecia\",\"Suiza\",\"Tailandia\",\"Taiwán\",\"Tanzania\",\"Túnez\",\"Turquía\",\"Ucrania\",\"Uganda\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabue\"],\"codes\":[\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BD\",\"BH\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CZ\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"EG\",\"LB\",\"SV\",\"AE\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"IN\",\"LA\",\"LV\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"NL\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"ZA\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/et.json",
    "content": "{\"names\":[\"Alžeeria\",\"Ameerika Ühendriigid\",\"Araabia Ühendemiraadid\",\"Argentiina\",\"Aserbaidžaan\",\"Austraalia\",\"Austria\",\"Bahrein\",\"Bangladesh\",\"Belgia\",\"Boliivia\",\"Bosnia ja Hertsegoviina\",\"Brasiilia\",\"Bulgaaria\",\"Costa Rica\",\"Dominikaani Vabariik\",\"Ecuador\",\"Eesti\",\"Egiptus\",\"El Salvador\",\"Filipiinid\",\"Ghana\",\"Gruusia\",\"Guatemala\",\"Hispaania\",\"Holland\",\"Honduras\",\"Hongkong\",\"Horvaatia\",\"Iirimaa\",\"Iisrael\",\"India\",\"Indoneesia\",\"Iraak\",\"Island\",\"Itaalia\",\"Jaapan\",\"Jamaica\",\"Jeemen\",\"Jordaania\",\"Kambodža\",\"Kanada\",\"Kasahstan\",\"Katar\",\"Keenia\",\"Kolumbia\",\"Kreeka\",\"Kuveit\",\"Küpros\",\"Laos\",\"Leedu\",\"Liechtenstein\",\"Liibanon\",\"Liibüa\",\"Luksemburg\",\"Lõuna-Aafrika\",\"Lõuna-Korea\",\"Läti\",\"Malaisia\",\"Malta\",\"Maroko\",\"Mehhiko\",\"Moldova\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeeria\",\"Norra\",\"Omaan\",\"Paapua Uus-Guinea\",\"Pakistan\",\"Panama\",\"Paraguay\",\"Peruu\",\"Poola\",\"Portugal\",\"Prantsusmaa\",\"Puerto Rico\",\"Põhja-Makedoonia\",\"Rootsi\",\"Rumeenia\",\"Saksamaa\",\"Saudi Araabia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Slovakkia\",\"Sloveenia\",\"Soome\",\"Sri Lanka\",\"Šveits\",\"Zimbabwe\",\"Taani\",\"Tai\",\"Taiwan\",\"Tansaania\",\"Tšehhi\",\"Tšiili\",\"Tuneesia\",\"Türgi\",\"Uganda\",\"Ukraina\",\"Ungari\",\"Uruguay\",\"Uus-Meremaa\",\"Valgevene\",\"Venemaa\",\"Venezuela\",\"Vietnam\",\"Ühendkuningriik\"],\"codes\":[\"DZ\",\"US\",\"AE\",\"AR\",\"AZ\",\"AU\",\"AT\",\"BH\",\"BD\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CR\",\"DO\",\"EC\",\"EE\",\"EG\",\"SV\",\"PH\",\"GH\",\"GE\",\"GT\",\"ES\",\"NL\",\"HN\",\"HK\",\"HR\",\"IE\",\"IL\",\"IN\",\"ID\",\"IQ\",\"IS\",\"IT\",\"JP\",\"JM\",\"YE\",\"JO\",\"KH\",\"CA\",\"KZ\",\"QA\",\"KE\",\"CO\",\"GR\",\"KW\",\"CY\",\"LA\",\"LT\",\"LI\",\"LB\",\"LY\",\"LU\",\"ZA\",\"KR\",\"LV\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"OM\",\"PG\",\"PK\",\"PA\",\"PY\",\"PE\",\"PL\",\"PT\",\"FR\",\"PR\",\"MK\",\"SE\",\"RO\",\"DE\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"FI\",\"LK\",\"CH\",\"ZW\",\"DK\",\"TH\",\"TW\",\"TZ\",\"CZ\",\"CL\",\"TN\",\"TR\",\"UG\",\"UA\",\"HU\",\"UY\",\"NZ\",\"BY\",\"RU\",\"VE\",\"VN\",\"GB\"]}"
  },
  {
    "path": "static/geolocations/eu.json",
    "content": "{\"names\":[\"Alemania\",\"Aljeria\",\"Ameriketako Estatu Batuak\",\"Arabiar Emirerri Batuak\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaijan\",\"Bahrain\",\"Bangladesh\",\"Belgika\",\"Bielorrusia\",\"Bolivia\",\"Bosnia-Herzegovina\",\"Brasil\",\"Bulgaria\",\"Costa Rica\",\"Danimarka\",\"Dominikar Errepublika\",\"Egipto\",\"Ekuador\",\"El Salvador\",\"Erresuma Batua\",\"Errumania\",\"Errusia\",\"Eslovakia\",\"Eslovenia\",\"Espainia\",\"Estonia\",\"Filipinak\",\"Finlandia\",\"Frantzia\",\"Georgia\",\"Ghana\",\"Grezia\",\"Guatemala\",\"Hego Afrika\",\"Hego Korea\",\"Herbehereak\",\"Honduras\",\"Hong Kong\",\"Hungaria\",\"India\",\"Indonesia\",\"Ipar Mazedonia\",\"Irak\",\"Irlanda\",\"Islandia\",\"Israel\",\"Italia\",\"Jamaika\",\"Japonia\",\"Jordania\",\"Kanada\",\"Kanbodia\",\"Kazakhstan\",\"Kenya\",\"Kolonbia\",\"Kroazia\",\"Kuwait\",\"Laos\",\"Letonia\",\"Libano\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxenburgo\",\"Malaysia\",\"Malta\",\"Maroko\",\"Mexiko\",\"Moldavia\",\"Montenegro\",\"Nepal\",\"Nigeria\",\"Nikaragua\",\"Norvegia\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Ginea Berria\",\"Paraguay\",\"Peru\",\"Polonia\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Saudi Arabia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Sri Lanka\",\"Suedia\",\"Suitza\",\"Taiwan\",\"Tanzania\",\"Thailandia\",\"Tunisia\",\"Turkia\",\"Txekia\",\"Txile\",\"Uganda\",\"Ukraina\",\"Uruguai\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zeelanda Berria\",\"Zimbabwe\",\"Zipre\"],\"codes\":[\"DE\",\"DZ\",\"US\",\"AE\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"CR\",\"DK\",\"DO\",\"EG\",\"EC\",\"SV\",\"GB\",\"RO\",\"RU\",\"SK\",\"SI\",\"ES\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"ZA\",\"KR\",\"NL\",\"HN\",\"HK\",\"HU\",\"IN\",\"ID\",\"MK\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"CA\",\"KH\",\"KZ\",\"KE\",\"CO\",\"HR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NG\",\"NI\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"SA\",\"SN\",\"RS\",\"SG\",\"LK\",\"SE\",\"CH\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"CZ\",\"CL\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"YE\",\"NZ\",\"ZW\",\"CY\"]}"
  },
  {
    "path": "static/geolocations/fa.json",
    "content": "{\"names\":[\"آذربایجان\",\"آرژانتین\",\"آلمان\",\"اتریش\",\"اردن\",\"اسپانیا\",\"استرالیا\",\"استونی\",\"اسرائیل\",\"اسلواکی\",\"اسلوونی\",\"افریقای جنوبی\",\"اکراین\",\"اکوادور\",\"الجزایر\",\"السالوادور\",\"امارات متحدهٔ عربی\",\"اندونزی\",\"انگلستان\",\"اوروگوئه\",\"اوگاندا\",\"ایالات متحده\",\"ایتالیا\",\"ایرلند\",\"ایسلند\",\"بحرین\",\"برزیل\",\"بلاروس\",\"بلژیک\",\"بلغارستان\",\"بنگلادش\",\"بوسنی و هرزگوین\",\"بولیوی\",\"پاپوآ گینه نو\",\"پاراگوئه\",\"پاکستان\",\"پاناما\",\"پرتغالی\",\"پرو\",\"پورتوریکو\",\"تانزانیا\",\"تایلند\",\"تایوان\",\"ترکیه\",\"تونس\",\"جامائیکا\",\"جمهوری چک\",\"جمهوری دومینیکن\",\"دانمارک\",\"روسیه\",\"رومانی\",\"زیمبابوه\",\"ژاپن\",\"سری لانکا\",\"سنگاپور\",\"سنگال\",\"سوئد\",\"سوئیس\",\"شیلی\",\"صربستان\",\"عراق\",\"عربستان سعودی\",\"عمان\",\"غنا\",\"فرانسه\",\"فنلاند\",\"فیلیپین\",\"قبرس\",\"قزاقستان\",\"قطر\",\"کاستاریکا\",\"کانادا\",\"کرواسی\",\"کرهٔ جنوبی\",\"کلمبیا\",\"کمبوجیه\",\"کنیا\",\"کویت\",\"گرجستان\",\"گواتمالا\",\"لائوس\",\"لبنان\",\"لتونی\",\"لوکزامبورگ\",\"لهستان\",\"لیبی\",\"لیتوانی\",\"لیختن اشتاین\",\"مالت\",\"مالزی\",\"مجارستان\",\"مراکش\",\"مصر\",\"مقدونیه شمالی\",\"مکزیک\",\"مولداوی\",\"مونته‌نگرو\",\"نپال\",\"نروژ\",\"نیجریه\",\"نیکاراگوئه\",\"نیوزلند\",\"ونزوئلا\",\"ویتنام\",\"هلند\",\"هند\",\"هندوراس\",\"هنگ کنگ\",\"یمن\",\"یونان\"],\"codes\":[\"AZ\",\"AR\",\"DE\",\"AT\",\"JO\",\"ES\",\"AU\",\"EE\",\"IL\",\"SK\",\"SI\",\"ZA\",\"UA\",\"EC\",\"DZ\",\"SV\",\"AE\",\"ID\",\"GB\",\"UY\",\"UG\",\"US\",\"IT\",\"IE\",\"IS\",\"BH\",\"BR\",\"BY\",\"BE\",\"BG\",\"BD\",\"BA\",\"BO\",\"PG\",\"PY\",\"PK\",\"PA\",\"PT\",\"PE\",\"PR\",\"TZ\",\"TH\",\"TW\",\"TR\",\"TN\",\"JM\",\"CZ\",\"DO\",\"DK\",\"RU\",\"RO\",\"ZW\",\"JP\",\"LK\",\"SG\",\"SN\",\"SE\",\"CH\",\"CL\",\"RS\",\"IQ\",\"SA\",\"OM\",\"GH\",\"FR\",\"FI\",\"PH\",\"CY\",\"KZ\",\"QA\",\"CR\",\"CA\",\"HR\",\"KR\",\"CO\",\"KH\",\"KE\",\"KW\",\"GE\",\"GT\",\"LA\",\"LB\",\"LV\",\"LU\",\"PL\",\"LY\",\"LT\",\"LI\",\"MT\",\"MY\",\"HU\",\"MA\",\"EG\",\"MK\",\"MX\",\"MD\",\"ME\",\"NP\",\"NO\",\"NG\",\"NI\",\"NZ\",\"VE\",\"VN\",\"NL\",\"IN\",\"HN\",\"HK\",\"YE\",\"GR\"]}"
  },
  {
    "path": "static/geolocations/fi.json",
    "content": "{\"names\":[\"Alankomaat\",\"Algeria\",\"Arabiemiirikunnat\",\"Argentiina\",\"Australia\",\"Azerbaidžan\",\"Bahrain\",\"Bangladesh\",\"Belgia\",\"Bolivia\",\"Bosnia ja Hertsegovina\",\"Brasilia\",\"Bulgaria\",\"Chile\",\"Costa Rica\",\"Dominikaaninen tasavalta\",\"Ecuador\",\"Egypti\",\"El Salvador\",\"Espanja\",\"Etelä-Afrikka\",\"Etelä-Korea\",\"Filippiinit\",\"Georgia\",\"Ghana\",\"Guatemala\",\"Honduras\",\"Hongkong\",\"Indonesia\",\"Intia\",\"Irak\",\"Irlanti\",\"Islanti\",\"Israel\",\"Italia\",\"Itävalta\",\"Jamaika\",\"Japani\",\"Jemen\",\"Jordania\",\"Kambodža\",\"Kanada\",\"Kazakstan\",\"Kenia\",\"Kolumbia\",\"Kreikka\",\"Kroatia\",\"Kuwait\",\"Kypros\",\"Laos\",\"Latvia\",\"Libanon\",\"Libya\",\"Liechtenstein\",\"Liettua\",\"Luxemburg\",\"Malesia\",\"Malta\",\"Marokko\",\"Meksiko\",\"Moldova\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Norja\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua-Uusi-Guinea\",\"Paraguay\",\"Peru\",\"Pohjois-Makedonia\",\"Portugali\",\"Puerto Rico\",\"Puola\",\"Qatar\",\"Ranska\",\"Romania\",\"Ruotsi\",\"Saksa\",\"Saudi-Arabia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"Sri Lanka\",\"Suomi\",\"Sveitsi\",\"Taiwan\",\"Tansania\",\"Tanska\",\"Thaimaa\",\"Tšekki\",\"Tunisia\",\"Turkki\",\"Uganda\",\"Ukraina\",\"Unkari\",\"Uruguay\",\"Uusi-Seelanti\",\"Valko-Venäjä\",\"Venezuela\",\"Venäjä\",\"Vietnam\",\"Viro\",\"Yhdistynyt kuningaskunta\",\"Yhdysvallat\",\"Zimbabwe\"],\"codes\":[\"NL\",\"DZ\",\"AE\",\"AR\",\"AU\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CL\",\"CR\",\"DO\",\"EC\",\"EG\",\"SV\",\"ES\",\"ZA\",\"KR\",\"PH\",\"GE\",\"GH\",\"GT\",\"HN\",\"HK\",\"ID\",\"IN\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"AT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"KZ\",\"KE\",\"CO\",\"GR\",\"HR\",\"KW\",\"CY\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"MK\",\"PT\",\"PR\",\"PL\",\"QA\",\"FR\",\"RO\",\"SE\",\"DE\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"LK\",\"FI\",\"CH\",\"TW\",\"TZ\",\"DK\",\"TH\",\"CZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"HU\",\"UY\",\"NZ\",\"BY\",\"VE\",\"RU\",\"VN\",\"EE\",\"GB\",\"US\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/fr-FR.json",
    "content": "{\"names\":[\"Afrique du Sud\",\"Algérie\",\"Allemagne\",\"Arabie saoudite\",\"Argentine\",\"Australie\",\"Autriche\",\"Azerbaïdjan\",\"Bahreïn\",\"Bangladesh\",\"Belgique\",\"Biélorussie\",\"Bolivie\",\"Bosnie-Herzégovine\",\"Brésil\",\"Bulgarie\",\"Cambodge\",\"Canada\",\"Chili\",\"Chypre\",\"Colombie\",\"Corée du Sud\",\"Costa Rica\",\"Croatie\",\"Danemark\",\"Égypte\",\"Émirats Arabes Unis\",\"Équateur\",\"Espagne\",\"Estonie\",\"États-Unis\",\"Finlande\",\"France\",\"Georgia\",\"Ghana\",\"Grèce\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hongrie\",\"Inde\",\"Indonésie\",\"Irak\",\"Irlande\",\"Islande\",\"Israël\",\"Italie\",\"Jamaïque\",\"Japon\",\"Jordanie\",\"Kazakhstan\",\"Kenya\",\"Koweït\",\"Laos\",\"Lettonie\",\"Liban\",\"Libye\",\"Liechtenstein\",\"Lituanie\",\"Luxembourg\",\"Macédoine du Nord\",\"Malaisie\",\"Malte\",\"Maroc\",\"Mexique\",\"Moldavie\",\"Monténégro\",\"Népal\",\"Nicaragua\",\"Nigeria\",\"Norvège\",\"Nouvelle-Zélande\",\"Oman\",\"Ouganda\",\"Pakistan\",\"Panama\",\"Papouasie-Nouvelle Guinée\",\"Paraguay\",\"Pays-Bas\",\"Pérou\",\"Philippines\",\"Pologne\",\"Porto Rico\",\"Portugal\",\"Qatar\",\"République Dominicaine\",\"Roumanie\",\"Royaume-Uni\",\"Russie\",\"Salvador\",\"Sénégal\",\"Serbie\",\"Singapour\",\"Slovaquie\",\"Slovénie\",\"Sri Lanka\",\"Suède\",\"Suisse\",\"Taïwan\",\"Tanzanie\",\"Tchéquie\",\"Thaïlande\",\"Tunisie\",\"Turquie\",\"Ukraine\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yémen\",\"Zimbabwe\"],\"codes\":[\"ZA\",\"DZ\",\"DE\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EG\",\"AE\",\"EC\",\"ES\",\"EE\",\"US\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"UG\",\"PK\",\"PA\",\"PG\",\"PY\",\"NL\",\"PE\",\"PH\",\"PL\",\"PR\",\"PT\",\"QA\",\"DO\",\"RO\",\"GB\",\"RU\",\"SV\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"LK\",\"SE\",\"CH\",\"TW\",\"TZ\",\"CZ\",\"TH\",\"TN\",\"TR\",\"UA\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/gl.json",
    "content": "{\"names\":[\"Acerbaixán\",\"Alemaña\",\"Alxeria\",\"Arabia Saudita\",\"Arxentina\",\"Australia\",\"Austria\",\"Bahrein\",\"Bangladesh\",\"Bélxica\",\"Bielorrusia\",\"Bolivia\",\"Bosnia e Herzegovina\",\"Brasil\",\"Bulgaria\",\"Camboxa\",\"Canadá\",\"Casaquistán\",\"Chequia\",\"Chile\",\"Chipre\",\"Cimbabue\",\"Colombia\",\"Corea do Sur\",\"Costa Rica\",\"Croacia\",\"Dinamarca\",\"Ecuador\",\"Emiratos Árabes Unidos\",\"Eslovaquia\",\"Eslovenia\",\"España\",\"Estados Unidos\",\"Estonia\",\"Exipto\",\"Filipinas\",\"Finlandia\",\"Francia\",\"Ghana\",\"Grecia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungría\",\"Iemen\",\"India\",\"Indonesia\",\"Iraq\",\"Irlanda\",\"Islandia\",\"Israel\",\"Italia\",\"Kenya\",\"Kuwait\",\"Laos\",\"Letonia\",\"Líbano\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxemburgo\",\"Macedonia do Norte\",\"Malaisia\",\"Malta\",\"Marrocos\",\"México\",\"Moldova\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nixeria\",\"Noruega\",\"Nova Zelandia\",\"O Salvador\",\"Omán\",\"Países Baixos\",\"Panamá\",\"Papúa Nova Guinea\",\"Paquistán\",\"Paraguai\",\"Perú\",\"Polonia\",\"Porto Rico\",\"Portugal\",\"Qatar\",\"Reino Unido\",\"República Dominicana\",\"Romanía\",\"Rusia\",\"Senegal\",\"Serbia\",\"Singapur\",\"Sri Lanka\",\"Sudáfrica\",\"Suecia\",\"Suíza\",\"Tailandia\",\"Taiwán\",\"Tanzania\",\"Tunisia\",\"Turquía\",\"Ucraína\",\"Uganda\",\"Uruguai\",\"Venezuela\",\"Vietnam\",\"Xamaica\",\"Xapón\",\"Xeorxia\",\"Xordania\"],\"codes\":[\"AZ\",\"DE\",\"DZ\",\"SA\",\"AR\",\"AU\",\"AT\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"KZ\",\"CZ\",\"CL\",\"CY\",\"ZW\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"AE\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"EG\",\"PH\",\"FI\",\"FR\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"YE\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"SV\",\"OM\",\"NL\",\"PA\",\"PG\",\"PK\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"QA\",\"GB\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"ZA\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"JM\",\"JP\",\"GE\",\"JO\"]}"
  },
  {
    "path": "static/geolocations/he.json",
    "content": "{\"names\":[\"אוגנדה\",\"אוסטריה\",\"אוסטרליה\",\"אוקראינה\",\"אורוגוואי\",\"אזרביג'ן\",\"איחוד האמירויות הערביות\",\"איטליה\",\"אינדונזיה\",\"איסלנד\",\"אירלנד\",\"אל סלבדור\",\"אלג'יריה\",\"אסטוניה\",\"אקוודור\",\"ארגנטינה\",\"ארצות הברית\",\"בולגריה\",\"בוליביה\",\"בוסניה והרצוגובינה\",\"בחריין\",\"בלגיה\",\"בלרוס\",\"בנגלדש\",\"ברזיל\",\"בריטניה\",\"ג'מייקה\",\"גאנה\",\"גווטמלה\",\"גיאורגיה\",\"גרמניה\",\"דנמרק\",\"דרום אפריקה\",\"דרום קוריאה\",\"הודו\",\"הולנד\",\"הונג קונג\",\"הונגריה\",\"הונדורס\",\"הפיליפינים\",\"הרפובליקה הדומיניקנית\",\"וייטנאם\",\"ונצואלה\",\"זימבבואה\",\"טורקיה\",\"טייוואן\",\"טנזניה\",\"יוון\",\"יפן\",\"ירדן\",\"ישראל\",\"כוויית\",\"לאוס\",\"לבנון\",\"לוב\",\"לוקסמבורג\",\"לטביה\",\"ליטא\",\"ליכטנשטיין\",\"מולדובה\",\"מונטנגרו\",\"מלזיה\",\"מלטה\",\"מצרים\",\"מקדוניה הצפונית\",\"מקסיקו\",\"מרוקו\",\"נורווגיה\",\"ניגריה\",\"ניו זילנד\",\"ניקרגואה\",\"נפאל\",\"סינגפור\",\"סלובניה\",\"סלובקיה\",\"סנגל\",\"ספרד\",\"סרביה\",\"סרי לנקה\",\"עומאן\",\"עירק\",\"ערב הסעודית\",\"פוארטו ריקו\",\"פולין\",\"פורטוגל\",\"פינלנד\",\"פנמה\",\"פפואה גיניאה החדשה\",\"פקיסטן\",\"פרגוואי\",\"פרו\",\"צ'ילה\",\"צ'כיה\",\"צרפת\",\"קולומביה\",\"קוסטה ריקה\",\"קזחסטן\",\"קטאר\",\"קמבודיה\",\"קנדה\",\"קניה\",\"קפריסין\",\"קרואטיה\",\"רומניה\",\"רוסיה\",\"שוודיה\",\"שווייץ\",\"תאילנד\",\"תוניסיה\",\"תימן\"],\"codes\":[\"UG\",\"AT\",\"AU\",\"UA\",\"UY\",\"AZ\",\"AE\",\"IT\",\"ID\",\"IS\",\"IE\",\"SV\",\"DZ\",\"EE\",\"EC\",\"AR\",\"US\",\"BG\",\"BO\",\"BA\",\"BH\",\"BE\",\"BY\",\"BD\",\"BR\",\"GB\",\"JM\",\"GH\",\"GT\",\"GE\",\"DE\",\"DK\",\"ZA\",\"KR\",\"IN\",\"NL\",\"HK\",\"HU\",\"HN\",\"PH\",\"DO\",\"VN\",\"VE\",\"ZW\",\"TR\",\"TW\",\"TZ\",\"GR\",\"JP\",\"JO\",\"IL\",\"KW\",\"LA\",\"LB\",\"LY\",\"LU\",\"LV\",\"LT\",\"LI\",\"MD\",\"ME\",\"MY\",\"MT\",\"EG\",\"MK\",\"MX\",\"MA\",\"NO\",\"NG\",\"NZ\",\"NI\",\"NP\",\"SG\",\"SI\",\"SK\",\"SN\",\"ES\",\"RS\",\"LK\",\"OM\",\"IQ\",\"SA\",\"PR\",\"PL\",\"PT\",\"FI\",\"PA\",\"PG\",\"PK\",\"PY\",\"PE\",\"CL\",\"CZ\",\"FR\",\"CO\",\"CR\",\"KZ\",\"QA\",\"KH\",\"CA\",\"KE\",\"CY\",\"HR\",\"RO\",\"RU\",\"SE\",\"CH\",\"TH\",\"TN\",\"YE\"]}"
  },
  {
    "path": "static/geolocations/hr.json",
    "content": "{\"names\":[\"Alžir\",\"Argentina\",\"Australija\",\"Austrija\",\"Azerbajdžan\",\"Bahrein\",\"Bangladeš\",\"Belgija\",\"Bjelorusija\",\"Bolivija\",\"Bosna i Hercegovina\",\"Brazil\",\"Bugarska\",\"Cipar\",\"Crna Gora\",\"Češka\",\"Čile\",\"Danska\",\"Dominikanska Republika\",\"Egipat\",\"Ekvador\",\"Estonija\",\"Filipini\",\"Finska\",\"Francuska\",\"Gana\",\"Grčka\",\"Gruzija\",\"Gvatemala\",\"Honduras\",\"Hong Kong\",\"Hrvatska\",\"Indija\",\"Indonezija\",\"Irak\",\"Irska\",\"Island\",\"Italija\",\"Izrael\",\"Jamajka\",\"Japan\",\"Jemen\",\"Jordan\",\"Južna Afrika\",\"Južna Koreja\",\"Kambodža\",\"Kanada\",\"Katar\",\"Kazahstan\",\"Kenija\",\"Kolumbija\",\"Kostarika\",\"Kuvajt\",\"Laos\",\"Latvija\",\"Libanon\",\"Libija\",\"Lihtenštajn\",\"Litva\",\"Luksemburg\",\"Mađarska\",\"Malezija\",\"Malta\",\"Maroko\",\"Meksiko\",\"Moldavija\",\"Nepal\",\"Nigerija\",\"Nikaragva\",\"Nizozemska\",\"Norveška\",\"Novi Zeland\",\"Njemačka\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Nova Gvineja\",\"Paragvaj\",\"Peru\",\"Poljska\",\"Portoriko\",\"Portugal\",\"Rumunjska\",\"Rusija\",\"Salvador\",\"Saudijska Arabija\",\"Senegal\",\"Singapur\",\"Sjedinjene Američke Države\",\"Sjeverna Makedonija\",\"Slovačka\",\"Slovenija\",\"Srbija\",\"Španjolska\",\"Šri Lanka\",\"Švedska\",\"Švicarska\",\"Tajland\",\"Tajvan\",\"Tanzanija\",\"Tunis\",\"Turska\",\"Uganda\",\"Ujedinjeni Arapski Emirati\",\"Ujedinjeno Kraljevstvo\",\"Ukrajina\",\"Urugvaj\",\"Venezuela\",\"Vijetnam\",\"Zimbabve\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"CY\",\"ME\",\"CZ\",\"CL\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GR\",\"GE\",\"GT\",\"HN\",\"HK\",\"HR\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IT\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"ZA\",\"KR\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"NG\",\"NI\",\"NL\",\"NO\",\"NZ\",\"DE\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"RO\",\"RU\",\"SV\",\"SA\",\"SN\",\"SG\",\"US\",\"MK\",\"SK\",\"SI\",\"RS\",\"ES\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"AE\",\"GB\",\"UA\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/hu.json",
    "content": "{\"names\":[\"Algéria\",\"Argentína\",\"Ausztrália\",\"Ausztria\",\"Azerbajdzsán\",\"Bahrein\",\"Banglades\",\"Belarusz\",\"Belgium\",\"Bolívia\",\"Bosznia és Hercegovina\",\"Brazília\",\"Bulgária\",\"Chile\",\"Ciprus\",\"Costa Rica\",\"Csehország\",\"Dánia\",\"Dél-Afrika\",\"Dél-Korea\",\"Dominikai Köztársaság\",\"Ecuador\",\"Egyesült Államok\",\"Egyesült Arab Emírségek\",\"Egyesült Királyság\",\"Egyiptom\",\"El Salvador\",\"Észak-Macedónia\",\"Észtország\",\"Finnország\",\"Franciaország\",\"Fülöp-szigetek\",\"Ghána\",\"Görögország\",\"Grúzia\",\"Guatemala\",\"Hollandia\",\"Honduras\",\"Hongkong\",\"Horvátország\",\"India\",\"Indonézia\",\"Irak\",\"Írország\",\"Izland\",\"Izrael\",\"Jamaica\",\"Japán\",\"Jemen\",\"Jordánia\",\"Kambodzsa\",\"Kanada\",\"Katar\",\"Kazahsztán\",\"Kenya\",\"Kolumbia\",\"Kuvait\",\"Laosz\",\"Lengyelország\",\"Lettország\",\"Libanon\",\"Líbia\",\"Liechtenstein\",\"Litvánia\",\"Luxemburg\",\"Magyarország\",\"Malajzia\",\"Málta\",\"Marokkó\",\"Mexikó\",\"Moldova\",\"Montenegró\",\"Németország\",\"Nepál\",\"Nicaragua\",\"Nigéria\",\"Norvégia\",\"Olaszország\",\"Omán\",\"Oroszország\",\"Pakisztán\",\"Panama\",\"Pápua Új-Guinea\",\"Paraguay\",\"Peru\",\"Portugália\",\"Puerto Rico\",\"Románia\",\"Spanyolország\",\"Srí Lanka\",\"Svájc\",\"Svédország\",\"Szaúd-Arábia\",\"Szenegál\",\"Szerbia\",\"Szingapúr\",\"Szlovákia\",\"Szlovénia\",\"Tajvan\",\"Tanzánia\",\"Thaiföld\",\"Törökország\",\"Tunézia\",\"Uganda\",\"Új-Zéland\",\"Ukrajna\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CL\",\"CY\",\"CR\",\"CZ\",\"DK\",\"ZA\",\"KR\",\"DO\",\"EC\",\"US\",\"AE\",\"GB\",\"EG\",\"SV\",\"MK\",\"EE\",\"FI\",\"FR\",\"PH\",\"GH\",\"GR\",\"GE\",\"GT\",\"NL\",\"HN\",\"HK\",\"HR\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"KW\",\"LA\",\"PL\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"DE\",\"NP\",\"NI\",\"NG\",\"NO\",\"IT\",\"OM\",\"RU\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PT\",\"PR\",\"RO\",\"ES\",\"LK\",\"CH\",\"SE\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"TW\",\"TZ\",\"TH\",\"TR\",\"TN\",\"UG\",\"NZ\",\"UA\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/id.json",
    "content": "{\"names\":[\"Afrika Selatan\",\"Aljazair\",\"Amerika Serikat\",\"Arab Saudi\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaijan\",\"Bahrain\",\"Bangladesh\",\"Belanda\",\"Belarus\",\"Belgia\",\"Bolivia\",\"Bosnia dan Herzegovina\",\"Brasil\",\"Bulgaria\",\"Ceko\",\"Cile\",\"Costa Rica\",\"Denmark\",\"Ekuador\",\"El Salvador\",\"Estonia\",\"Filipina\",\"Finlandia\",\"Georgia\",\"Ghana\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungaria\",\"India\",\"Indonesia\",\"Inggris\",\"Irak\",\"Irlandia\",\"Islandia\",\"Israel\",\"Italia\",\"Jamaika\",\"Jepang\",\"Jerman\",\"Kamboja\",\"Kanada\",\"Kazakhstan\",\"Kenya\",\"Kolombia\",\"Korea Selatan\",\"Kroasia\",\"Kuwait\",\"Laos\",\"Latvia\",\"Lebanon\",\"Libya\",\"Liechtenstein\",\"Lituania\",\"Luksemburg\",\"Makedonia Utara\",\"Malaysia\",\"Malta\",\"Maroko\",\"Meksiko\",\"Mesir\",\"Moldova\",\"Montenegro\",\"Nepal\",\"Nigeria\",\"Nikaragua\",\"Norwegia\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Nugini\",\"Paraguay\",\"Peru\",\"Polandia\",\"Portugal\",\"Prancis\",\"Puerto Riko\",\"Qatar\",\"Republik Dominika\",\"Rumania\",\"Rusia\",\"Selandia Baru\",\"Senegal\",\"Serbia\",\"Singapura\",\"Siprus\",\"Slovakia\",\"Slovenia\",\"Spanyol\",\"Sri Lanka\",\"Swedia\",\"Swiss\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tunisia\",\"Turki\",\"Uganda\",\"Ukraina\",\"Uni Emirat Arab\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yaman\",\"Yordania\",\"Yunani\",\"Zimbabwe\"],\"codes\":[\"ZA\",\"DZ\",\"US\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"NL\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CZ\",\"CL\",\"CR\",\"DK\",\"EC\",\"SV\",\"EE\",\"PH\",\"FI\",\"GE\",\"GH\",\"GT\",\"HN\",\"HK\",\"HU\",\"IN\",\"ID\",\"GB\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"DE\",\"KH\",\"CA\",\"KZ\",\"KE\",\"CO\",\"KR\",\"HR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"EG\",\"MD\",\"ME\",\"NP\",\"NG\",\"NI\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"FR\",\"PR\",\"QA\",\"DO\",\"RO\",\"RU\",\"NZ\",\"SN\",\"RS\",\"SG\",\"CY\",\"SK\",\"SI\",\"ES\",\"LK\",\"SE\",\"CH\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"UG\",\"UA\",\"AE\",\"UY\",\"VE\",\"VN\",\"YE\",\"JO\",\"GR\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/is.json",
    "content": "{\"names\":[\"Alsír\",\"Argentína\",\"Aserbaídsjan\",\"Austurríki\",\"Ástralía\",\"Bandaríkin\",\"Bangladess\",\"Barein\",\"Belgía\",\"Bosnía og Hersegóvína\",\"Bólivía\",\"Brasilía\",\"Bretland\",\"Búlgaría\",\"Danmörk\",\"Dóminíska lýðveldið\",\"Egyptaland\",\"Eistland\",\"Ekvador\",\"El Salvador\",\"Filippseyjar\",\"Finnland\",\"Frakkland\",\"Gana\",\"Georgía\",\"Grikkland\",\"Gvatemala\",\"Holland\",\"Hondúras\",\"Hong Kong\",\"Hvíta-Rússland\",\"Indland\",\"Indónesía\",\"Írak\",\"Írland\",\"Ísland\",\"Ísrael\",\"Ítalía\",\"Jamaíka\",\"Japan\",\"Jemen\",\"Jórdanía\",\"Kambódía\",\"Kanada\",\"Kasakstan\",\"Katar\",\"Kenía\",\"Kosta Ríka\",\"Kólumbía\",\"Króatía\",\"Kúveit\",\"Kýpur\",\"Laos\",\"Lettland\",\"Liechtenstein\",\"Litháen\",\"Líbanon\",\"Líbía\",\"Lúxemborg\",\"Malasía\",\"Malta\",\"Marokkó\",\"Mexíkó\",\"Moldóva\",\"Nepal\",\"Nígería\",\"Níkaragva\",\"Norður-Makedónía\",\"Noregur\",\"Nýja-Sjáland\",\"Óman\",\"Pakistan\",\"Panama\",\"Papúa Nýja-Gínea\",\"Paragvæ\",\"Perú\",\"Portúgal\",\"Pólland\",\"Púertó Ríkó\",\"Rúmenía\",\"Rússland\",\"Sameinuðu arabísku furstadæmin\",\"Sádi-Arabía\",\"Senegal\",\"Serbía\",\"Simbabve\",\"Singapúr\",\"Síle\",\"Slóvakía\",\"Slóvenía\",\"Spánn\",\"Srí Lanka\",\"Suður-Afríka\",\"Suður-Kórea\",\"Svartfjallaland\",\"Sviss\",\"Svíþjóð\",\"Taívan\",\"Tansanía\",\"Tékkland\",\"Túnis\",\"Tyrkland\",\"Tæland\",\"Ungverjaland\",\"Úganda\",\"Úkraína\",\"Úrúgvæ\",\"Venesúela\",\"Víetnam\",\"Þýskaland\"],\"codes\":[\"DZ\",\"AR\",\"AZ\",\"AT\",\"AU\",\"US\",\"BD\",\"BH\",\"BE\",\"BA\",\"BO\",\"BR\",\"GB\",\"BG\",\"DK\",\"DO\",\"EG\",\"EE\",\"EC\",\"SV\",\"PH\",\"FI\",\"FR\",\"GH\",\"GE\",\"GR\",\"GT\",\"NL\",\"HN\",\"HK\",\"BY\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"KZ\",\"QA\",\"KE\",\"CR\",\"CO\",\"HR\",\"KW\",\"CY\",\"LA\",\"LV\",\"LI\",\"LT\",\"LB\",\"LY\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"NG\",\"NI\",\"MK\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PT\",\"PL\",\"PR\",\"RO\",\"RU\",\"AE\",\"SA\",\"SN\",\"RS\",\"ZW\",\"SG\",\"CL\",\"SK\",\"SI\",\"ES\",\"LK\",\"ZA\",\"KR\",\"ME\",\"CH\",\"SE\",\"TW\",\"TZ\",\"CZ\",\"TN\",\"TR\",\"TH\",\"HU\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"DE\"]}"
  },
  {
    "path": "static/geolocations/it.json",
    "content": "{\"names\":[\"Algeria\",\"Arabia Saudita\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaigian\",\"Bahrein\",\"Bangladesh\",\"Belgio\",\"Bielorussia\",\"Bolivia\",\"Bosnia-Erzegovina\",\"Brasile\",\"Bulgaria\",\"Cambogia\",\"Canada\",\"Cile\",\"Cipro\",\"Colombia\",\"Corea del Sud\",\"Costa Rica\",\"Croazia\",\"Danimarca\",\"Ecuador\",\"Egitto\",\"El Salvador\",\"Emirati Arabi Uniti\",\"Estonia\",\"Filippine\",\"Finlandia\",\"Francia\",\"Georgia\",\"Germania\",\"Ghana\",\"Giamaica\",\"Giappone\",\"Giordania\",\"Grecia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"India\",\"Indonesia\",\"Iraq\",\"Irlanda\",\"Islanda\",\"Israele\",\"Italia\",\"Kazakistan\",\"Kenya\",\"Kuwait\",\"Laos\",\"Lettonia\",\"Libano\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Lussemburgo\",\"Macedonia del Nord\",\"Malesia\",\"Malta\",\"Marocco\",\"Messico\",\"Moldavia\",\"Montenegro\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Norvegia\",\"Nuova Zelanda\",\"Oman\",\"Paesi Bassi\",\"Pakistan\",\"Panama\",\"Papua Nuova Guinea\",\"Paraguay\",\"Perù\",\"Polonia\",\"Portogallo\",\"Portorico\",\"Qatar\",\"Regno Unito\",\"Repubblica Ceca\",\"Repubblica Dominicana\",\"Romania\",\"Russia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovacchia\",\"Slovenia\",\"Spagna\",\"Sri Lanka\",\"Stati Uniti\",\"Sudafrica\",\"Svezia\",\"Svizzera\",\"Taiwan\",\"Tanzania\",\"Thailandia\",\"Tunisia\",\"Turchia\",\"Ucraina\",\"Uganda\",\"Ungheria\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"EG\",\"SV\",\"AE\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"DE\",\"GH\",\"JM\",\"JP\",\"JO\",\"GR\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"NL\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"CZ\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"US\",\"ZA\",\"SE\",\"CH\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"UA\",\"UG\",\"HU\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/ja.json",
    "content": "{\"names\":[\"アイスランド\",\"アイルランド\",\"アゼルバイジャン\",\"アメリカ\",\"アラブ首長国連邦\",\"アルジェリア\",\"アルゼンチン\",\"イエメン\",\"イギリス\",\"イスラエル\",\"イタリア\",\"イラク\",\"インド\",\"インドネシア\",\"ウガンダ\",\"ウクライナ\",\"ウルグアイ共和国\",\"エクアドル共和国\",\"エジプト\",\"エストニア\",\"エルサルバドル共和国\",\"オーストラリア\",\"オーストリア\",\"オマーン\",\"オランダ\",\"ガーナ\",\"カザフスタン\",\"カタール\",\"カナダ\",\"カンボジア国\",\"キプロス共和国\",\"ギリシャ\",\"グァテマラ共和国\",\"クウェート\",\"クロアチア\",\"ケニア\",\"コスタリカ共和国\",\"コロンビア\",\"サウジアラビア\",\"ジャマイカ\",\"ジョージア\",\"シンガポール\",\"ジンバブエ\",\"スイス\",\"スウェーデン\",\"スペイン\",\"スリランカ\",\"スロバキア\",\"スロベニア\",\"セネガル\",\"セルビア\",\"タイ\",\"タンザニア\",\"チェコ\",\"チュニジア\",\"チリ\",\"デンマーク\",\"ドイツ\",\"ドミニカ共和国\",\"トルコ\",\"ナイジェリア\",\"ニカラグア共和国\",\"ニュージーランド\",\"ネパール\",\"ノルウェー\",\"バーレーン\",\"パキスタン\",\"パナマ共和国\",\"パプア　ニューギニア\",\"パラグアイ共和国\",\"ハンガリー\",\"バングラディッシュ人民共和国\",\"フィリピン\",\"フィンランド\",\"プエルトリコ\",\"ブラジル\",\"フランス\",\"ブルガリア\",\"ベトナム\",\"ベネズエラ共和国\",\"ベラルーシ\",\"ペルー\",\"ベルギー\",\"ポーランド\",\"ボスニア ヘルツェゴビナ\",\"ボリビア共和国\",\"ポルトガル\",\"ホンジュラス共和国\",\"マルタ\",\"マレーシア\",\"メキシコ\",\"モルドバ共和国\",\"モロッコ\",\"モンテネグロ\",\"ヨルダン\",\"ラオス\",\"ラトビア\",\"リトアニア\",\"リビア\",\"リヒテンシュタイン公国\",\"ルーマニア\",\"ルクセンブルグ\",\"レバノン\",\"ロシア\",\"韓国\",\"香港\",\"台湾\",\"南アフリカ\",\"日本\",\"北マケドニア\"],\"codes\":[\"IS\",\"IE\",\"AZ\",\"US\",\"AE\",\"DZ\",\"AR\",\"YE\",\"GB\",\"IL\",\"IT\",\"IQ\",\"IN\",\"ID\",\"UG\",\"UA\",\"UY\",\"EC\",\"EG\",\"EE\",\"SV\",\"AU\",\"AT\",\"OM\",\"NL\",\"GH\",\"KZ\",\"QA\",\"CA\",\"KH\",\"CY\",\"GR\",\"GT\",\"KW\",\"HR\",\"KE\",\"CR\",\"CO\",\"SA\",\"JM\",\"GE\",\"SG\",\"ZW\",\"CH\",\"SE\",\"ES\",\"LK\",\"SK\",\"SI\",\"SN\",\"RS\",\"TH\",\"TZ\",\"CZ\",\"TN\",\"CL\",\"DK\",\"DE\",\"DO\",\"TR\",\"NG\",\"NI\",\"NZ\",\"NP\",\"NO\",\"BH\",\"PK\",\"PA\",\"PG\",\"PY\",\"HU\",\"BD\",\"PH\",\"FI\",\"PR\",\"BR\",\"FR\",\"BG\",\"VN\",\"VE\",\"BY\",\"PE\",\"BE\",\"PL\",\"BA\",\"BO\",\"PT\",\"HN\",\"MT\",\"MY\",\"MX\",\"MD\",\"MA\",\"ME\",\"JO\",\"LA\",\"LV\",\"LT\",\"LY\",\"LI\",\"RO\",\"LU\",\"LB\",\"RU\",\"KR\",\"HK\",\"TW\",\"ZA\",\"JP\",\"MK\"]}"
  },
  {
    "path": "static/geolocations/ko.json",
    "content": "{\"names\":[\"가나\",\"과테말라\",\"그루지아\",\"그리스\",\"나이지리아\",\"남아프리카\",\"네덜란드\",\"네팔\",\"노르웨이\",\"뉴질랜드\",\"니카라과\",\"대만\",\"덴마크\",\"도미니카 공화국\",\"독일\",\"라오스\",\"라트비아\",\"러시아\",\"레바논\",\"루마니아\",\"룩셈부르크\",\"리비아\",\"리투아니아\",\"리히텐슈타인\",\"말레이시아\",\"멕시코\",\"모로코\",\"몬테네그로\",\"몰도바\",\"몰타\",\"미국\",\"바레인\",\"방글라데시\",\"베네수엘라\",\"베트남\",\"벨기에\",\"벨로루시\",\"보스니아-헤르체코비나\",\"볼리비아\",\"북마케도니아\",\"불가리아\",\"브라질\",\"사우디아라비아\",\"사이프러스\",\"세네갈\",\"세르비아\",\"스리랑카\",\"스웨덴\",\"스위스\",\"스페인\",\"슬로바키아\",\"슬로베니아\",\"싱가포르\",\"아랍 에미레이트\",\"아르헨티나\",\"아이슬란드\",\"아일랜드\",\"아제르바이잔\",\"알제리\",\"에스토니아\",\"에콰도르\",\"엘살바도르\",\"영국\",\"예멘\",\"오만\",\"오스트리아\",\"온두라스\",\"요르단\",\"우간다\",\"우루과이\",\"우크라이나\",\"이라크\",\"이스라엘\",\"이집트\",\"이탈리아\",\"인도\",\"인도네시아\",\"일본\",\"자메이카\",\"짐바브웨\",\"체코\",\"칠레\",\"카자흐스탄\",\"카타르\",\"캄보디아\",\"캐나다\",\"케냐\",\"코스타리카\",\"콜롬비아\",\"쿠웨이트\",\"크로아티아\",\"탄자니아\",\"태국\",\"터키\",\"튀니지\",\"파나마\",\"파라과이\",\"파키스탄\",\"파푸아 뉴기니\",\"페루\",\"포르투갈\",\"폴란드\",\"푸에르토리코\",\"프랑스\",\"핀란드\",\"필리핀\",\"한국\",\"헝가리\",\"호주\",\"홍콩\"],\"codes\":[\"GH\",\"GT\",\"GE\",\"GR\",\"NG\",\"ZA\",\"NL\",\"NP\",\"NO\",\"NZ\",\"NI\",\"TW\",\"DK\",\"DO\",\"DE\",\"LA\",\"LV\",\"RU\",\"LB\",\"RO\",\"LU\",\"LY\",\"LT\",\"LI\",\"MY\",\"MX\",\"MA\",\"ME\",\"MD\",\"MT\",\"US\",\"BH\",\"BD\",\"VE\",\"VN\",\"BE\",\"BY\",\"BA\",\"BO\",\"MK\",\"BG\",\"BR\",\"SA\",\"CY\",\"SN\",\"RS\",\"LK\",\"SE\",\"CH\",\"ES\",\"SK\",\"SI\",\"SG\",\"AE\",\"AR\",\"IS\",\"IE\",\"AZ\",\"DZ\",\"EE\",\"EC\",\"SV\",\"GB\",\"YE\",\"OM\",\"AT\",\"HN\",\"JO\",\"UG\",\"UY\",\"UA\",\"IQ\",\"IL\",\"EG\",\"IT\",\"IN\",\"ID\",\"JP\",\"JM\",\"ZW\",\"CZ\",\"CL\",\"KZ\",\"QA\",\"KH\",\"CA\",\"KE\",\"CR\",\"CO\",\"KW\",\"HR\",\"TZ\",\"TH\",\"TR\",\"TN\",\"PA\",\"PY\",\"PK\",\"PG\",\"PE\",\"PT\",\"PL\",\"PR\",\"FR\",\"FI\",\"PH\",\"KR\",\"HU\",\"AU\",\"HK\"]}"
  },
  {
    "path": "static/geolocations/lt.json",
    "content": "{\"names\":[\"Airija\",\"Alžyras\",\"Argentina\",\"Australija\",\"Austrija\",\"Azerbaidžanas\",\"Bahreinas\",\"Baltarusija\",\"Bangladešas\",\"Belgija\",\"Bolivija\",\"Bosnija ir Hercegovina\",\"Brazilija\",\"Bulgarija\",\"Čekija\",\"Čilė\",\"Danija\",\"Dominikos Respublika\",\"Egiptas\",\"Ekvadoras\",\"Estija\",\"Filipinai\",\"Gana\",\"Graikija\",\"Gruzija\",\"Gvatemala\",\"Hondūras\",\"Honkongas\",\"Indija\",\"Indonezija\",\"Irakas\",\"Islandija\",\"Ispanija\",\"Italija\",\"Izraelis\",\"Jamaika\",\"Japonija\",\"Jemenas\",\"Jordanija\",\"Jungtinė Karalystė\",\"Jungtinės Amerikos Valstijos\",\"Jungtiniai Arabų Emyratai\",\"Juodkalnija\",\"Kambodža\",\"Kanada\",\"Kataras\",\"Kazachstanas\",\"Kenija\",\"Kipras\",\"Kolumbija\",\"Kosta Rika\",\"Kroatija\",\"Kuveitas\",\"Laosas\",\"Latvija\",\"Lenkija\",\"Libanas\",\"Libija\",\"Lichtenšteinas\",\"Lietuva\",\"Liuksemburgas\",\"Malaizija\",\"Malta\",\"Marokas\",\"Meksika\",\"Moldova\",\"Naujoji Zelandija\",\"Nepalas\",\"Nyderlandai\",\"Nigerija\",\"Nikaragva\",\"Norvegija\",\"Omanas\",\"Pakistanas\",\"Panama\",\"Papua Naujoji Gvinėja\",\"Paragvajus\",\"Peru\",\"Pietų Afrika\",\"Pietų Korėja\",\"Portugalija\",\"Prancūzija\",\"Puerto Rikas\",\"Rumunija\",\"Rusija\",\"Salvadoras\",\"Saudo Arabija\",\"Senegalas\",\"Serbija\",\"Singapūras\",\"Slovakija\",\"Slovėnija\",\"Suomija\",\"Šiaurės Makedonija\",\"Šri Lanka\",\"Švedija\",\"Šveicarija\",\"Tailandas\",\"Taivanis\",\"Tanzanija\",\"Tunisas\",\"Turkija\",\"Uganda\",\"Ukraina\",\"Urugvajus\",\"Venesuela\",\"Vengrija\",\"Vietnamas\",\"Vokietija\",\"Zimbabvė\"],\"codes\":[\"IE\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BY\",\"BD\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CZ\",\"CL\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"GH\",\"GR\",\"GE\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IS\",\"ES\",\"IT\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"GB\",\"US\",\"AE\",\"ME\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CY\",\"CO\",\"CR\",\"HR\",\"KW\",\"LA\",\"LV\",\"PL\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NZ\",\"NP\",\"NL\",\"NG\",\"NI\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"ZA\",\"KR\",\"PT\",\"FR\",\"PR\",\"RO\",\"RU\",\"SV\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"FI\",\"MK\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"VE\",\"HU\",\"VN\",\"DE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/nb-NO.json",
    "content": "{\"names\":[\"Algerie\",\"Argentina\",\"Aserbajdsjan\",\"Australia\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgia\",\"Bolivia\",\"Bosnia-Hercegovina\",\"Brasil\",\"Bulgaria\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Danmark\",\"De forente arabiske emirater\",\"Den dominikanske republikk\",\"Ecuador\",\"Egypt\",\"El Salvador\",\"Estland\",\"Filippinene\",\"Finland\",\"Frankrike\",\"Georgia\",\"Ghana\",\"Guatemala\",\"Hellas\",\"Honduras\",\"Hongkong\",\"India\",\"Indonesia\",\"Irak\",\"Irland\",\"Island\",\"Israel\",\"Italia\",\"Jamaica\",\"Japan\",\"Jemen\",\"Jordan\",\"Kambodsja\",\"Kasakhstan\",\"Kenya\",\"Kroatia\",\"Kuwait\",\"Kypros\",\"Laos\",\"Latvia\",\"Libanon\",\"Libya\",\"Liechtenstein\",\"Litauen\",\"Luxembourg\",\"Malaysia\",\"Malta\",\"Marokko\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Nederland\",\"Nepal\",\"New Zealand\",\"Nicaragua\",\"Nigeria\",\"Nord-Makedonia\",\"Norge\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Ny-Guinea\",\"Paraguay\",\"Peru\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Romania\",\"Russland\",\"Saudi-Arabia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"Spania\",\"Sri Lanka\",\"Storbritannia\",\"Sveits\",\"Sverige\",\"Sør-Afrika\",\"Sør-Korea\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tsjekkia\",\"Tunisia\",\"Tyrkia\",\"Tyskland\",\"Uganda\",\"Ukraina\",\"Ungarn\",\"Uruguay\",\"USA\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\",\"Østerrike\"],\"codes\":[\"DZ\",\"AR\",\"AZ\",\"AU\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CA\",\"CL\",\"CO\",\"CR\",\"DK\",\"AE\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GT\",\"GR\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"KZ\",\"KE\",\"HR\",\"KW\",\"CY\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NL\",\"NP\",\"NZ\",\"NI\",\"NG\",\"MK\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"GB\",\"CH\",\"SE\",\"ZA\",\"KR\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"DE\",\"UG\",\"UA\",\"HU\",\"UY\",\"US\",\"VE\",\"VN\",\"ZW\",\"AT\"]}"
  },
  {
    "path": "static/geolocations/nl.json",
    "content": "{\"names\":[\"Algerije\",\"Argentinië\",\"Australië\",\"Azerbeidzjan\",\"Bahrein\",\"Bangladesh\",\"Belarus\",\"België\",\"Bolivia\",\"Bosnië-Herzegovina\",\"Brazilië\",\"Bulgarije\",\"Cambodja\",\"Canada\",\"Chili\",\"Colombia\",\"Costa Rica\",\"Cyprus\",\"Denemarken\",\"Dominicaanse Republiek\",\"Duitsland\",\"Ecuador\",\"Egypte\",\"El Salvador\",\"Estland\",\"Filipijnen\",\"Finland\",\"Frankrijk\",\"Georgië\",\"Ghana\",\"Griekenland\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hongarije\",\"Ierland\",\"IJsland\",\"India\",\"Indonesië\",\"Irak\",\"Israël\",\"Italië\",\"Jamaica\",\"Japan\",\"Jemen\",\"Jordanië\",\"Kazachstan\",\"Kenia\",\"Koeweit\",\"Kroatië\",\"Laos\",\"Letland\",\"Libanon\",\"Libië\",\"Liechtenstein\",\"Litouwen\",\"Luxemburg\",\"Maleisië\",\"Malta\",\"Marokko\",\"Mexico\",\"Moldavië\",\"Montenegro\",\"Nederland\",\"Nepal\",\"Nicaragua\",\"Nieuw-Zeeland\",\"Nigeria\",\"Noord-Macedonië\",\"Noorwegen\",\"Oeganda\",\"Oekraïne\",\"Oman\",\"Oostenrijk\",\"Pakistan\",\"Panama\",\"Papoea-Nieuw-Guinea\",\"Paraguay\",\"Peru\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Roemenië\",\"Rusland\",\"Saudi-Arabië\",\"Senegal\",\"Servië\",\"Singapore\",\"Slovenië\",\"Slowakije\",\"Spanje\",\"Sri Lanka\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tsjechië\",\"Tunesië\",\"Turkije\",\"Uruguay\",\"Venezuela\",\"Verenigd Koninkrijk\",\"Verenigde Arabische Emiraten\",\"Verenigde Staten\",\"Vietnam\",\"Zimbabwe\",\"Zuid-Afrika\",\"Zuid-Korea\",\"Zweden\",\"Zwitserland\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CL\",\"CO\",\"CR\",\"CY\",\"DK\",\"DO\",\"DE\",\"EC\",\"EG\",\"SV\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"IE\",\"IS\",\"IN\",\"ID\",\"IQ\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KZ\",\"KE\",\"KW\",\"HR\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NL\",\"NP\",\"NI\",\"NZ\",\"NG\",\"MK\",\"NO\",\"UG\",\"UA\",\"OM\",\"AT\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SI\",\"SK\",\"ES\",\"LK\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"UY\",\"VE\",\"GB\",\"AE\",\"US\",\"VN\",\"ZW\",\"ZA\",\"KR\",\"SE\",\"CH\"]}"
  },
  {
    "path": "static/geolocations/nn.json",
    "content": "{\"names\":[\"Algerie\",\"Argentina\",\"Aserbajdsjan\",\"Australia\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgia\",\"Bolivia\",\"Bosnia-Hercegovina\",\"Brasil\",\"Bulgaria\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Danmark\",\"De forente arabiske emirater\",\"Den dominikanske republikk\",\"Ecuador\",\"Egypt\",\"El Salvador\",\"Estland\",\"Filippinene\",\"Finland\",\"Frankrike\",\"Georgia\",\"Ghana\",\"Guatemala\",\"Hellas\",\"Honduras\",\"Hongkong\",\"India\",\"Indonesia\",\"Irak\",\"Irland\",\"Island\",\"Israel\",\"Italia\",\"Jamaica\",\"Japan\",\"Jemen\",\"Jordan\",\"Kambodsja\",\"Kasakhstan\",\"Kenya\",\"Kroatia\",\"Kuwait\",\"Kypros\",\"Laos\",\"Latvia\",\"Libanon\",\"Libya\",\"Liechtenstein\",\"Litauen\",\"Luxembourg\",\"Malaysia\",\"Malta\",\"Marokko\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Nederland\",\"Nepal\",\"New Zealand\",\"Nicaragua\",\"Nigeria\",\"Nord-Makedonia\",\"Norge\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Ny-Guinea\",\"Paraguay\",\"Peru\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Romania\",\"Russland\",\"Saudi-Arabia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"Spania\",\"Sri Lanka\",\"Storbritannia\",\"Sveits\",\"Sverige\",\"Sør-Afrika\",\"Sør-Korea\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tsjekkia\",\"Tunisia\",\"Tyrkia\",\"Tyskland\",\"Uganda\",\"Ukraina\",\"Ungarn\",\"Uruguay\",\"USA\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\",\"Østerrike\"],\"codes\":[\"DZ\",\"AR\",\"AZ\",\"AU\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CA\",\"CL\",\"CO\",\"CR\",\"DK\",\"AE\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GT\",\"GR\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"KZ\",\"KE\",\"HR\",\"KW\",\"CY\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NL\",\"NP\",\"NZ\",\"NI\",\"NG\",\"MK\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"GB\",\"CH\",\"SE\",\"ZA\",\"KR\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"DE\",\"UG\",\"UA\",\"HU\",\"UY\",\"US\",\"VE\",\"VN\",\"ZW\",\"AT\"]}"
  },
  {
    "path": "static/geolocations/pl.json",
    "content": "{\"names\":[\"Algieria\",\"Arabia Saudyjska\",\"Argentyna\",\"Australia\",\"Austria\",\"Azerbejdżan\",\"Bahrajn\",\"Bangladesz\",\"Belgia\",\"Białoruś\",\"Boliwia\",\"Bośnia i Hercegowina\",\"Brazylia\",\"Bułgaria\",\"Chile\",\"Chorwacja\",\"Cypr\",\"Czarnogóra\",\"Czechy\",\"Dania\",\"Dominikana\",\"Egipt\",\"Ekwador\",\"Estonia\",\"Filipiny\",\"Finlandia\",\"Francja\",\"Georgia\",\"Ghana\",\"Grecja\",\"Gwatemala\",\"Hiszpania\",\"Holandia\",\"Honduras\",\"Hongkong\",\"Indie\",\"Indonezja\",\"Irak\",\"Irlandia\",\"Islandia\",\"Izrael\",\"Jamajka\",\"Japonia\",\"Jemen\",\"Jordania\",\"Kambodża\",\"Kanada\",\"Katar\",\"Kazachstan\",\"Kenia\",\"Kolumbia\",\"Korea Południowa\",\"Kostaryka\",\"Kuwejt\",\"Laos\",\"Liban\",\"Libia\",\"Lichtenstein\",\"Litwa\",\"Luksemburg\",\"Łotwa\",\"Macedonia Północna\",\"Malezja\",\"Malta\",\"Maroko\",\"Meksyk\",\"Mołdawia\",\"Nepal\",\"Niemcy\",\"Nigeria\",\"Nikaragua\",\"Norwegia\",\"Nowa Zelandia\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua-Nowa Gwinea\",\"Paragwaj\",\"Peru\",\"Polska\",\"Portoryko\",\"Portugalia\",\"Republika Południowej Afryki\",\"Rosja\",\"Rumunia\",\"Salwador\",\"Senegal\",\"Serbia\",\"Singapur\",\"Słowacja\",\"Słowenia\",\"Sri Lanka\",\"Stany Zjednoczone\",\"Szwajcaria\",\"Szwecja\",\"Tajlandia\",\"Tajwan\",\"Tanzania\",\"Tunezja\",\"Turcja\",\"Uganda\",\"Ukraina\",\"Urugwaj\",\"Wenezuela\",\"Węgry\",\"Wielka Brytania\",\"Wietnam\",\"Włochy\",\"Zimbabwe\",\"Zjednoczone Emiraty Arabskie\"],\"codes\":[\"DZ\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"CL\",\"HR\",\"CY\",\"ME\",\"CZ\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"GH\",\"GR\",\"GT\",\"ES\",\"NL\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"KR\",\"CR\",\"KW\",\"LA\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"LV\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"DE\",\"NG\",\"NI\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"ZA\",\"RU\",\"RO\",\"SV\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"LK\",\"US\",\"CH\",\"SE\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"VE\",\"HU\",\"GB\",\"VN\",\"IT\",\"ZW\",\"AE\"]}"
  },
  {
    "path": "static/geolocations/pt-BR.json",
    "content": "{\"names\":[\"África do Sul\",\"Alemanha\",\"Arábia Saudita\",\"Argélia\",\"Argentina\",\"Austrália\",\"Áustria\",\"Azerbaijão\",\"Bangladesh\",\"Barein\",\"Bélgica\",\"Bielorrússia\",\"Bolívia\",\"Bósnia-Herzegovina\",\"Brasil\",\"Bulgária\",\"Camboja\",\"Canadá\",\"Catar\",\"Cazaquistão\",\"Chile\",\"Chipre\",\"Colômbia\",\"Coréia do Sul\",\"Costa Rica\",\"Croácia\",\"Dinamarca\",\"Egito\",\"El Salvador\",\"Emirados Árabes Unidos\",\"Equador\",\"Eslováquia\",\"Eslovênia\",\"Espanha\",\"Estados Unidos\",\"Estônia\",\"Filipinas\",\"Finlândia\",\"França\",\"Gana\",\"Georgia\",\"Grécia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungria\",\"Iêmen\",\"Índia\",\"Indonésia\",\"Iraque\",\"Irlanda\",\"Islândia\",\"Israel\",\"Itália\",\"Jamaica\",\"Japão\",\"Jordânia\",\"Kuwait\",\"Laos\",\"Letônia\",\"Líbano\",\"Líbia\",\"Liechtenstein\",\"Lituânia\",\"Luxemburgo\",\"Macedônia do Norte\",\"Malásia\",\"Malta\",\"Marrocos\",\"México\",\"Moldávia\",\"Montenegro\",\"Nepal\",\"Nicarágua\",\"Nigéria\",\"Noruega\",\"Nova Zelândia\",\"Omã\",\"Países Baixos\",\"Panamá\",\"Papua-Nova Guiné\",\"Paquistão\",\"Paraguai\",\"Peru\",\"Polônia\",\"Porto Rico\",\"Portugal\",\"Quênia\",\"Reino Unido\",\"República Dominicana\",\"República Tcheca\",\"Romênia\",\"Rússia\",\"Senegal\",\"Sérvia\",\"Singapura\",\"Sri Lanka\",\"Suécia\",\"Suíça\",\"Tailândia\",\"Taiwan\",\"Tanzânia\",\"Tunísia\",\"Turquia\",\"Ucrânia\",\"Uganda\",\"Uruguai\",\"Venezuela\",\"Vietnã\",\"Zimbábue\"],\"codes\":[\"ZA\",\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BD\",\"BH\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"QA\",\"KZ\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EG\",\"SV\",\"AE\",\"EC\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GE\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"YE\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"NL\",\"PA\",\"PG\",\"PK\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"KE\",\"GB\",\"DO\",\"CZ\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/pt-PT.json",
    "content": "{\"names\":[\"África do Sul\",\"Alemanha\",\"Arábia Saudita\",\"Argélia\",\"Argentina\",\"Austrália\",\"Áustria\",\"Azerbaijão\",\"Bangladexe\",\"Barém\",\"Bélgica\",\"Bielorrússia\",\"Bolívia\",\"Bósnia-Herzegovina\",\"Brasil\",\"Bulgária\",\"Camboja\",\"Canadá\",\"Catar\",\"Cazaquistão\",\"Chéquia\",\"Chile\",\"Chipre\",\"Colômbia\",\"Coreia do Sul\",\"Costa Rica\",\"Croácia\",\"Dinamarca\",\"Egito\",\"El Salvador\",\"Emirados Árabes Unidos\",\"Equador\",\"Eslováquia\",\"Eslovénia\",\"Espanha\",\"Estados Unidos\",\"Estónia\",\"Filipinas\",\"Finlândia\",\"França\",\"Gana\",\"Geórgia\",\"Grécia\",\"Guatemala\",\"Holanda\",\"Honduras\",\"Hong Kong\",\"Hungria\",\"Iémen\",\"Índia\",\"Indonésia\",\"Iraque\",\"Irlanda\",\"Islândia\",\"Israel\",\"Itália\",\"Jamaica\",\"Japão\",\"Jordânia\",\"Kuwait\",\"Laos\",\"Letónia\",\"Líbano\",\"Líbia\",\"Lienchtenstein\",\"Lituânia\",\"Luxemburgo\",\"Macedónia do Norte\",\"Malásia\",\"Malta\",\"Marrocos\",\"México\",\"Moldávia\",\"Montenegro\",\"Nepal\",\"Nicarágua\",\"Nigéria\",\"Noruega\",\"Nova Zelândia\",\"Omã\",\"Panamá\",\"Papuásia-Nova Guiné\",\"Paquistão\",\"Paraguai\",\"Peru\",\"Polónia\",\"Porto Rico\",\"Portugal\",\"Quénia\",\"Reino Unido\",\"República Dominicana\",\"Roménia\",\"Rússia\",\"Senegal\",\"Sérvia\",\"Singapura\",\"Sri Lanka\",\"Suécia\",\"Suíça\",\"Tailândia\",\"Taiwan\",\"Tanzânia\",\"Tunísia\",\"Turquia\",\"Ucrânia\",\"Uganda\",\"Uruguai\",\"Venezuela\",\"Vietname\",\"Zimbabué\"],\"codes\":[\"ZA\",\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BD\",\"BH\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"QA\",\"KZ\",\"CZ\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EG\",\"SV\",\"AE\",\"EC\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GE\",\"GR\",\"GT\",\"NL\",\"HN\",\"HK\",\"HU\",\"YE\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"PA\",\"PG\",\"PK\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"KE\",\"GB\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/pt.json",
    "content": "{\"names\":[\"África do Sul\",\"Alemanha\",\"Arábia Saudita\",\"Argélia\",\"Argentina\",\"Austrália\",\"Áustria\",\"Azerbaijão\",\"Bangladesh\",\"Barein\",\"Bélgica\",\"Bielorrússia\",\"Bolívia\",\"Bósnia-Herzegovina\",\"Brasil\",\"Bulgária\",\"Camboja\",\"Canadá\",\"Catar\",\"Cazaquistão\",\"Chile\",\"Chipre\",\"Colômbia\",\"Coréia do Sul\",\"Costa Rica\",\"Croácia\",\"Dinamarca\",\"Egito\",\"El Salvador\",\"Emirados Árabes Unidos\",\"Equador\",\"Eslováquia\",\"Eslovênia\",\"Espanha\",\"Estados Unidos\",\"Estônia\",\"Filipinas\",\"Finlândia\",\"França\",\"Gana\",\"Georgia\",\"Grécia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"Hungria\",\"Iêmen\",\"Índia\",\"Indonésia\",\"Iraque\",\"Irlanda\",\"Islândia\",\"Israel\",\"Itália\",\"Jamaica\",\"Japão\",\"Jordânia\",\"Kuwait\",\"Laos\",\"Letônia\",\"Líbano\",\"Líbia\",\"Liechtenstein\",\"Lituânia\",\"Luxemburgo\",\"Macedônia do Norte\",\"Malásia\",\"Malta\",\"Marrocos\",\"México\",\"Moldávia\",\"Montenegro\",\"Nepal\",\"Nicarágua\",\"Nigéria\",\"Noruega\",\"Nova Zelândia\",\"Omã\",\"Países Baixos\",\"Panamá\",\"Papua-Nova Guiné\",\"Paquistão\",\"Paraguai\",\"Peru\",\"Polônia\",\"Porto Rico\",\"Portugal\",\"Quênia\",\"Reino Unido\",\"República Dominicana\",\"República Tcheca\",\"Romênia\",\"Rússia\",\"Senegal\",\"Sérvia\",\"Singapura\",\"Sri Lanka\",\"Suécia\",\"Suíça\",\"Tailândia\",\"Taiwan\",\"Tanzânia\",\"Tunísia\",\"Turquia\",\"Ucrânia\",\"Uganda\",\"Uruguai\",\"Venezuela\",\"Vietnã\",\"Zimbábue\"],\"codes\":[\"ZA\",\"DE\",\"SA\",\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BD\",\"BH\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"QA\",\"KZ\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EG\",\"SV\",\"AE\",\"EC\",\"SK\",\"SI\",\"ES\",\"US\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GE\",\"GR\",\"GT\",\"HN\",\"HK\",\"HU\",\"YE\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"JO\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"NL\",\"PA\",\"PG\",\"PK\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"KE\",\"GB\",\"DO\",\"CZ\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UA\",\"UG\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/ro.json",
    "content": "{\"names\":[\"Africa de Sud\",\"Algeria\",\"Arabia Saudită\",\"Argentina\",\"Australia\",\"Austria\",\"Azerbaidjan\",\"Bahrein\",\"Bangladesh\",\"Belarus\",\"Belgia\",\"Bolivia\",\"Bosnia și Herțegovina\",\"Brazilia\",\"Bulgaria\",\"Cambodgia\",\"Canada\",\"Cehia\",\"Chile\",\"Cipru\",\"Columbia\",\"Coreea de Sud\",\"Costa Rica\",\"Croația\",\"Danemarca\",\"Ecuador\",\"Egipt\",\"El Salvador\",\"Elveția\",\"Emiratele Arabe Unite\",\"Estonia\",\"Filipine\",\"Finlanda\",\"Franța\",\"Georgia\",\"Germania\",\"Ghana\",\"Grecia\",\"Guatemala\",\"Honduras\",\"Hong Kong\",\"India\",\"Indonezia\",\"Iordania\",\"Irak\",\"Irlanda\",\"Islanda\",\"Israel\",\"Italia\",\"Jamaica\",\"Japonia\",\"Kazahstan\",\"Kenya\",\"Kuweit\",\"Laos\",\"Letonia\",\"Liban\",\"Libia\",\"Liechtenstein\",\"Lituania\",\"Luxemburg\",\"Macedonia de Nord\",\"Malaezia\",\"Malta\",\"Maroc\",\"Mexic\",\"Moldova\",\"Muntenegru\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Norvegia\",\"Noua Zeelandă\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Noua Guinee\",\"Paraguay\",\"Peru\",\"Polonia\",\"Portugalia\",\"Puerto Rico\",\"Qatar\",\"Regatul Unit\",\"Republica Dominicană\",\"România\",\"Rusia\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovacia\",\"Slovenia\",\"Spania\",\"Sri Lanka\",\"Statele Unite ale Americii\",\"Suedia\",\"Taiwan\",\"Tanzania\",\"Thailanda\",\"Tunisia\",\"Turcia\",\"Țările de Jos\",\"Ucraina\",\"Uganda\",\"Ungaria\",\"Uruguay\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Zimbabwe\"],\"codes\":[\"ZA\",\"DZ\",\"SA\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"KH\",\"CA\",\"CZ\",\"CL\",\"CY\",\"CO\",\"KR\",\"CR\",\"HR\",\"DK\",\"EC\",\"EG\",\"SV\",\"CH\",\"AE\",\"EE\",\"PH\",\"FI\",\"FR\",\"GE\",\"DE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"JO\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MK\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NP\",\"NI\",\"NG\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"GB\",\"DO\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"US\",\"SE\",\"TW\",\"TZ\",\"TH\",\"TN\",\"TR\",\"NL\",\"UA\",\"UG\",\"HU\",\"UY\",\"VE\",\"VN\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/ru.json",
    "content": "{\"names\":[\"Австралия\",\"Австрия\",\"Азербайджан\",\"Алжир\",\"Аргентина\",\"Бангладеш\",\"Бахрейн\",\"Беларусь\",\"Бельгия\",\"Болгария\",\"Боливия\",\"Босния и Герцеговина\",\"Бразилия\",\"Великобритания\",\"Венгрия\",\"Венесуэла\",\"Вьетнам\",\"Гана\",\"Гватемала\",\"Германия\",\"Гондурас\",\"Гонконг\",\"Греция\",\"Грузия\",\"Дания\",\"Доминиканская Республика\",\"Египет\",\"Зимбабве\",\"Израиль\",\"Индия\",\"Индонезия\",\"Иордания\",\"Ирак\",\"Ирландия\",\"Исландия\",\"Испания\",\"Италия\",\"Йемен\",\"Казахстан\",\"Камбоджа\",\"Канада\",\"Катар\",\"Кения\",\"Кипр\",\"Колумбия\",\"Коста-Рика\",\"Кувейт\",\"Лаос\",\"Латвия\",\"Ливан\",\"Ливия\",\"Литва\",\"Лихтенштейн\",\"Люксембург\",\"Малайзия\",\"Мальта\",\"Марокко\",\"Мексика\",\"Молдова\",\"Непал\",\"Нигерия\",\"Нидерланды\",\"Никарагуа\",\"Новая Зеландия\",\"Норвегия\",\"Объединенные Арабские Эмираты\",\"Оман\",\"Пакистан\",\"Панама\",\"Папуа-Новая Гвинея\",\"Парагвай\",\"Перу\",\"Польша\",\"Португалия\",\"Пуэрто-Рико\",\"Россия\",\"Румыния\",\"Сальвадор\",\"Саудовская Аравия\",\"Северная Македония\",\"Сенегал\",\"Сербия\",\"Сингапур\",\"Словакия\",\"Словения\",\"США\",\"Таиланд\",\"Тайвань\",\"Танзания\",\"Тунис\",\"Турция\",\"Уганда\",\"Украина\",\"Уругвай\",\"Филиппины\",\"Финляндия\",\"Франция\",\"Хорватия\",\"Черногория\",\"Чехия\",\"Чили\",\"Швейцария\",\"Швеция\",\"Шри-Ланка\",\"Эквадор\",\"Эстония\",\"Южная Корея\",\"Южно-Африканская Республика\",\"Ямайка\",\"Япония\"],\"codes\":[\"AU\",\"AT\",\"AZ\",\"DZ\",\"AR\",\"BD\",\"BH\",\"BY\",\"BE\",\"BG\",\"BO\",\"BA\",\"BR\",\"GB\",\"HU\",\"VE\",\"VN\",\"GH\",\"GT\",\"DE\",\"HN\",\"HK\",\"GR\",\"GE\",\"DK\",\"DO\",\"EG\",\"ZW\",\"IL\",\"IN\",\"ID\",\"JO\",\"IQ\",\"IE\",\"IS\",\"ES\",\"IT\",\"YE\",\"KZ\",\"KH\",\"CA\",\"QA\",\"KE\",\"CY\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LT\",\"LI\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"NG\",\"NL\",\"NI\",\"NZ\",\"NO\",\"AE\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"RU\",\"RO\",\"SV\",\"SA\",\"MK\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"US\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"PH\",\"FI\",\"FR\",\"HR\",\"ME\",\"CZ\",\"CL\",\"CH\",\"SE\",\"LK\",\"EC\",\"EE\",\"KR\",\"ZA\",\"JM\",\"JP\"]}"
  },
  {
    "path": "static/geolocations/sk.json",
    "content": "{\"names\":[\"Alžírsko\",\"Argentína\",\"Austrália\",\"Azerbajdžan\",\"Bahrajn\",\"Bangladéš\",\"Belgicko\",\"Bielorusko\",\"Bolívia\",\"Bosna a Hercegovina\",\"Brazília\",\"Bulharsko\",\"Cyprus\",\"Česko\",\"Čierna Hora\",\"Čile\",\"Dánsko\",\"Dominikánska republika\",\"Egypt\",\"Ekvádor\",\"Estónsko\",\"Filipíny\",\"Fínsko\",\"Francúzsko\",\"Ghana\",\"Grécko\",\"Gruzínsko\",\"Guatemala\",\"Holandsko\",\"Honduras\",\"Hongkong\",\"Chorvátsko\",\"India\",\"Indonézia\",\"Irak\",\"Írsko\",\"Island\",\"Izrael\",\"Jamajka\",\"Japonsko\",\"Jemen\",\"Jordánsko\",\"Juhoafrická republika\",\"Južná Kórea\",\"Kambodža\",\"Kanada\",\"Katar\",\"Kazachstan\",\"Keňa\",\"Kolumbia\",\"Kostarika\",\"Kuvajt\",\"Laos\",\"Libanon\",\"Líbya\",\"Lichtenštajnsko\",\"Litva\",\"Lotyšsko\",\"Luxembursko\",\"Maďarsko\",\"Malajzia\",\"Malta\",\"Maroko\",\"Mexiko\",\"Moldavsko\",\"Nemecko\",\"Nepál\",\"Nigéria\",\"Nikaragua\",\"Nórsko\",\"Nový Zéland\",\"Omán\",\"Pakistan\",\"Panama\",\"Papua – Nová Guinea\",\"Paraguaj\",\"Peru\",\"Poľsko\",\"Portoriko\",\"Portugalsko\",\"Rakúsko\",\"Rumunsko\",\"Rusko\",\"Salvádor\",\"Saudská Arábia\",\"Senegal\",\"Severné Macedónsko\",\"Singapur\",\"Slovensko\",\"Slovinsko\",\"Spojené arabské emiráty\",\"Spojené kráľovstvo\",\"Spojené štáty\",\"Srbsko\",\"Srí Lanka\",\"Španielsko\",\"Švajčiarsko\",\"Švédsko\",\"Taiwan\",\"Taliansko\",\"Tanzánia\",\"Thajsko\",\"Tunisko\",\"Turecko\",\"Uganda\",\"Ukrajina\",\"Uruguaj\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"CY\",\"CZ\",\"ME\",\"CL\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GR\",\"GE\",\"GT\",\"NL\",\"HN\",\"HK\",\"HR\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"ZA\",\"KR\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"CR\",\"KW\",\"LA\",\"LB\",\"LY\",\"LI\",\"LT\",\"LV\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"DE\",\"NP\",\"NG\",\"NI\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"AT\",\"RO\",\"RU\",\"SV\",\"SA\",\"SN\",\"MK\",\"SG\",\"SK\",\"SI\",\"AE\",\"GB\",\"US\",\"RS\",\"LK\",\"ES\",\"CH\",\"SE\",\"TW\",\"IT\",\"TZ\",\"TH\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/sl.json",
    "content": "{\"names\":[\"Alžirija\",\"Argentina\",\"Avstralija\",\"Avstrija\",\"Azerbajdžan\",\"Bahrajn\",\"Bangladeš\",\"Belgija\",\"Belorusija\",\"Bolgarija\",\"Bolivija\",\"Bosna in Hercegovina\",\"Brazilija\",\"Ciper\",\"Češka\",\"Čile\",\"Črna gora\",\"Danska\",\"Dominikanska republika\",\"Egipt\",\"Ekvador\",\"Estonija\",\"Filipini\",\"Finska\",\"Francija\",\"Gana\",\"Grčija\",\"Gruzija\",\"Gvatemala\",\"Honduras\",\"Hongkong\",\"Hrvaška\",\"Indija\",\"Indonezija\",\"Irak\",\"Irska\",\"Islandija\",\"Italija\",\"Izrael\",\"Jamajka\",\"Japonska\",\"Jemen\",\"Jordanija\",\"Južna Afrika\",\"Južna Koreja\",\"Kambodža\",\"Kanada\",\"Katar\",\"Kazahstan\",\"Kenija\",\"Kolumbija\",\"Kostarika\",\"Kuvajt\",\"Laos\",\"Latvija\",\"Libanon\",\"Libija\",\"Lihtenštajn\",\"Litva\",\"Luksemburg\",\"Madžarska\",\"Malezija\",\"Malta\",\"Maroko\",\"Mehika\",\"Moldavija\",\"Nemčija\",\"Nepal\",\"Nigerija\",\"Nikaragva\",\"Nizozemska\",\"Norveška\",\"Nova Zelandija\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Nova Gvineja\",\"Paragvaj\",\"Peru\",\"Poljska\",\"Portoriko\",\"Portugalska\",\"Romunija\",\"Rusija\",\"Salvador\",\"Saudova Arabija\",\"Senegal\",\"Severna Makedonija\",\"Singapur\",\"Slovaška\",\"Slovenija\",\"Srbija\",\"Španija\",\"Šrilanka\",\"Švedska\",\"Švica\",\"Tajska\",\"Tajvan\",\"Tanzanija\",\"Tunizija\",\"Turčija\",\"Uganda\",\"Ukrajina\",\"Urugvaj\",\"Venezuela\",\"Vietnam\",\"Združene države\",\"Združeni arabski emirati\",\"Združeno kraljestvo\",\"Zimbabve\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BE\",\"BY\",\"BG\",\"BO\",\"BA\",\"BR\",\"CY\",\"CZ\",\"CL\",\"ME\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"PH\",\"FI\",\"FR\",\"GH\",\"GR\",\"GE\",\"GT\",\"HN\",\"HK\",\"HR\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IT\",\"IL\",\"JM\",\"JP\",\"YE\",\"JO\",\"ZA\",\"KR\",\"KH\",\"CA\",\"QA\",\"KZ\",\"KE\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"DE\",\"NP\",\"NG\",\"NI\",\"NL\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"RO\",\"RU\",\"SV\",\"SA\",\"SN\",\"MK\",\"SG\",\"SK\",\"SI\",\"RS\",\"ES\",\"LK\",\"SE\",\"CH\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"US\",\"AE\",\"GB\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/sr.json",
    "content": "{\"names\":[\"Азербејџан\",\"Алжир\",\"Аргентина\",\"Аустралија\",\"Аустрија\",\"Бангладеш\",\"Бахреин\",\"Белгија\",\"Белорусија\",\"Боливија\",\"Босна и Херцеговина\",\"Бразил\",\"Бугарска\",\"Венецуела\",\"Вијетнам\",\"Гана\",\"Гватемала\",\"Грузија\",\"Грчка\",\"Данска\",\"Доминиканска Република\",\"Египат\",\"Еквадор\",\"Естонија\",\"Зимбабве\",\"Израел\",\"Индија\",\"Индонезија\",\"Ирак\",\"Ирска\",\"Исланд\",\"Италија\",\"Јамајка\",\"Јапан\",\"Јемен\",\"Јордан\",\"Јужна Кореја\",\"Јужноафричка Република\",\"Казахстан\",\"Камбоџа\",\"Канада\",\"Катар\",\"Кенија\",\"Кипар\",\"Колумбија\",\"Костарика\",\"Кувајт\",\"Лаос\",\"Летонија\",\"Либан\",\"Либија\",\"Литванија\",\"Лихтенштајн\",\"Луксембург\",\"Мађарска\",\"Малезија\",\"Малта\",\"Мароко\",\"Мексико\",\"Молдавија\",\"Немачка\",\"Непал\",\"Нигерија\",\"Никарагва\",\"Нови Зеланд\",\"Норвешка\",\"Оман\",\"Пакистан\",\"Панама\",\"Папуа Нова Гвинеја\",\"Парагвај\",\"Перу\",\"Пољска\",\"Порторико\",\"Португалија\",\"Румунија\",\"Русија\",\"САД\",\"Салвадор\",\"Саудијска Арабија\",\"Северна Македонија\",\"Сенегал\",\"Сингапур\",\"Словачка\",\"Словенија\",\"Србија\",\"Тајван\",\"Тајланд\",\"Танзанија\",\"Тунис\",\"Турска\",\"Уганда\",\"Уједињени Арапски Емирати\",\"Уједињено Краљевство\",\"Украјина\",\"Уругвај\",\"Филипини\",\"Финска\",\"Француска\",\"Холандија\",\"Хонгконг\",\"Хондурас\",\"Хрватска\",\"Црна Гора\",\"Чешка\",\"Чиле\",\"Швајцарска\",\"Шведска\",\"Шпанија\",\"Шри Ланка\"],\"codes\":[\"AZ\",\"DZ\",\"AR\",\"AU\",\"AT\",\"BD\",\"BH\",\"BE\",\"BY\",\"BO\",\"BA\",\"BR\",\"BG\",\"VE\",\"VN\",\"GH\",\"GT\",\"GE\",\"GR\",\"DK\",\"DO\",\"EG\",\"EC\",\"EE\",\"ZW\",\"IL\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KR\",\"ZA\",\"KZ\",\"KH\",\"CA\",\"QA\",\"KE\",\"CY\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LT\",\"LI\",\"LU\",\"HU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"DE\",\"NP\",\"NG\",\"NI\",\"NZ\",\"NO\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PR\",\"PT\",\"RO\",\"RU\",\"US\",\"SV\",\"SA\",\"MK\",\"SN\",\"SG\",\"SK\",\"SI\",\"RS\",\"TW\",\"TH\",\"TZ\",\"TN\",\"TR\",\"UG\",\"AE\",\"GB\",\"UA\",\"UY\",\"PH\",\"FI\",\"FR\",\"NL\",\"HK\",\"HN\",\"HR\",\"ME\",\"CZ\",\"CL\",\"CH\",\"SE\",\"ES\",\"LK\"]}"
  },
  {
    "path": "static/geolocations/sv.json",
    "content": "{\"names\":[\"Algeriet\",\"Argentina\",\"Australien\",\"Azerbadjan\",\"Bahrain\",\"Bangladesh\",\"Belarus\",\"Belgien\",\"Bolivia\",\"Bosnien-Hercegovina\",\"Brasilien\",\"Bulgarien\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Cypern\",\"Danmark\",\"Dominikanska republiken\",\"Ecuador\",\"Egypten\",\"El Salvador\",\"Estland\",\"Filippinerna\",\"Finland\",\"Frankrike\",\"Förenade arabemiraten\",\"Förenade kungariket\",\"Georgien\",\"Ghana\",\"Grekland\",\"Guatemala\",\"Honduras\",\"Hongkong\",\"Indien\",\"Indonesien\",\"Irak\",\"Irland\",\"Island\",\"Israel\",\"Italien\",\"Jamaica\",\"Japan\",\"Jemen\",\"Jordanien\",\"Kambodja\",\"Kanada\",\"Kazakstan\",\"Kenya\",\"Kroatien\",\"Kuwait\",\"Laos\",\"Lettland\",\"Libanon\",\"Libyen\",\"Liechtenstein\",\"Litauen\",\"Luxemburg\",\"Malaysia\",\"Malta\",\"Marocko\",\"Mexiko\",\"Moldavien\",\"Montenegro\",\"Nederländerna\",\"Nepal\",\"Nicaragua\",\"Nigeria\",\"Nordmakedonien\",\"Norge\",\"Nya Zeeland\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua Nya Guinea\",\"Paraguay\",\"Peru\",\"Polen\",\"Portugal\",\"Puerto Rico\",\"Qatar\",\"Rumänien\",\"Ryssland\",\"Saudiarabien\",\"Schweiz\",\"Senegal\",\"Serbien\",\"Singapore\",\"Slovakien\",\"Slovenien\",\"Spanien\",\"Sri Lanka\",\"Sverige\",\"Sydafrika\",\"Sydkorea\",\"Taiwan\",\"Tanzania\",\"Thailand\",\"Tjeckien\",\"Tunisien\",\"Turkiet\",\"Tyskland\",\"Uganda\",\"Ukraina\",\"Ungern\",\"Uruguay\",\"USA\",\"Venezuela\",\"Vietnam\",\"Zimbabwe\",\"Österrike\"],\"codes\":[\"DZ\",\"AR\",\"AU\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"BO\",\"BA\",\"BR\",\"BG\",\"CL\",\"CO\",\"CR\",\"CY\",\"DK\",\"DO\",\"EC\",\"EG\",\"SV\",\"EE\",\"PH\",\"FI\",\"FR\",\"AE\",\"GB\",\"GE\",\"GH\",\"GR\",\"GT\",\"HN\",\"HK\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"IL\",\"IT\",\"JM\",\"JP\",\"YE\",\"JO\",\"KH\",\"CA\",\"KZ\",\"KE\",\"HR\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"ME\",\"NL\",\"NP\",\"NI\",\"NG\",\"MK\",\"NO\",\"NZ\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"QA\",\"RO\",\"RU\",\"SA\",\"CH\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"ES\",\"LK\",\"SE\",\"ZA\",\"KR\",\"TW\",\"TZ\",\"TH\",\"CZ\",\"TN\",\"TR\",\"DE\",\"UG\",\"UA\",\"HU\",\"UY\",\"US\",\"VE\",\"VN\",\"ZW\",\"AT\"]}"
  },
  {
    "path": "static/geolocations/ta.json",
    "content": "{\"names\":[\"அமெரிக்க ஐக்கிய நாடுகள்\",\"அயர்லாந்து\",\"அர்ஜென்டீனா\",\"அல்ஜீரியா\",\"அஜர்பைஜான்\",\"ஆஸ்திரியா\",\"ஆஸ்திரேலியா\",\"இத்தாலி\",\"இந்தியா\",\"இந்தோனேஷியா\",\"இலங்கை\",\"இஸ்ரேல்\",\"ஈக்வெடார்\",\"ஈராக்\",\"உக்ரைன்\",\"உகாண்டா\",\"உருகுவே\",\"எகிப்து\",\"எல் சால்வேடார்\",\"எஸ்டோனியா\",\"ஏமன்\",\"ஐக்கிய அரபு எமிரேட்ஸ்\",\"ஐஸ்லாந்து\",\"ஓமன்\",\"ஃபிரான்ஸ்\",\"ஃபின்லாந்து\",\"கத்தார்\",\"கம்போடியா\",\"கவுதமாலா\",\"கனடா\",\"கஸகஸ்தான்\",\"கானா\",\"கிரீஸ்\",\"குரோஷியா\",\"குவைத்\",\"கென்யா\",\"கொலம்பியா\",\"கோஸ்டா ரிகா\",\"சவுதி அரேபியா\",\"சிங்கப்பூர்\",\"சிலி\",\"செக்கியா\",\"செர்பியா\",\"செனகல்\",\"சைப்ரஸ்\",\"டென்மார்க்\",\"டொமினிகன் குடியரசு\",\"தாய்லாந்து\",\"தான்சானியா\",\"துருக்கி\",\"துனிசியா\",\"தென் ஆப்பிரிக்கா\",\"தென்கொரியா\",\"தைவான்\",\"நார்வே\",\"நிகரகுவா\",\"நியூசிலாந்து\",\"நெதர்லாந்து\",\"நேபாளம்\",\"நைஜீரியா\",\"பங்களாதேஷ்\",\"பபுவா நியூ கினியா\",\"பராகுவே\",\"பல்கேரியா\",\"பனாமா\",\"பஹ்ரெய்ன்\",\"பாகிஸ்தான்\",\"பிரேசில்\",\"பிலிப்பைன்ஸ்\",\"புயர்டோ ரிகோ\",\"பெரு\",\"பெல்ஜியம்\",\"பெலாரஸ்\",\"பொலிவியா\",\"போர்ச்சுகல்\",\"போலந்து\",\"போஸ்னியா மற்றும் ஹெர்ஸெகோவினா\",\"மல்டோவா\",\"மலேஷியா\",\"மாண்டிநீக்ரோ\",\"மால்டா\",\"மெக்சிகோ\",\"மொராக்கோ\",\"யுனைடெட் கிங்டம்\",\"ரஷ்யா\",\"ரோமானியா\",\"லக்சம்பர்க்\",\"லாத்வியா\",\"லாவோஸ்\",\"லிச்சென்ஸ்டீன்\",\"லிதுவேனியா\",\"லிபியா\",\"லெபனான்\",\"வடக்கு மாசிடோனியா\",\"வியட்நாம்\",\"வெனிசுலா\",\"ஜப்பான்\",\"ஜமைக்கா\",\"ஜார்ஜியா\",\"ஜிம்பாப்வே\",\"ஜெர்மனி\",\"ஜோர்டான்\",\"ஸ்பெயின்\",\"ஸ்லோவேனியா\",\"ஸ்லோவோக்கியா\",\"ஸ்விட்சர்லாந்து\",\"ஸ்வீடன்\",\"ஹங்கேரி\",\"ஹாங்காங்\",\"ஹோண்டுராஸ்\"],\"codes\":[\"US\",\"IE\",\"AR\",\"DZ\",\"AZ\",\"AT\",\"AU\",\"IT\",\"IN\",\"ID\",\"LK\",\"IL\",\"EC\",\"IQ\",\"UA\",\"UG\",\"UY\",\"EG\",\"SV\",\"EE\",\"YE\",\"AE\",\"IS\",\"OM\",\"FR\",\"FI\",\"QA\",\"KH\",\"GT\",\"CA\",\"KZ\",\"GH\",\"GR\",\"HR\",\"KW\",\"KE\",\"CO\",\"CR\",\"SA\",\"SG\",\"CL\",\"CZ\",\"RS\",\"SN\",\"CY\",\"DK\",\"DO\",\"TH\",\"TZ\",\"TR\",\"TN\",\"ZA\",\"KR\",\"TW\",\"NO\",\"NI\",\"NZ\",\"NL\",\"NP\",\"NG\",\"BD\",\"PG\",\"PY\",\"BG\",\"PA\",\"BH\",\"PK\",\"BR\",\"PH\",\"PR\",\"PE\",\"BE\",\"BY\",\"BO\",\"PT\",\"PL\",\"BA\",\"MD\",\"MY\",\"ME\",\"MT\",\"MX\",\"MA\",\"GB\",\"RU\",\"RO\",\"LU\",\"LV\",\"LA\",\"LI\",\"LT\",\"LY\",\"LB\",\"MK\",\"VN\",\"VE\",\"JP\",\"JM\",\"GE\",\"ZW\",\"DE\",\"JO\",\"ES\",\"SI\",\"SK\",\"CH\",\"SE\",\"HU\",\"HK\",\"HN\"]}"
  },
  {
    "path": "static/geolocations/tr.json",
    "content": "{\"names\":[\"Almanya\",\"Amerika Birleşik Devletleri\",\"Arjantin\",\"Avustralya\",\"Avusturya\",\"Azerbaycan\",\"Bahreyn\",\"Bangladeş\",\"Belarus\",\"Belçika\",\"Birleşik Arap Emirlikleri\",\"Bolivya\",\"Bosna ve Hersek\",\"Brezilya\",\"Bulgaristan\",\"Cezayir\",\"Çekya\",\"Danimarka\",\"Dominik Cumhuriyeti\",\"Ekvador\",\"El Salvador\",\"Endonezya\",\"Estonya\",\"Fas\",\"Filipinler\",\"Finlandiya\",\"Fransa\",\"Gana\",\"Guatemala\",\"Güney Afrika\",\"Güney Kıbrıs Rum Yönetimi\",\"Güney Kore\",\"Gürcistan\",\"Hırvatistan\",\"Hindistan\",\"Hollanda\",\"Honduras\",\"Hong Kong\",\"Irak\",\"İngiltere\",\"İrlanda\",\"İspanya\",\"İsrail\",\"İsveç\",\"İsviçre\",\"İtalya\",\"İzlanda\",\"Jamaika\",\"Japonya\",\"Kamboçya\",\"Kanada\",\"Karadağ\",\"Katar\",\"Kazakistan\",\"Kenya\",\"Kolombiya\",\"Kosta Rika\",\"Kuveyt\",\"Kuzey Makedonya\",\"Laos\",\"Letonya\",\"Libya\",\"Liechtenstein\",\"Litvanya\",\"Lübnan\",\"Lüksemburg\",\"Macaristan\",\"Malezya\",\"Malta\",\"Meksika\",\"Mısır\",\"Moldova\",\"Nepal\",\"Nijerya\",\"Nikaragua\",\"Norveç\",\"Pakistan\",\"Panama\",\"Papua Yeni Gine\",\"Paraguay\",\"Peru\",\"Polonya\",\"Portekiz\",\"Porto Riko\",\"Romanya\",\"Rusya\",\"Senegal\",\"Sırbistan\",\"Singapur\",\"Slovakya\",\"Slovenya\",\"Sri Lanka\",\"Suudi Arabistan\",\"Şili\",\"Tanzanya\",\"Tayland\",\"Tayvan\",\"Tunus\",\"Türkiye\",\"Uganda\",\"Ukrayna\",\"Umman\",\"Uruguay\",\"Ürdün\",\"Venezuela\",\"Vietnam\",\"Yemen\",\"Yeni Zelanda\",\"Yunanistan\",\"Zimbabve\"],\"codes\":[\"DE\",\"US\",\"AR\",\"AU\",\"AT\",\"AZ\",\"BH\",\"BD\",\"BY\",\"BE\",\"AE\",\"BO\",\"BA\",\"BR\",\"BG\",\"DZ\",\"CZ\",\"DK\",\"DO\",\"EC\",\"SV\",\"ID\",\"EE\",\"MA\",\"PH\",\"FI\",\"FR\",\"GH\",\"GT\",\"ZA\",\"CY\",\"KR\",\"GE\",\"HR\",\"IN\",\"NL\",\"HN\",\"HK\",\"IQ\",\"GB\",\"IE\",\"ES\",\"IL\",\"SE\",\"CH\",\"IT\",\"IS\",\"JM\",\"JP\",\"KH\",\"CA\",\"ME\",\"QA\",\"KZ\",\"KE\",\"CO\",\"CR\",\"KW\",\"MK\",\"LA\",\"LV\",\"LY\",\"LI\",\"LT\",\"LB\",\"LU\",\"HU\",\"MY\",\"MT\",\"MX\",\"EG\",\"MD\",\"NP\",\"NG\",\"NI\",\"NO\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"PL\",\"PT\",\"PR\",\"RO\",\"RU\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"LK\",\"SA\",\"CL\",\"TZ\",\"TH\",\"TW\",\"TN\",\"TR\",\"UG\",\"UA\",\"OM\",\"UY\",\"JO\",\"VE\",\"VN\",\"YE\",\"NZ\",\"GR\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/uk.json",
    "content": "{\"names\":[\"Австралія\",\"Австрія\",\"Азербайджан\",\"Алжир\",\"Аргентина\",\"Бангладеш\",\"Бахрейн\",\"Бельгія\",\"Білорусь\",\"Болгарія\",\"Болівія\",\"Боснія та Герцеговина\",\"Бразилія\",\"В'єтнам\",\"Велика Британія\",\"Венесуела\",\"Гана\",\"Гватемала\",\"Гондурас\",\"Гонконг\",\"Греція\",\"Грузія\",\"Данія\",\"Домініканська Республіка\",\"Еквадор\",\"Естонія\",\"Єгипет\",\"Ємен\",\"Зімбабве\",\"Ізраїль\",\"Індія\",\"Індонезія\",\"Ірак\",\"Ірландія\",\"Ісландія\",\"Іспанія\",\"Італія\",\"Йорданія\",\"Казахстан\",\"Камбоджа\",\"Канада\",\"Катар\",\"Кенія\",\"Кіпр\",\"Колумбія\",\"Коста-Рика\",\"Кувейт\",\"Лаос\",\"Латвія\",\"Литва\",\"Ліван\",\"Лівія\",\"Ліхтенштейн\",\"Люксембург\",\"Малайзія\",\"Мальта\",\"Марокко\",\"Мексика\",\"Молдова\",\"Непал\",\"Нігерія\",\"Нідерланди\",\"Нікарагуа\",\"Німеччина\",\"Нова Зеландія\",\"Норвегія\",\"Об'єднані Арабські Емірати\",\"Оман\",\"Пакистан\",\"Панама\",\"Папуа – Нова Гвінея\",\"Парагвай\",\"Перу\",\"Південна Корея\",\"Південно-Африканська Республіка\",\"Північна Македонія\",\"Польща\",\"Португалія\",\"Пуерто-Рико\",\"Росія\",\"Румунія\",\"Сальвадор\",\"Саудівська Аравія\",\"Сенегал\",\"Сербія\",\"Сінгапур\",\"Словаччина\",\"Словенія\",\"Сполучені Штати Америки\",\"Таїланд\",\"Тайвань\",\"Танзанія\",\"Туніс\",\"Туреччина\",\"Уганда\",\"Угорщина\",\"Україна\",\"Уругвай\",\"Філіппіни\",\"Фінляндія\",\"Франція\",\"Хорватія\",\"Чехія\",\"Чилі\",\"Чорногорія\",\"Швейцарія\",\"Швеція\",\"Шрі-Ланка\",\"Ямайка\",\"Японія\"],\"codes\":[\"AU\",\"AT\",\"AZ\",\"DZ\",\"AR\",\"BD\",\"BH\",\"BE\",\"BY\",\"BG\",\"BO\",\"BA\",\"BR\",\"VN\",\"GB\",\"VE\",\"GH\",\"GT\",\"HN\",\"HK\",\"GR\",\"GE\",\"DK\",\"DO\",\"EC\",\"EE\",\"EG\",\"YE\",\"ZW\",\"IL\",\"IN\",\"ID\",\"IQ\",\"IE\",\"IS\",\"ES\",\"IT\",\"JO\",\"KZ\",\"KH\",\"CA\",\"QA\",\"KE\",\"CY\",\"CO\",\"CR\",\"KW\",\"LA\",\"LV\",\"LT\",\"LB\",\"LY\",\"LI\",\"LU\",\"MY\",\"MT\",\"MA\",\"MX\",\"MD\",\"NP\",\"NG\",\"NL\",\"NI\",\"DE\",\"NZ\",\"NO\",\"AE\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"KR\",\"ZA\",\"MK\",\"PL\",\"PT\",\"PR\",\"RU\",\"RO\",\"SV\",\"SA\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"US\",\"TH\",\"TW\",\"TZ\",\"TN\",\"TR\",\"UG\",\"HU\",\"UA\",\"UY\",\"PH\",\"FI\",\"FR\",\"HR\",\"CZ\",\"CL\",\"ME\",\"CH\",\"SE\",\"LK\",\"JM\",\"JP\"]}"
  },
  {
    "path": "static/geolocations/vi.json",
    "content": "{\"names\":[\"Ả-Rập Xê-út\",\"Ai Cập\",\"Algeria\",\"Áo\",\"Argentina\",\"Azerbaijan\",\"Ấn Độ\",\"Ba Lan\",\"Bahrain\",\"Bangladesh\",\"Bắc Macedonia\",\"Belarus\",\"Bỉ\",\"Bolivia\",\"Bosnia và Herzegovina\",\"Bồ Đào Nha\",\"Brazil\",\"Bungary\",\"Các Tiểu Vương quốc Ả Rập Thống nhất\",\"Campuchia\",\"Canada\",\"Chile\",\"Colombia\",\"Costa Rica\",\"Cộng hoà Dominica\",\"Croatia\",\"Đài Loan\",\"Đan Mạch\",\"Đảo Síp\",\"Đức\",\"Ecuador\",\"El Salvador\",\"Estonia\",\"Georgia\",\"Ghana\",\"Guatemala\",\"Hà Lan\",\"Hàn Quốc\",\"Hoa Kỳ\",\"Honduras\",\"Hồng Kông\",\"Hungary\",\"Hy Lạp\",\"Iceland\",\"Indonesia\",\"Iraq\",\"Ireland\",\"Israel\",\"Jamaica\",\"Jordan\",\"Kazakhstan\",\"Kenya\",\"Kuwait\",\"Lào\",\"Latvia\",\"Lebanon\",\"Libya\",\"Liechtenstein\",\"Lithuania\",\"Luxembourg\",\"Ma-rốc\",\"Malaysia\",\"Malta\",\"Mexico\",\"Moldova\",\"Montenegro\",\"Na Uy\",\"Nam Phi\",\"Nepal\",\"New Zealand\",\"Nga\",\"Nhật Bản\",\"Nicaragua\",\"Nigeria\",\"Oman\",\"Pakistan\",\"Panama\",\"Papua New Guinea\",\"Paraguay\",\"Peru\",\"Pháp\",\"Phần Lan\",\"Philipin\",\"Puerto Rico\",\"Qatar\",\"Rumani\",\"Séc\",\"Senegal\",\"Serbia\",\"Singapore\",\"Slovakia\",\"Slovenia\",\"Sri Lanka\",\"Tanzania\",\"Tây Ban Nha\",\"Thái Lan\",\"Thổ Nhĩ Kỳ\",\"Thuỵ Điển\",\"Thuỵ Sĩ\",\"Tunisia\",\"Úc\",\"Uganda\",\"Ukraina\",\"Uruguay\",\"Venezuela\",\"Việt Nam\",\"Vương quốc Anh\",\"Ý\",\"Yemen\",\"Zimbabwe\"],\"codes\":[\"SA\",\"EG\",\"DZ\",\"AT\",\"AR\",\"AZ\",\"IN\",\"PL\",\"BH\",\"BD\",\"MK\",\"BY\",\"BE\",\"BO\",\"BA\",\"PT\",\"BR\",\"BG\",\"AE\",\"KH\",\"CA\",\"CL\",\"CO\",\"CR\",\"DO\",\"HR\",\"TW\",\"DK\",\"CY\",\"DE\",\"EC\",\"SV\",\"EE\",\"GE\",\"GH\",\"GT\",\"NL\",\"KR\",\"US\",\"HN\",\"HK\",\"HU\",\"GR\",\"IS\",\"ID\",\"IQ\",\"IE\",\"IL\",\"JM\",\"JO\",\"KZ\",\"KE\",\"KW\",\"LA\",\"LV\",\"LB\",\"LY\",\"LI\",\"LT\",\"LU\",\"MA\",\"MY\",\"MT\",\"MX\",\"MD\",\"ME\",\"NO\",\"ZA\",\"NP\",\"NZ\",\"RU\",\"JP\",\"NI\",\"NG\",\"OM\",\"PK\",\"PA\",\"PG\",\"PY\",\"PE\",\"FR\",\"FI\",\"PH\",\"PR\",\"QA\",\"RO\",\"CZ\",\"SN\",\"RS\",\"SG\",\"SK\",\"SI\",\"LK\",\"TZ\",\"ES\",\"TH\",\"TR\",\"SE\",\"CH\",\"TN\",\"AU\",\"UG\",\"UA\",\"UY\",\"VE\",\"VN\",\"GB\",\"IT\",\"YE\",\"ZW\"]}"
  },
  {
    "path": "static/geolocations/zh-CN.json",
    "content": "{\"names\":[\"阿尔及利亚\",\"阿根廷\",\"阿拉伯联合酋长国\",\"阿曼\",\"阿塞拜疆\",\"埃及\",\"爱尔兰\",\"爱沙尼亚\",\"奥地利\",\"澳大利亚\",\"巴布亚新几内亚\",\"巴基斯坦\",\"巴拉圭\",\"巴林\",\"巴拿马\",\"巴西\",\"白俄罗斯\",\"保加利亚\",\"北马其顿\",\"比利时\",\"冰岛\",\"波多黎各\",\"波兰\",\"波斯尼亚和黑塞哥维那\",\"玻利维亚\",\"丹麦\",\"德国\",\"多米尼加共和国\",\"俄罗斯\",\"厄瓜多尔\",\"法国\",\"菲律宾\",\"芬兰\",\"哥伦比亚\",\"哥斯达黎加\",\"格鲁吉亚共和国\",\"哈萨克斯坦\",\"韩国\",\"荷兰\",\"黑山共和国\",\"洪都拉斯\",\"加拿大\",\"加纳\",\"柬埔寨\",\"捷克\",\"津巴布韦\",\"卡塔尔\",\"科威特\",\"克罗地亚\",\"肯尼亚\",\"拉脱维亚\",\"老挝\",\"黎巴嫩\",\"立陶宛\",\"利比亚\",\"列支敦士登\",\"卢森堡公国\",\"罗马尼亚\",\"马耳他\",\"马来西亚\",\"美国\",\"孟加拉国\",\"秘鲁\",\"摩尔多瓦\",\"摩洛哥\",\"墨西哥\",\"南非\",\"尼加拉瓜\",\"尼泊尔\",\"尼日利亚\",\"挪威\",\"葡萄牙\",\"日本\",\"瑞典\",\"瑞士\",\"萨尔瓦多\",\"塞尔维亚\",\"塞内加尔\",\"塞浦路斯\",\"沙特阿拉伯\",\"斯里兰卡\",\"斯洛伐克\",\"斯洛文尼亚\",\"台湾\",\"泰国\",\"坦桑尼亚\",\"突尼斯\",\"土耳其\",\"危地马拉\",\"委内瑞拉\",\"乌干达\",\"乌克兰\",\"乌拉圭\",\"西班牙\",\"希腊\",\"香港\",\"新加坡\",\"新西兰\",\"匈牙利\",\"牙买加\",\"也门\",\"伊拉克\",\"以色列\",\"意大利\",\"印度\",\"印尼\",\"英国\",\"约旦\",\"越南\",\"智利\"],\"codes\":[\"DZ\",\"AR\",\"AE\",\"OM\",\"AZ\",\"EG\",\"IE\",\"EE\",\"AT\",\"AU\",\"PG\",\"PK\",\"PY\",\"BH\",\"PA\",\"BR\",\"BY\",\"BG\",\"MK\",\"BE\",\"IS\",\"PR\",\"PL\",\"BA\",\"BO\",\"DK\",\"DE\",\"DO\",\"RU\",\"EC\",\"FR\",\"PH\",\"FI\",\"CO\",\"CR\",\"GE\",\"KZ\",\"KR\",\"NL\",\"ME\",\"HN\",\"CA\",\"GH\",\"KH\",\"CZ\",\"ZW\",\"QA\",\"KW\",\"HR\",\"KE\",\"LV\",\"LA\",\"LB\",\"LT\",\"LY\",\"LI\",\"LU\",\"RO\",\"MT\",\"MY\",\"US\",\"BD\",\"PE\",\"MD\",\"MA\",\"MX\",\"ZA\",\"NI\",\"NP\",\"NG\",\"NO\",\"PT\",\"JP\",\"SE\",\"CH\",\"SV\",\"RS\",\"SN\",\"CY\",\"SA\",\"LK\",\"SK\",\"SI\",\"TW\",\"TH\",\"TZ\",\"TN\",\"TR\",\"GT\",\"VE\",\"UG\",\"UA\",\"UY\",\"ES\",\"GR\",\"HK\",\"SG\",\"NZ\",\"HU\",\"JM\",\"YE\",\"IQ\",\"IL\",\"IT\",\"IN\",\"ID\",\"GB\",\"JO\",\"VN\",\"CL\"]}"
  },
  {
    "path": "static/geolocations/zh-TW.json",
    "content": "{\"names\":[\"土耳其\",\"丹麥\",\"厄瓜多\",\"巴布亞紐幾內亞\",\"巴西\",\"巴拉圭\",\"巴林\",\"巴拿馬\",\"巴基斯坦\",\"日本\",\"比利時\",\"牙買加\",\"以色列\",\"加拿大\",\"北馬其頓\",\"卡達\",\"台灣\",\"尼加拉瓜\",\"尼泊爾\",\"瓜地馬拉\",\"白俄羅斯\",\"立陶宛\",\"伊拉克\",\"冰島\",\"列支敦士登\",\"匈牙利\",\"印尼\",\"印度\",\"多明尼加共和國\",\"西班牙\",\"克羅埃西亞\",\"利比亞\",\"宏都拉斯\",\"希臘\",\"沙烏地阿拉伯\",\"辛巴威\",\"亞賽拜然\",\"坦尚尼亞\",\"奈及利亞\",\"委內瑞拉\",\"孟加拉\",\"拉脫維亞\",\"法國\",\"波士尼亞-赫塞哥維納\",\"波多黎克\",\"波蘭\",\"肯亞\",\"芬蘭\",\"阿拉伯聯合大公國\",\"阿根廷\",\"阿曼\",\"阿爾及利亞\",\"俄羅斯\",\"保加利亞\",\"南非\",\"南韓\",\"哈薩克\",\"柬埔寨\",\"玻利維亞\",\"科威特\",\"突尼西亞\",\"約旦\",\"美國\",\"英國\",\"迦納\",\"香港\",\"哥倫比亞\",\"哥斯大黎加\",\"埃及\",\"挪威\",\"泰國\",\"烏干達\",\"烏克蘭\",\"烏拉圭\",\"秘魯\",\"紐西蘭\",\"馬來西亞\",\"馬爾他\",\"捷克\",\"荷蘭\",\"喬治亞\",\"斯里蘭卡\",\"斯洛伐克\",\"斯洛維尼亞\",\"智利\",\"菲律賓\",\"越南\",\"塞內加爾\",\"塞爾維亞\",\"奧地利\",\"愛沙尼亞\",\"愛爾蘭\",\"新加坡\",\"瑞士\",\"瑞典\",\"義大利\",\"葉門\",\"葡萄牙\",\"蒙特內哥羅\",\"寮國\",\"德國\",\"摩洛哥\",\"摩爾多瓦\",\"黎巴嫩\",\"墨西哥\",\"澳洲\",\"盧森堡\",\"賽普勒斯\",\"薩爾瓦多\",\"羅馬尼亞\"],\"codes\":[\"TR\",\"DK\",\"EC\",\"PG\",\"BR\",\"PY\",\"BH\",\"PA\",\"PK\",\"JP\",\"BE\",\"JM\",\"IL\",\"CA\",\"MK\",\"QA\",\"TW\",\"NI\",\"NP\",\"GT\",\"BY\",\"LT\",\"IQ\",\"IS\",\"LI\",\"HU\",\"ID\",\"IN\",\"DO\",\"ES\",\"HR\",\"LY\",\"HN\",\"GR\",\"SA\",\"ZW\",\"AZ\",\"TZ\",\"NG\",\"VE\",\"BD\",\"LV\",\"FR\",\"BA\",\"PR\",\"PL\",\"KE\",\"FI\",\"AE\",\"AR\",\"OM\",\"DZ\",\"RU\",\"BG\",\"ZA\",\"KR\",\"KZ\",\"KH\",\"BO\",\"KW\",\"TN\",\"JO\",\"US\",\"GB\",\"GH\",\"HK\",\"CO\",\"CR\",\"EG\",\"NO\",\"TH\",\"UG\",\"UA\",\"UY\",\"PE\",\"NZ\",\"MY\",\"MT\",\"CZ\",\"NL\",\"GE\",\"LK\",\"SK\",\"SI\",\"CL\",\"PH\",\"VN\",\"SN\",\"RS\",\"AT\",\"EE\",\"IE\",\"SG\",\"CH\",\"SE\",\"IT\",\"YE\",\"PT\",\"ME\",\"LA\",\"DE\",\"MA\",\"MD\",\"LB\",\"MX\",\"AU\",\"LU\",\"CY\",\"SV\",\"RO\"]}"
  },
  {
    "path": "static/invidious-instances.json",
    "content": "[\n  {\n    \"url\": \"https://iv.ggtyler.dev\",\n    \"cors\": true\n  },\n  {\n    \"url\": \"https://invidious.nerdvpn.de\",\n    \"cors\": true\n  },\n  {\n    \"url\": \"https://inv.nadeko.net\",\n    \"cors\": false\n  },\n  {\n    \"url\": \"https://invidious.jing.rocks\",\n    \"cors\": true\n  },\n  {\n    \"url\": \"https://invidious.perennialte.ch\",\n    \"cors\": true\n  },\n  {\n    \"url\": \"https://invidious.reallyaweso.me\",\n    \"cors\": false\n  },\n  {\n    \"url\": \"https://invidious.privacyredirect.com\",\n    \"cors\": true\n  }\n]"
  },
  {
    "path": "static/locales/activeLocales.json",
    "content": "[\n  \"en-US\",\n  \"en-GB\",\n  \"ar\",\n  \"be\",\n  \"bg\",\n  \"br\",\n  \"ca\",\n  \"cs\",\n  \"cy\",\n  \"da\",\n  \"de-DE\",\n  \"el\",\n  \"es\",\n  \"es-AR\",\n  \"es-MX\",\n  \"et\",\n  \"eu\",\n  \"fa\",\n  \"fi\",\n  \"fr-FR\",\n  \"gl\",\n  \"he\",\n  \"hu\",\n  \"hr\",\n  \"id\",\n  \"is\",\n  \"it\",\n  \"ja\",\n  \"ko\",\n  \"lt\",\n  \"nb-NO\",\n  \"nl\",\n  \"nn\",\n  \"pl\",\n  \"pt\",\n  \"pt-BR\",\n  \"pt-PT\",\n  \"ro\",\n  \"ru\",\n  \"sk\",\n  \"sl\",\n  \"sr\",\n  \"sv\",\n  \"ta\",\n  \"tr\",\n  \"uk\",\n  \"vi\",\n  \"zh-CN\",\n  \"zh-TW\"\n]\n"
  },
  {
    "path": "static/locales/af.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Afrikaans'\n\n# Webkit Menu Bar\nFile: 'Lêer'\nNew Window: 'Nuwe Venster'\nPreferences: 'Voorkeure'\nQuit: 'Sluit'\nEdit: 'Wysig'\nUndo: 'Ontdoen'\nRedo: 'doen oor'\nCut: 'knip'\nCopy: 'Kopieer'\nPaste: 'Plak'\nDelete: 'Verwyder'\nSelect all: 'Kies alles'\nToggle Developer Tools: 'Wissel Ontwikkelaar Gereedskap'\nActual size: 'Werklike grootte'\nZoom in: 'Zoom in'\nZoom out: 'Zoom uit'\nToggle fullscreen: 'Wissel na volle skerm'\nWindow: 'Venster'\nMinimize: 'Minimaliseer'\nClose: 'suilt'\nBack: 'Terug'\nForward: 'vorentoe'\nOpen New Window: 'Maak nuwe venster oop'\nGo to page: 'Gaan na {page}'\nClose Banner: 'Sluit baniere'\n\nVersion {versionNumber} is now available!  Click for more details: 'Weergawe {versionNumber} is nou beskikbaar! Klik vir meer besonderhede'\nDownload From Site: 'Laai af van die webwerf'\nA new blog is now available, {blogTitle}. Click to view more: '''n Nuwe blog is nou beskikbaar, {blogTitle}. Klik om meer te sien'\nAre you sure you want to open this link?: 'Is jy seker jy wil hierdie skakel oopmaak?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video''s'\n  Shorts: 'Kortvideo’s'\n  Live: 'Regstreeks'\n  Posts: 'Plasings'\n  Sort By: 'Sorteer volgens'\n  Counts:\n    Video Count: '1 video | {count} videos'\n    Channel Count: '1 kanaal | {count} kanale'\n    Subscriber Count: '1 intekenaar | {count} intekenaars'\n    View Count: '1 kyk | {count} kyke'\n    Watching Count: '1 kyk | {count} kyk'\n\n# Search Bar\n    Like Count: 1 hou van | {count} hou van'e\n    Comment Count: 1 opmerking | {count} opmerkings\nSearch / Go to URL: 'Soek / Gaan na URL'\nSearch Bar:\n  Clear Input: 'Maak invoer skoon'\n  Remove: Verwyder\nSearch character limit: 'soek'\nSearch Listing:\n  Label:\n    4K: '4K'\n    Subtitles: 'Onderskrifte'\n    # Aria labels\n    Closed Captions: 'Geslote onderskrifte'\n  # In Filter Button\n    VR180: VR180\n    360 Video: 360°\n    New: Nuut\n    3D: 3D\n    8K: 8K\nSearch Filters:\n  Search Filters: 'Soekfilters'\n  Sort By:\n    Most Relevant: 'Mees relevant'\n    Rating: 'Gradering'\n    Upload Date: 'Oplaaddatum'\n    View Count: 'Beskouingsaantal'\n  Time:\n    Time: 'Tyd'\n    Any Time: 'Enige tyd'\n    Last Hour: 'Laaste uur'\n    Today: 'Vandag'\n    This Week: 'Hierdie week'\n    This Month: 'Hierdie maand'\n    This Year: 'Hierdie jaar'\n  Type:\n    Type: 'Tipe'\n    All Types: 'Alle tipes'\n    Videos: 'Video''s'\n    Channels: 'Kanale'\n    Movies: 'Rolprente'\n    #& Playlists\n  Duration:\n    Duration: 'Duur'\n    All Durations: 'Alle durasies'\n    Short (< 4 minutes): 'Kort (<4 minute)'\n    Medium (4 - 20 minutes): 'Medium (4 - 20 minute)'\n    Long (> 20 minutes): 'Lank (> 20 minute)'\n  Features:\n    Features: 'Funksies'\n    HD: 'HD'\n    Subtitles: 'Onderskrifte'\n    Creative Commons: 'Creative-Commons'\n    3D: '3D'\n    Live: ''\n    4K: ''\n    360 Video: ''\n    Location: ''\n    HDR: ''\n    VR180: ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: 'Meer'\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Trending Tabs: ''\n  Sports: Sport\nMost Popular: 'Mees Populêr'\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: 'Val terug op nie-voorkeur agterent by faling'\n    Enable Search Suggestions: 'Aktiveer soekvoorstelle'\n    Auto Load Next Page:\n      Label: 'Outolaai volgende blad'\n      Tooltip: 'Laai bykomende blaaie en kommentaar outomaties.'\n    Default Landing Page: 'Versteklandingsblad'\n    Locale Preference: 'Lokale voorkeur'\n    System Default: 'Stelselverstek'\n    Preferred API Backend:\n      Preferred API Backend: 'Voorkeur-API-agterent'\n      Local API: 'Lokale API'\n      Invidious API: 'Invidious-API'\n    Video View Type:\n      Video View Type: 'Video-aansigtipe'\n      Grid: 'Rooster'\n      List: 'Lys'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Duimnaelvoorkeur'\n      Default: 'Verstek'\n      Beginning: 'Begin'\n      Middle: 'Middel'\n      End: 'Einde'\n      Hidden: 'Versteek'\n      Blur: 'Vervaag'\n    Current Invidious Instance: 'Huidige Invidious-instansie'\n    The currently set default instance is {instance}: '{instance} is tans die verstekinstansie'\n    No default instance has been set: 'Geen verstekinstansie is ingestel nie'\n    Current instance will be randomized on startup: 'Huidige instansie sat by begin willekeurig gekies word'\n    Set Current Instance as Default: 'Stel huidige instansie in as verstek'\n    Clear Default Instance: 'Wis verstekinstansie'\n    View all Invidious instance information: 'Bekyk alle Invidious-instansie-inligting'\n    Region for Trending: 'Streek vir stygend'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Hantering van eksterne skakel'\n      Open Link: 'Open skakel'\n      Ask Before Opening Link: 'Vra voordat skakel geopen word'\n      No Action: 'Geen aksie'\n    Open Deep Links In New Window: Open URL’s na FreeTube gestuur in ’n nuwe venster\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Gebruik primêre temakleur vir boonste balk'\n    Expand Side Bar by Default: 'Vou systaaf by verstek uit'\n    Disable Smooth Scrolling: 'Deaktiveer vloeiende rol'\n    UI Scale: 'Koppelvlakskaal'\n    Hide Side Bar Labels: 'Versteek systaafetikette'\n    Hide FreeTube Header Logo: 'Versteek FreeTube-koplogo'\n    Base Theme:\n      Base Theme: 'Basistema'\n      Black: 'Swart'\n      Dark: 'Donker'\n      System Default: 'Stelselverstek'\n      Light: 'Lig'\n      Dracula: 'Dracula'\n      Catppuccin Mocha: 'Catppuccin Mocha'\n      Pastel Pink: 'Pastelpienk'\n      Hot Pink: 'Helderpienk'\n      Nordic: 'Noors'\n      Solarized Dark: 'Gesolariseerde donker'\n      Solarized Light: 'Gesolariseerde lig'\n      Everforest Dark Hard: Everforest Donker hard\n      Everforest Dark Medium: Everforest Donker medium\n      Everforest Light Low: Everforest Lig laag\n      Everforest Light Hard: Everforest Lig hard\n      Everforest Dark Low: Everforest Donker laag\n      Everforest Light Medium: Everforest Lig medium\n      Gruvbox Dark: Gruvboxx donker\n      Gruvbox Light: Gruvbox lig\n      Catppuccin Frappe: Catppuccin Frappe\n    Main Color Theme:\n      Main Color Theme: 'Primêre kleurtema'\n      Red: 'Rooi'\n      Pink: 'Pienk'\n      Purple: 'Pers'\n      Deep Purple: 'Donkerpers'\n      Indigo: 'Indigo'\n      Blue: 'Blou'\n      Light Blue: 'Ligblou'\n      Cyan: 'Siaan'\n      Teal: 'Blougroen'\n      Green: 'Groen'\n      Light Green: 'Liggroen'\n      Lime: 'Lemmetjie'\n      Yellow: 'Geel'\n      Amber: 'Amber'\n      Orange: 'Oranje'\n      Deep Orange: 'Donkeroranje'\n      Dracula Cyan: 'Dracula-siaan'\n      Dracula Green: 'Dracula-groen'\n      Dracula Orange: 'Dracula-oranje'\n      Dracula Pink: 'Dracula-pienk'\n      Dracula Purple: 'Dracula-pers'\n      Dracula Red: 'Dracula-rooi'\n      Dracula Yellow: 'Dracula-geel'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mokka Rooswater'\n      Catppuccin Mocha Flamingo: 'Catppuccin Mokka Flamingo'\n      Catppuccin Mocha Pink: 'Catppuccin Mocha Pienk'\n      Catppuccin Mocha Mauve: 'Catppuccin Mokka Mauve'\n      Catppuccin Mocha Red: 'Catppuccin Mokka Rooi'\n      Catppuccin Mocha Maroon: 'Catppuccin mokka Kastanjebruin'\n      Catppuccin Mocha Peach: 'Catppuccin Mokka Perske'\n      Catppuccin Mocha Yellow: 'Catppuccin Mokka Geel'\n      Catppuccin Mocha Green: 'Catppuccin Mokka Groen'\n      Catppuccin Mocha Teal: 'Catppuccin Mokka Blougroen'\n      Catppuccin Mocha Sky: 'Catppuccin Mokka Lugblou'\n      Catppuccin Mocha Sapphire: 'Catppuccin Mokka Saffier'\n      Catppuccin Mocha Blue: 'Catppuccin Mocha Blou'\n      Catppuccin Mocha Lavender: 'Catppuccin Mocha Laventel'\n      Solarized Yellow: 'Sonbeligte geel'\n      Solarized Orange: 'Sonbeligte oranje'\n      Solarized Red: 'Sonbeligte rooi'\n      Solarized Magenta: 'Sonbeligte magenta'\n      Solarized Violet: 'Sonbeligte violet'\n      Solarized Blue: 'Sonbeligte blou'\n      Solarized Cyan: 'Sonbeligte siaan'\n      Solarized Green: 'Sonbeligte groen'\n      Gruvbox Light Orange: Gruvbox ligoranje\n      Gruvbox Dark Purple: Gruvbox donkerpers\n      Gruvbox Dark Aqua: Gruvbox donkerakwa\n      Gruvbox Dark Orange: Gruvbox donkeroranje\n      Gruvbox Light Red: Gruvbox ligrooi\n      Gruvbox Light Blue: Gruvbox ligblou\n      Gruvbox Light Purple: Gruvbox ligpers\n      Catppuccin Frappe Blue: Catppuccin Frappe Blou\n      Gruvbox Dark Green: Gruvbox Donkergroen\n      Gruvbox Dark Blue: Gruvbox Donkerblou\n      Catppuccin Frappe Pink: Catppuccin Frappe Pienk\n      Catppuccin Frappe Red: Catppuccin Frappe Rooi\n      Catppuccin Frappe Teal: Catppuccin Frappe Blougroen\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Saffier\n      Everforest Dark Purple: Everforest Donkerpers\n      Everforest Light Red: Everforest Ligrooi\n      Everforest Light Orange: Everforest Ligoranje\n      Everforest Light Yellow: Everforest Liggeel\n      Everforest Light Aqua: Everforest Ligakwa\n      Everforest Light Blue: Everforest Ligblou\n      Everforest Light Purple: Everforest Ligpers\n      Everforest Dark Orange: Everforest Donkeroranje\n      Catppuccin Frappe Sky: Catppuccin Frappe Lugblou\n      Everforest Dark Aqua: Everforest Donkerakwa\n      Catppuccin Frappe Lavender: Catppuccin Frappe Laventel\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rooswater\n      Everforest Dark Red: Everforest Ronkerrooi\n      Everforest Dark Yellow: Everforest Donkergeel\n      Everforest Dark Green: Everforest Donkergroen\n      Everforest Dark Blue: Everforest Donkerblou\n      Everforest Light Green: Everforest Liggroen\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Yellow: Catppuccin Frappe Geel\n      Catppuccin Frappe Peach: Catppuccin Frappe Perske\n      Catppuccin Frappe Maroon: Catppuccin Frappe Kastanjebruin\n      Catppuccin Frappe Green: Catppuccin Frappe Groen\n      Gruvbox Dark Yellow: Gruvbox Donkergeel\n    Secondary Color Theme: 'Sekondêre kleurtema'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'Speler'\n    Play Next Video: 'Speel aanbevole video’s outomaties af'\n    Turn on Subtitles by Default: 'Aktiveer onderskrifte by verstek'\n    Autoplay Videos: 'Begin video’s outomaties'\n    Proxy Videos Through Invidious: 'Speel videos d.m.v. Invidious-proksie af'\n    Autoplay Playlists: 'Speel video’s in afspeellys outomaties af'\n    Enable Theatre Mode by Default: ''\n    Scroll Volume Over Video Player: 'Verander volume deur in die videobeeld te rol'\n    Scroll Playback Rate Over Video Player: 'Bepaal afspeelsnelheid deur in die videobeeld te rol'\n    Skip by Scrolling Over Video Player: 'Slaan oor deur in die videospeler te rol'\n    Display Play Button In Video Player: 'Toon afspeelknop in videospeler'\n    Enter Fullscreen on Display Rotate: 'Betree volskerm wanneer skerm gedraai word'\n    Next Video Interval: 'Outo-afspeelafteller'\n    Fast-Forward / Rewind Interval: 'Vorentoe-/Terugspoelinterval'\n    Default Volume: 'Verstekvolume'\n    Default Playback Rate: 'Verstekafspeelsnelheid'\n    Max Video Playback Rate: 'Maksimum video-afspeelsnelheid'\n    Video Playback Rate Interval: 'Video-afspeelsnelheidinterval'\n    Default Video Format:\n      Default Video Format: 'Verstekvideoformaat'\n      Dash Formats: 'DASH-formate'\n      Legacy Formats: 'Verouderde formate'\n      Audio Formats: 'Oudioformate'\n    Default Quality:\n      Default Quality: 'Verstekkwaliteit'\n      Auto: 'Outomaties'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: 'Aktiveer skermkiekie'\n      Format Label: 'Skermkiekieformaat'\n      Quality Label: 'Skermkiekiekwaliteit'\n      Ask Path: 'Vra watter vouer om in te bewaar'\n      Folder Label: 'Skermkiekievouer'\n      Folder Button: 'Kies vouer'\n      File Name Label: 'Lêernaampatroon'\n      File Name Tooltip: 'U kan die volgende veranderlike gebruik; %Y viersyferjaartal, %M tweesyvermaandtal, %D tweesyferdagtal, %H tweesyferuurtal, %N tweesyferminuuttal, %S tweesefersekondetal, %T driesyfermillisekondtal, %s tweesyfervideosekond, %t driesyfervideomillisekond, %i video-ID.'\n      Error:\n        Forbidden Characters: 'Ontoelaatbare karakters'\n        Empty File Name: 'Leë lêernaam'\n    Autoplay Interruption Timer: Outo-afspeel-steurteller\n    Default Viewing Mode:\n      Theater: Teater\n      Default Viewing Mode: Verstekkykmodus\n      Full Screen: Volskerm\n      Picture in Picture: Beeld-in-beeld\n      External Player: Eksterne speler ({externalPlayerName})\n  External Player Settings:\n    External Player Settings: 'Eksterne speler'\n    External Player: 'Eksterne speler'\n    Ignore Unsupported Action Warnings: 'Ignoreer waarskuwings vir nie-ondersteunde aksies'\n    Ignore Default Arguments: 'Ignoreer verstekargumente'\n    Custom External Player Executable: 'Stel uitvoerbare lêer van eksterne videospeler in'\n    Custom External Player Arguments: 'Aangepaste argumente vir eksterne videospeler'\n    Players:\n      None:\n        Name: 'Geen'\n  Privacy Settings:\n    Privacy Settings: 'Privaatheid'\n    Remember History: 'Onthou kykgeskiedenis'\n    Save Watched Progress: 'Bewaar videovoortgang'\n    Save Watched Videos With Last Viewed Playlist: 'Hou gekykte video’s by met die afspeellys ‘Laaste gekyk’'\n    Clear Search Cache: ''\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: ''\n    Remove Watch History: 'Verwyder kykgeskiedenis'\n    Are you sure you want to remove your entire watch history?: 'Is u seker u wil u hele kykgeskiedenis verwyder?'\n    Watch history has been cleared: 'Kykgeskiedenis is gewis'\n    Remove All Subscriptions / Profiles: 'Verwyder alle intekeninge / profiele'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Is u seker u wil alle intekeninge en proviele verwyder?  Dit kan nie ontdaan word nie.'\n    Remove All Playlists: 'Verwyder alle afspeellyste'\n    All playlists have been removed: 'Alle afspeellyste is verwyder'\n    Are you sure you want to remove all your playlists?: 'Is u seker u wil alle afspeellyste verwyder?'\n    Are you sure you want to clear out your search history and cache?: Is u seker u wil u soekgeskiedenis en kasgeheue wis?\n    Search history and cache have been cleared: Soekgeskiedenis en kasgeheue is gewis\n    Remember Search History: Onthou soekgeskiedenis\n    Clear Search History and Cache: Wis soekgeskiedenis en kasgeheue\n  Subscription Settings:\n    Subscription Settings: 'Intekening'\n    Fetch Feeds from RSS: 'Haal voer vanaf RSS op'\n    Fetch Automatically: 'Haal voer outomaties op'\n    Confirm Before Unsubscribing: 'Bevestig voor uittekening'\n    'Limit the number of videos displayed for each channel': Beperk die aantal video’s wat vir elke kanaal vertoon word\n    To: tot\n  Distraction Free Settings:\n    Distraction Free Settings: 'Afleidingsvry'\n    Sections:\n      Side Bar: 'Systaaf'\n      Subscriptions Page: 'Intekenblad'\n      Channel Page: 'Kanaalblad'\n      Watch Page: 'Kykblad'\n      General: 'Algemeen'\n    Hide Video Views: 'Versteek video-kyke'\n    Hide Video Likes And Dislikes: 'Versteek Hou van en Hou nie van'\n    Hide Channel Subscribers: 'Versteek kanaalintekenare'\n    Hide Comment Likes: 'Versteek Hou van op kommentare'\n    Hide Recommended Videos: 'Versteek aanbevolde video’s'\n    Hide Trending Videos: 'Versteek stygende video’s'\n    Hide Popular Videos: 'Versteek gewilde video’s'\n    Hide Playlists: 'Versteek afspeellyste'\n    Hide Live Chat: 'Versteek regstreekse klets'\n    Hide Active Subscriptions: 'Versteek aktiewe intekeninge'\n    Hide Video Description: 'Versteek videobeskrywing'\n    Hide Comments: 'Versteek kommentaar'\n    Hide Profile Pictures in Comments: 'Versteek profielprente in kommentaar'\n    Display Titles Without Excessive Capitalisation: 'Toon titels sonder oormatige hooflettergebruik en interpunksie'\n    Hide Live Streams: 'Versteek direkte strome'\n    Hide Upcoming Premieres: 'Versteek komende premières'\n    Hide Sharing Actions: 'Versteek deel-aksies'\n    Hide Videos on Watch: 'Versteek alle gekykte video’s'\n    Hide Chapters: 'Versteek hoofstukke'\n    Hide Channels: 'Versteek video’s van kanale'\n    Hide Channels Disabled Message: 'Sommige kanale is met ID versper en is nie verwerk nie. Funksie is versper terwyl daardie ID’s bygewerk word'\n    Hide Channels Placeholder: 'Kanaal-ID'\n    Hide Channels Invalid: 'Gegewe kanaal-ID is ongeldig'\n    Hide Channels API Error: 'Fout by die ophaal van gebruiker met die gegewe ID. Gaan weer na of die ID korrek is.'\n    Hide Channels Already Exists: 'Kanaal-ID bestaan reeds'\n    Hide Featured Channels: 'Versteek uitgeligte kanale'\n    Hide Channel Playlists: 'Versteek kanaal-“afspeellys”-oortjie'\n    Hide Channel Shorts: 'Versteek kanaal-“kortvideo’s”-oortjie'\n    Hide Channel Podcasts: 'Versteek kanaal-“podsendings”-oortjie'\n    Hide Channel Releases: 'Versteek kanaal-“vrystellings”-oortjie'\n    Hide Videos, Playlists and Channels Containing Text: 'Versteek video’s en afspeellyste wat teks bevat'\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 'Woord, woordfragment of frase'\n    Hide Subscriptions Videos: 'Versteek intekenings video’s'\n    Hide Subscriptions Shorts: 'Versteek intekenings kortvideo’s'\n    Hide Subscriptions Live: 'Versteek intekenings regstreeks'\n    Show Added Items: Toon toegevoegde items\n    Hide Channel Home: Versteek kanaal-“tuis”-oortjie\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Kies uitstuurtipe'\n    Import Subscriptions: 'Voer intekenings in'\n    Subscription File: 'Intekeninglêer'\n    History File: 'Geskiedenislêer'\n    Playlist File: 'Afspeellyslêer'\n    Export Subscriptions: 'Stuur intekenings uit'\n    Export FreeTube: 'Stuur FreeTube uit'\n    Export YouTube: 'Stuur YouTube uit'\n    Export NewPipe: 'Stuur NewPipe uit'\n    Import History: 'Voer geskiedenis in'\n    Export History: 'Stuur geskiedenis uit'\n    Import Playlists: 'Voer afspeellyste in'\n    Export Playlists: 'Stuur afspeellyste uit'\n    Export Playlists For Older FreeTube Versions:\n      Label: 'Stuur afspeellyste uit vir ouer FreeTube-weergawes'\n      # |- = Keep newlines, No newline at end\n      Tooltip: |-\n        Hierdie opsie stuur video’s van alle afspeel­lyste uit na een afspeel­lys genaamd ‘Gunstelinge’.\n        Uitstuur en invoer van video’s in afspeel­lyste vir ’n ouer weergawe van FreeTube:\n        1. Stuur u afspeel­lyste uit met hierdie opsie geaktiveer.\n        2. Verwyder al u bestaande afspeel­lyste met die opsie ‘Verwyder alle afspeel­lyste’ onder ‘Privaatheids­instellings’.\n         3. Begin die ouer weergawe van FreeTube en ivoer die uitgestuurde afspeel­lyste in.\n    Profile object has insufficient data, skipping item: 'Profielobjek het onvoldoende data, item word oorgeslaan'\n    All subscriptions and profiles have been successfully imported: 'Alle intekenings en profiele is suksesvol ingevoer'\n    All subscriptions have been successfully imported: 'Alle intekenings is suksesvol ingevoer'\n    Invalid subscriptions file: 'Ongeldige intekenings-lêer'\n    Invalid history file: 'Ongeldige geskiedenislêer'\n    Subscriptions have been successfully exported: 'Intekenings is suksesvol uitgestuur'\n    History object has insufficient data, skipping item: 'Geskiedenisobjek het onvoldoende data, item word oorgeslaan'\n    All watched history has been successfully imported: 'Alle gekykte geskiedenis is suksesvol ingevoer'\n    All watched history has been successfully exported: 'Alle gekykte geskiedenis is suksesvol uitgestuur'\n    Playlist insufficient data: 'Onvoldoende data vir “{playlist}”-afspeellys, item word oorgeslaan'\n    All playlists has been successfully imported: 'Alle afspeellyste is suksesvol ingevoer'\n    All playlists has been successfully exported: 'Alle afspeellyste is suksesvol uitgestuur'\n    Unable to read file: 'Kan nie lêer lees nie'\n    Unable to write file: 'Kan nie lêer skryf nie'\n    Unknown data key: 'Onbekende datasleutel'\n    How do I import my subscriptions?: 'Hoe voer ek my intekeninge in?'\n    Manage Subscriptions: 'Bestuur intekeninge'\n  Proxy Settings:\n    Proxy Settings: 'Instaanbediener'\n    Enable Tor / Proxy: 'Aktiveer Tor / Instaanbediener'\n    Proxy Protocol: 'Instaanbedienerprotokol'\n    Proxy Host: 'Instaangasheer'\n    Proxy Port Number: 'Instaanpoortnommer'\n    Clicking on Test Proxy will send a request to: 'Deur op Toets instaanbediener te klik word ’n versoek verstuur na'\n    Test Proxy: 'Toets instaanbediener'\n    Your Info: 'U inligting'\n    Ip: 'IP'\n    Country: 'Land'\n    Region: 'Streek'\n    City: 'Stad'\n    Error getting network information. Is your proxy configured properly?: 'Fout by ophaal van netwerkinligting. Is u instaanbediener korrek opgestel?'\n    Proxy Warning: FreeTube het nie ’n ingeboude instaanbediener nie maar kan aan ’n eksterne een koppel, soos een wat op u masjien loop soos Tor of ’n eksterne een soos ’n SOCKS5-instaanbediener wat deur sommige VPN’s verskaf word. Indien geaktiveer, maak seker u instaanbediener/Tor is korrek opgestel anders kan FreeTube geen data ophaal nie.\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'SponsorBlock'\n    Enable SponsorBlock: 'Aktiveer SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'SponsorBlock API-bronadres (verstek is https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'Stel my in kennis wanneer geborgde segment oorgeslaan is'\n    UseDeArrowTitles: 'Gebruik DeArrow-videotitels'\n    UseDeArrowThumbnails: 'Gebruik DeArrow vir duimnaels'\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'DeArrow-duinmaelgenereerder API-bronadres (verstek is https://dearrow-thumb.ajay.app)'\n    Skip Options:\n      Skip Option: 'Slaan opsie oor'\n      Auto Skip: 'Slaan outomaties oor'\n      Show In Seek Bar: 'Toon in soekbalk'\n      Prompt To Skip: 'Vra om oor te slaan'\n      Do Nothing: 'Doen niks'\n    Category Color: 'Kategoriekleur'\n  Parental Control Settings:\n    Parental Control Settings: 'Ouerbeheer'\n    Hide Unsubscribe Button: 'Versteek uittekenknop'\n    Show Family Friendly Only: 'Toon slegs gesinsvriendelike inhoud'\n    Hide Search Bar: 'Versteek soekbalk'\n  Experimental Settings:\n    Experimental Settings: 'Eksperimenteel'\n    Warning: 'Dit is eksperimentele instellings wat die toep kan laat uitbom indien geaktiveer. Dit word aanbeveel om rugsteune te maak. Gebruik op eie risiko!'\n    Replace HTTP Cache: 'Vervang HTTP-kasgeheue'\n  Password Dialog:\n    Password: 'Wagwoord'\n    Enter Password To Unlock: 'Voer wagwoord in om instellings te ontgrendel'\n  Password Settings:\n    Password Settings: 'Wagwoord'\n    Set Password To Prevent Access: 'Stel ’n wagwoord in om toegang tot instellings te voorkom'\n    Set Password: 'Stel wagwoord in'\n    Remove Password: 'Verwyder wagwoord'\nAbout:\n  #On About page\n  About: 'Oor'\n  Beta: 'Beta'\n  Source code: 'Bronkode'\n  AGPLv3: 'AGPLv3'\n  Downloads / Changelog: 'Aflaaie / Veranderingslogboek'\n  GitHub releases: 'GitHub-vrystellings'\n  Help: 'Hulp'\n  FreeTube Wiki: 'FreeTube Wiki'\n  FAQ: 'Gereelde vrae'\n  Discussions: 'Besprekings'\n  Report a problem: 'Rapporteer ’n probleem'\n  GitHub issues: 'GitHub-probleme'\n  Please check for duplicates before posting: 'Gaan na vir duplikate voor u dit plaas'\n  Website: 'Webwerf'\n  Blog: 'Woernaal'\n  Email: 'E-pos'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Klets op Matrix'\n  room rules: 'kamerreëls'\n  Translate: 'Vertaal'\n  Credits: 'Danksegging'\n  these people and projects: 'hierdie mense en projekte'\n  Donate: 'Skenk'\n\nProfile:\n  Profile Settings: 'Profiel'\n  Toggle Profile List: 'Tokkel profiellys'\n  Profile Select: 'Profielseleksie'\n  Profile Filter: 'Profielfilter'\n  All Channels: 'Alle kanale'\n  Profile Manager: 'Profielbestuurder'\n  Create New Profile: 'Skep nuwe profiel'\n  Edit Profile: 'Wysig profiel'\n  Edit Profile Name: 'Wysig profielnaam'\n  Create Profile Name: 'Skep profielnaam'\n  Profile Name: 'Profielnaam'\n  Color Picker: 'Kleurkieser'\n  Custom Color: 'Pasgemaakte kleur'\n  Profile Preview: 'Profielvoorskou'\n  Create Profile: 'Skep profiel'\n  Update Profile: 'Werk profiel by'\n  Make Default Profile: 'Maak verstekprofiel'\n  Delete Profile: 'Skrap profiel'\n  Are you sure you want to delete this profile?: 'Is u seker u wil hierdie profiel skrap?'\n  All subscriptions will also be deleted.: 'Alle intekeninge sal ook geskrap word.'\n  Your profile name cannot be empty: 'U profielnaam kan nie leeg wees nie'\n  Profile has been created: 'Profiel is geskep'\n  Profile has been updated: 'Profiel is bygewerk'\n  Your default profile has been set to {profile}: 'U verstekprofiel is ingestel op {profile}'\n  Removed {profile} from your profiles: 'Verwyder {profile} uit u profiele'\n  Your default profile has been changed to your primary profile: 'U verstekprofiel is na u hoofprofiel verander'\n  '{profile} is now the active profile': '{profile} is nou die aktiewe profiel'\n  Subscription List: 'Intekenlys'\n  Other Channels: 'Ander kanale'\n  '{number} selected': '{number} gekies'\n  Select All: 'Kies alles'\n  Select None: 'Kies geen'\n  Delete Selected: 'Skrap gekose'\n  Add Selected To Profile: 'Voeg gekose toe tot profiel'\n  No channel(s) have been selected: 'Geen kanaal(e) is gekies nie'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Dit is u primêre profiel.  Is u seker u wil die gekose kanale skrap?  Dieselfde kanale sal geskrap word in enige ander profiel waarin dit voorkom.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Is u seker u wil die gekose kanale skrap?  Dit sal nie die kanaal uit enige ander profiel skrap nie.'\n  Close Profile Dropdown: 'Sluit profielkieslys'\n  Open Profile Dropdown: 'Open profielkieslys'\n#On Channel Page\nChannel:\n  Subscribe: 'Teken in'\n  Unsubscribe: 'Teken uit'\n  Channel has been removed from your subscriptions: 'Kanaal is uit u intekeninge verwyder'\n  Removed subscription from {count} other channel(s): 'Intekening van {count} ander kanaal(e) is verwyder'\n  Added channel to your subscriptions: 'Kanaal is tot u intekeninge toegevoeg'\n  Search Channel: 'Deursoek kanaal'\n  Your search results have returned 0 results: 'U soekaksie het 0 resultate gelewer'\n  This channel does not exist: 'Hierdie kanaal bestaan nie'\n  This channel does not allow searching: 'Hierdie kanaal laat nie soektogte toe nie'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'Hierdie kanaal is ouderdomsbeperk en kan nie tans in FreeTube bekyk word nie.'\n  Channel Tabs: 'Kanaaloortjies'\n  Videos:\n    Videos: 'Video’s'\n    This channel does not currently have any videos: 'Hierdie kanaal het tans geen video’s'\n    Sort Types:\n      Newest: 'Nuutste'\n      Oldest: 'Oudste'\n      Most Popular: 'Gewildste'\n  Shorts:\n    This channel does not currently have any shorts: 'Hierdie kanaal het tans geen kortvideo’s nie'\n  Live:\n    Live: 'Regstreeks'\n    This channel does not currently have any live streams: 'Hierdie kanaal het tans geen rekstreekse stromings nie'\n  Playlists:\n    Playlists: 'Afspeellyste'\n    This channel does not currently have any playlists: 'Hierdie kanaal het tans geen afspeellyste nie'\n    Sort Types:\n      Last Video Added: 'Laaste toegevoegde video'\n      Newest: 'Nuutste'\n      Oldest: 'Oudste'\n  Podcasts:\n    Podcasts: 'Podsendings'\n    This channel does not currently have any podcasts: 'Hierdie kanaal het tans geen podsendings nie'\n  Releases:\n    Releases: 'Vrystellings'\n    This channel does not currently have any releases: 'Hierdie kanaal het nie tans enige vrystellings nie'\n  About:\n    About: 'Oor'\n    Channel Description: 'Kanaalbeskrywing'\n    Tags:\n      Tags: 'Etikette'\n      Search for: 'Soek na ‘{tag}’'\n    Details: 'Details'\n    Joined: 'Lid sedert'\n    Location: 'Ligging'\n    Featured Channels: 'Uitgeligte kanale'\n  Posts:\n    This channel currently does not have any posts: 'Hierdie kanaal het nie tans enige plasings nie'\n    votes: '{votes} stemme'\n    Reveal Answers: 'Onthul antwoorde'\n    Hide Answers: 'Versteek antwoorde'\n    Video hidden by FreeTube: 'Video is deur FreeTube versteek'\n    View Full Post: Bekyk volle plasing\n    Viewing Posts Only Supported By Invidious: Bekyk van plasings word slegs vir Invidious ondersteun. Gaan na ’n kanaal se gemeenskapsblad om inhoud te sien sonder Invidious.\n  Home:\n    Home: Tuis\n    View Playlist: Bekyk afspeellys\nVideo:\n  More Options: 'Nog opsies'\n  Mark As Watched: 'Markeer as gekyk'\n  Remove From History: 'Verwyder uit geskiedenis'\n  Video has been marked as watched: 'Video is gemarkeer as gekyk'\n  Video has been removed from your history: 'Video is uit u geskiedenis verwyder'\n  Save Video: 'Bewaar video'\n  Video has been saved: 'Video is bewaar'\n  Video has been removed from your saved list: 'Video is verwyder uit u lys van bewaarde video’s'\n  Open in YouTube: 'Open in YouTube'\n  Copy YouTube Link: 'Kopieer YouTube-skakel'\n  Open YouTube Embedded Player: 'Open YouTube- ingebedde skakel'\n  Copy YouTube Embedded Player Link: 'Kopieer YouTube-inbedspelerskakel'\n  Open in Invidious: 'Open in Invidious'\n  Copy Invidious Link: 'Kopieer Invidious-skakel'\n  Open Channel in YouTube: 'Open kanaal in YouTube'\n  Copy YouTube Channel Link: 'Kopieer YouTube-kanaalskakel'\n  Open Channel in Invidious: 'Open kanaal in Invidious'\n  Copy Invidious Channel Link: 'Kopieer Invidious-kanaalskakel'\n  Hide Channel: 'Versteek kanaal'\n  Unhide Channel: 'Toon kanaal'\n  Views: 'Kyke'\n  Loop Playlist: 'Herhaal afspeellys'\n  Shuffle Playlist: 'Skommel afspeellys'\n  Reverse Playlist: 'Keer afspeellys om'\n  Previous: 'Vorige'\n  Next: 'Volgende'\n  Watched: 'Gekyk'\n  Autoplay: 'Outo-afspeel'\n  Starting soon, please refresh the page to check again: 'Begin binnekort, verfris asb. die blad om weer na te gaan'\n  # As in a Live Video\n  Premieres: 'Première'\n  Upcoming: 'Komend'\n  Live: 'Regstreeks'\n  Live Now: 'Nou regstreeks'\n  Live Chat: 'Regstreekse klets'\n  Enable Live Chat: 'Aktiveer regstreekse klets'\n  Live Chat is currently not supported in this build.: 'Regstreekse klets word nie in hierdie bou gesteun nie.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Regstreekse klets is geaktiveer.  Kletsboodskappe sal hier verskyn.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Regstreekse klets word nie met die Invidious-API ondersteun nie.  ’n Direkte verbinding na YouTube word vereis.'\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'Regstreekse klets is nie vir hierdie stroom beskikbaar nie. Die oplaaier het dit gedeaktiveer.'\n  Show Super Chat Comment: 'Toon superkletskommentaar'\n  Scroll to Bottom: 'Rol na onderent'\n  Published:\n    In less than a minute: 'Oor minder as een minuut'\n  Published on: 'Gepubliseer op'\n  Streamed on: 'Gestroom op'\n  Started streaming on: 'Het begin met stroming op'\n  Sponsor Block category:\n    sponsor: 'Borg'\n    intro: 'Inleiding'\n    outro: 'Uitleiding'\n    self-promotion: 'Selfbevordering'\n    interaction: 'Interaksie'\n    music offtopic: 'Musiek ongepas'\n    recap: 'Opsomming'\n    filler: 'Vulsel'\n  External Player:\n    OpenInTemplate: 'Open in {externalPlayer}'\n    video: 'video'\n    playlist: 'afspeellys'\n    OpeningTemplate: 'Open tans {videoOrPlaylist} in {externalPlayer}…'\n    UnsupportedActionTemplate: '{externalPlayer} ondersteun nie: {action}'\n    Unsupported Actions:\n      starting video at offset: 'begin video met verrekening'\n      setting a playback rate: 'stel afspeelsnelheid in'\n      opening playlists: 'open afspeellyste'\n      opening specific video in a playlist (falling back to opening the video): 'open spesifieke video in ’n afspeellys (val terug tot die open van die video)'\n      reversing playlists: 'keer afspeellyste om'\n      shuffling playlists: 'skommel afspeellyste'\n      looping playlists: 'herhalende afspeellyste'\n  Player:\n    TranslatedCaptionTemplate: '{language} (vertaal vanaf “{originalLanguage}”)'\n    Audio Tracks: 'Oudiosnitte'\n    Theatre Mode: 'Teatermodus'\n    Exit Theatre Mode: 'Verlaat teatermodus'\n    Full Window: 'Volle venster'\n    Exit Full Window: 'Verlaat volle venster'\n    Take Screenshot: 'Maak skermkiekie'\n    Show Stats: 'Toon statistiek'\n    Hide Stats: 'Versteek statistiek'\n    Stats:\n      Stats: 'Statistieke'\n      Video ID: 'Video ID: {videoId}'\n      Media Formats: 'Mediaformate: {formats}'\n      Resolution: 'Resolusie: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Spelerdimensies: {width}x{height}'\n      Bitrate: 'Bistempo: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Bandwydte: {bandwidth} kbps'\n      Buffered: 'Gebuffer: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Verlore rame: {droppedFrames} / Totale rame: {totalFrames}'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Kodeks: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Kodeks: {videoCodec} / {audioCodec}'\n    You appear to be offline: 'U blyk vanlyn te wees.'\n    Playback will resume automatically when your connection comes back: 'Afspeel sal outomaties hervat wanneer u verbinding terug kom.'\n    Skipped segment: 'Segment {segmentCategory} oorgeslaan'\n#& Videos\n    Autoplay is off: Outo-afspeel is af\n    Autoplay is on: Outo-afspeel is aan\n  Unlisted: Ongelys\n  IP block: YouTube het u IP-adres versper en u kan nie video’s kyk nie. Verander u VPN of instaanbediener.\n  MembersOnly: Videos slegs vir lede kan nie met FreeTube gekyk word nie omdat dit ’n Google-aantekening en betaalde lidmaatskap op die oplaaier se kanaal vereis.\n  AgeRestricted: Video’s met ’n ouderdomsperk kan nie met FreeTube gekyk word nie omdat dit ’n Google-aantekening en ouderdomvebestigde YouTube-rekening vereis.\n  DeArrow:\n    Show Original Details: Toon oorspronklike details\n    Show Modified Details: Toon gewysigde details\n#& Playlists\n  DRMProtected: DRM-beskermde video’s kan nie in FreeTube afgespeel word nie omdat dit eiendoms geslotebronkomponente vereis. Indien u die video wil kyk, doen dit asb. op die amptelike YouTube-webwerf in ’n webblaaier met DRM geaktiveer.\n  Watched Progress Saved: Kykvordering is bewaar\nPlaylist:\n  #& About\n  Playlist: 'Afspeellys'\n  View Full Playlist: 'Bekyk volledige afspeellys'\n  Last Updated On: 'Laas bygewerk op'\n  Sort By:\n    DateAddedNewest: 'Datum toegevoeg (nuutste)'\n    DateAddedOldest: 'Datum toegevoeg (oudste)'\n    AuthorAscending: 'Outeur (A-Z)'\n    AuthorDescending: 'Outeur (Z-A)'\n    VideoTitleAscending: 'Titel (A-Z)'\n    VideoTitleDescending: 'Titel (Z-A)'\n    Custom: 'Pasgemaak'\n\n# On Video Watch Page\n#* Published\n#& Views\n    VideoDurationAscending: Duur (korste)\n    VideoDurationDescending: Duur (langste)\n    PublishedOldest: Datum gepubliseer (oudste)\n    PublishedNewest: Datum gepubliseer (nuutste)\nChange Format:\n  Change Media Formats: 'Verander mediaformate'\n  Use Dash Formats: 'Gebruik DASH-formate'\n  Use Legacy Formats: 'Gebruik legaatformate'\n  Use Audio Formats: 'Gebruik oudioformate'\n  Dash formats are not available for this video: 'DASH-formate is nie beskikbaar vir hierdie video nie'\n  Audio formats are not available for this video: 'Oudioformate is nie beskikbaar vir hierdie video nie'\n  Legacy formats are not available for this video: 'Legaatformate is nie beskikbaar vir hierdie video nie'\nShare:\n  Share Video: 'Deel video'\n  Share Channel: 'Deel kanaal'\n  Share Playlist: 'Deel afspeellys'\n  Include Timestamp: 'Sluit tydstempel in'\n  Copy Link: 'Kopieer skakel'\n  Open Link: 'Open skakel'\n  Copy Embed: 'Kopieer inbedskakel'\n  Open Embed: 'Open inbedskakel'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-URL is na knipbod gekopieer'\n  Invidious Embed URL copied to clipboard: 'Invidious-inbedskakel is na knipbord gekopieer'\n  Invidious Channel URL copied to clipboard: 'Invidious-kanaalskakel is na knipbord gekopieer'\n  YouTube URL copied to clipboard: 'YouTube-skakel is na knipbord gekopieer'\n  YouTube Embed URL copied to clipboard: 'YouTube-inbedskakel is na knipbord gekopieer'\n  YouTube Channel URL copied to clipboard: 'YouTube-kanaalskakel is na knipbord gekopieer'\n  Share Post: Deel plasing\nClipboard:\n  Copy failed: 'Kopiëring na knipbord het misluk'\n  Cannot access clipboard without a secure connection: 'Geen toegang tot knipbord sonder ’n beveiligde verbinding'\n\nChapters:\n  Chapters: 'Hoofstukke'\n  Key Moments: Sleuteloomblikke\nMini Player: 'Mini-speler'\nComments:\n  Comments: 'Kommentare'\n  Click to View Comments: 'Klik om kommentare te sien'\n  Getting comment replies, please wait: 'Kommentare word opgehaal, wag asb.'\n  There are no more comments for this video: 'Daar is geen verdere kommentare vir hierdie video nie'\n  Hide Comments: 'Versteek kommentare'\n  Top comments: 'Topkommentare'\n  Newest first: 'Nuutste eerste'\n  View {replyCount} replies: 'Sien 1 antwoord | Sien {replyCount} antwoorde'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'Toon nog antwoorde'\n  There are no comments available for this video: 'Daar is geen reaksies beskikbaar vir hierdie video nie'\n  Load More Comments: 'Laai nog kommentare'\n  Pinned by: 'Vasgemaak deur'\n  Member: 'Lid'\n  Subscribed: 'Ingeteken'\n  Hearted: 'Met hart'\n  There are no comments available for this post: Daar is geen kommentare beskikbaar vir hierdie plasing nie\n  Hide {replyCount} replies: Versteek 1 antwoord | Versteek {replyCount} antwoorde\n  View 1 reply from {channelName}: Sien 1 antwoord van {channelName}\n  View {replyCount} replies from {channelName} and others: Sien {replyCount} antwoorde van {channelName} en ander\nUp Next: 'Volgende'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Kies die agterpunt wat FreeTube gebruik om data te versamel. Die lokale API is ’n ingeboude uithaler. Die Invidious API moet met ’n Invidious-bediener gekoppel word.'\n    Fallback to Non-Preferred Backend on Failure: 'Wanneer u voorkeur-API probleme gee sal FreeTube outomaties terugval op die alternatiewe nie-voorkeur-API wanneer hierdie instelling geaktiveer is.'\n    Thumbnail Preference: 'Alle duimnaels in FreeTube sal vervang word met ’n beeld uit die video, vervaag of versteek i.p.v. die verstek duimnael.'\n    Invidious Instance: 'Die Invidious-instansie waarmee FreeTube sal verbind om API-oproepe te maak.'\n    Region for Trending: 'Met streek van stygend kan u kies welke land se gewilde videos aan u vertoon moet word.'\n    External Link Handling: |\n      Kies die verstek gedrag vir wanneer ’n skakel geklik word wat nie in FreeTube geopen kan word nie.\n      FreeTube sal die geklikte skakel by verstek in u verstek blaaier open.\n    Open Deep Links In New Window: Bronadresse wat aan FreeTube gegee word, soos wat deur blaaieruitbreidings of bevellynargumente gestuur word, word in ’n nuwe venster geopen.\n  Player Settings:\n    Proxy Videos Through Invidious: 'FreeTube sal verbind met Invidious en die video’s van daar aflaai eerder as om ’n direkte verbinding met YouTube te maak.'\n    Default Video Format: 'Kies die formate wat gebruik word wanneer ’n video afspeel. DASH-formate kan hoër kwaliteit afspeel. Legaat formate word beperk tot ’n maks van 360p maar gebruik minder bandwydte. Oudio formate is slegs oudio strome.'\n    Scroll Playback Rate Over Video Player: 'Terwyl die muis oor die video is, druk en hou die Control-toets (Command-toets op Mac) en rol met die muis om die afspeelsnelheid te beheer. Druk en hou die Control-toets (Command-toets op Mac) en klik met die linker muisknop om vinnig terug te keer na die verstek afspeelsnelheid (1x tensy aangepas in die instellings).'\n    Skip by Scrolling Over Video Player: 'Gebruik die rolwiel om deur die video te spoel, soos by MPV.'\n  External Player Settings:\n    External Player: 'Deur die kies van ’n eksterne videospeler sal daar ’n ikoone op die video se duimnael verskyn waarmee dit (of afspeellys indien ondersteun) in die gekose eksterne videospeler geopen kan word. Let op: Invidious-instellings beïnvloed nie eksterne videospelers nie.'\n    Custom External Player Executable: 'FreeTube neem by verstek aan dat die gekose eksterne videospeler d.m.v. die PATH-omgewingsveranderlike gevind kan word. Indien nodig kan ’n pasgemaakte pad hier ingevoer word.'\n    Ignore Warnings: 'Onderdruk waarskuwings wanneer die huidige eksterne videospeler nie die huidige aksie ondersteun nie (bv. afspeellyste omkeer, ens.).'\n    Ignore Default Arguments: 'Moet geen verstek argumente na die eksterne videospeler stuur buiten die video-URL nie (bv. afspeelsnelheid, afspeellys-URL, ens.). Pasgemaakte argumente word steeds deurgestuur.'\n    Custom External Player Arguments: 'Enige pasgemaakte bevellynrgumente, wat u aan die eksterne videospeler vir deurgee.'\n    DefaultCustomArgumentsTemplate: \"(verstek: ‘{defaultCustomArguments}’)\"\n  Distraction Free Settings:\n    Hide Channels: 'Voer ’n kanaal-ID in om alle video’s, afspeellyste en die kanaal self te versteek sodat dit nie in soek, stygend, gewildste, en aanbeveel weergegee word nie. Die ingevoerde kanaal-ID moet volledig ooreenstem en is hooflettergevoelig.'\n    Hide Subscriptions Live: 'Hierdie instelling woord oorheers deur die toepwye “{appWideSetting}”-instelling in die “{subsection}” gedeelte van “{settingsSection}”'\n    Hide Videos, Playlists and Channels Containing Text: 'Voer ’n woord, woordfragment of woordgroep in (nie hooflettergevoelig) om alle video’s en afspeellyste waarvan die oorspronklike titel dit bevat, regoor FreeTube te versteek, met uitsondering van net geskiedenis, u afspeellyste en video’s in afspeellyste.'\n    Hide Videos on Watch: Versteek bekykte video’s op die Video’s-, Shorts- en Live-oortjies op die blaaie Intekeninge en Kanale. Dit beïnvloed nie die Tuis-oortjie op kanaalblaaie nie\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Wanneer geaktiveer, sal FreeTube RSS i.p.v. sy verstek metode gebruik om u intekenvoer op te haal. RSS is vinniger en voorkom IP-versperring, maar bied nie sekere inligting soos videoduur, status of plasings nie'\n    Fetch Automatically: 'Wanneer geaktiveer, sal FreeTube u intekenvoer outomaties ophaal wanneer ’n nuwe venster geopen word.'\n  Experimental Settings:\n    Replace HTTP Cache: 'Deaktiveer die skyfgebaseerde HTTP-kas van Electron en aktiveer ’n aangepaste afbeeldingskas in die geheue in. Sal lei tot ’n verhoogde RAM-gebruik.'\n  SponsorBlock Settings:\n    UseDeArrowTitles: 'Vervang videotitels met gebruiker ingediende titels vanaf DeArrow.'\n    UseDeArrowThumbnails: 'Vervang videoduimnaels met duimnaels vanaf DeArrow.'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Lokale API-fout (Klik om te kopieer)'\nInvidious API Error (Click to copy): 'Invidious API-fout (Klik om te kopieer)'\nFalling back to Invidious API: 'Val terug op Invidious API'\nFalling back to Local API: 'Val terug op lokale API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Hierdie video is onbeskikbaar vanweë ontbrekende formate. Dit kan gebeur weens video-onbeskikbaarheid in u land.'\nUnknown YouTube url type, cannot be opened in app: 'Onbekende YouTube-bronadres, die URL kan nie in die toep geopen word nie'\nLoop is now disabled: 'Herhaling is nou gedeaktiveer'\nLoop is now enabled: 'Herhaling is nou geaktiveer'\nShuffle is now disabled: 'Skommel is nou gedeaktiveer'\nShuffle is now enabled: 'Skommel is nou geaktiveer'\nThe playlist has been reversed: 'Die afspeellys speel van agter af'\nPlaying Next Video: 'Speel volgende video af'\nPlaying Previous Video: 'Speel vorige video af'\nPlaying Next Video Interval: 'Volgende video word afgespeel. Klik om te kanselleer. | Volgende video word oor {nextVideoInterval} sekond afgespeel. Klik om te kanselleer. | Volgende video word oor {nextVideoInterval} sekondes afgespeel. Klik om te kanselleer.'\nCanceled next video autoplay: 'Outomatiese afspeel is gekanselleer'\n\nDefault Invidious instance has been set to {instance}: 'Verstek Invidious-instansie is ingestel op {instance}'\nDefault Invidious instance has been cleared: 'Verstek Invidious-instansie is gewis'\n'The playlist has ended. Enable loop to continue playing': 'Die afspeellys is klaar.  Aktiveer lusafspeel in te bly afspeel'\nAge Restricted:\n  This channel is age restricted: 'Hierdie kanaal het ’n ouderdomsperk'\n  This video is age restricted: 'Hierdie video het ’n ouderdomsperk'\nExternal link opening has been disabled in the general settings: 'Die open van eksterne skakels is gedeaktiveer in die algemene instellings'\nScreenshot Success: 'Bewaarde skermkiekie'\nScreenshot Error: 'Skermkiekie het misluk. {error}'\nChannel Hidden: '{channel} tot kanaalfilter toegevoeg'\nChannel Unhidden: '{channel} verwyder uit kanaalfilter'\nTrimmed input must be at least N characters long: 'Bygesnyde invoer moet ten minste 1 karakter lank wees | Bygesnyde invoer moet ten minste {length} karakters lank wees'\nTag already exists: 'Etiket “{tagName}” bestaan reeds'\n\nHashtag:\n  Hashtag: 'Hutsmerk'\n  This hashtag does not currently have any videos: 'Hierdie hutsmerk het tans geen video’s'\nMoments Ago: 'oomblikke gelede'\nYes: 'Ja'\nNo: 'Nee'\nOk: 'Goed'\nYes, Delete: 'Ja, skrap'\nYes, Restart: 'Ja, herbegin'\nYes, Open Link: 'Ja, open skakel'\nCancel: 'Kanselleer'\n# symbol used to indicate that an item is correct\ncheckmark: '✓'\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: '{label}: {value}'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  arrowright: Regspyltjie\n  arrowup: Oppyltjie\n  alt: Alt\n  arrowdown: Afpyltjie\n  ctrl: Ctrl\n  arrowleft: Linkspyltjie\n  shift: Wissel\n  enter: Doen\n  plus: Plus\nDescription:\n  Collapse Description: Toon minder\n  Expand Description: …nog\nAutoplay Interruption Timer: Outo-afspeel is gekanselleer weens {autoplayInterruptionIntervalHours} uur van onaktiwiteit\nKeyboardShortcutPrompt:\n  Navigate to Settings: Navigeer na die instellingsblad\n  Play: Tokkel afspeel/wag\n  Navigate to History: Navigeer na die geskiedenisblad\n  Refresh: Verfris voer met nuutste inhoud\n  Last Frame: Vorige raam (terwyl wagtend)\n  Volume Up: Maak harder\n  Volume Down: Maak sagter\n  Small Rewind: Spoel X sekondes terug gebaseer op die Terugspoelinterval en huidige video-afspeeltempo\n  Small Fast Forward: Spoel X sekondes vorentoe gebaseer op die Vorentoespoelinterval en huidige video-afspeeltempo\n  Mute: Tokkel demper\n  Search in New Window: Soek in ’n nuwe venster\n  Large Rewind: Spel 10 sekondes terug / Spoel video terug gebaseer op huidige video-afspeeltempo\n  Decrease Video Speed: Vertraag videospoed gebaseer op video-afspeeltempo-interval\n  Reset Zoom: Herstel zoemvlak / Koppelvlakskaal\n  Next Frame: Volgende raam (terwyl wagtend)\n  Show Keyboard Shortcuts: Toon sneltoetse\n  History Backward: Gaan een blad terug\n  History Forward: Gaan een blad vorentoe\n  New Window: Skep ’n nuwe venster\n  Captions: Tokkel onderskrifte AAN/AF\n  Stats: Toon videostatistieke\n  Fullscreen: Tokkel volskerm\n  Picture in Picture: Tokkel beeld-in-beeldmodus\n  Increase Video Speed: Versnel videospoed gebaseer op huidige video-afspeeltempo-interval\n  Full Window: Tokkel volle venster\n  Theatre Mode: Tokkel teatermodus\n  Take Screenshot: Maak skermkiekie\n  Minimize Window: Verklein venster\n  Close Window: Sluit venster\n  Zoom In: Zoem in\n  Focus Search: Fokus op die soekbalk\n  Zoom Out: Zoem uit\n  Next Chapter: Volgende hoofstuk\n  Skip by Tenths: Slaan oor video op persentasie (3 oorslane vir 30% van videoduur)\n  Last Chapter: Laaste hoofstuk\n  Toggle Developer Tools: Tokkel ontwikkelaarsnutsmiddels\n  Focus Secondary Search: Fokus op die sekondêre soekbalk (indien een teenwoordig is)\n  Large Fast Forward: Spoel 10 sekondes vorentoe / Spoel video vorentoe gebaseer op huidige video-afspeeltempo\n  Sections:\n    Video:\n      General: 'Video: Algemeen'\n      Playback: 'Video: Afspeel'\n    App:\n      Situational: 'Toep: Omstandigheid'\n      General: 'Toep: Algemeen'\n  Keyboard Shortcuts: Sneltoetse\n  Home: Speol terug na die begin van die video\n  End: Spoel vorentoe na die einde van die video\n  Skip to Next Video: Gaan na die volgende video in ’n afspeellys of die volgende aanbevole video\n  Skip to Previous Video: Gaan na die volgende video in ’n afspeellys\nshortcutLabelSeparator: ｜\nRight-click or hold to see history: Regskliek of hou in om die geskiedenis te sien\n"
  },
  {
    "path": "static/locales/ar.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'العربية'\n\n# Webkit Menu Bar\nFile: 'ملف'\nQuit: 'خروج'\nEdit: 'تحرير'\nUndo: 'تراجع'\nRedo: 'إعادة'\nCut: 'قص'\nCopy: 'نسخ'\nPaste: 'لصق'\nDelete: 'حذف'\nSelect all: 'حدد الكل'\nToggle Developer Tools: 'إظهار/إخفاء أدوات المطوّر'\nActual size: 'الحجم الأصلي'\nZoom in: 'تكبير'\nZoom out: 'تصغير'\nToggle fullscreen: 'تفعيل وضع الشاشة الكاملة'\nWindow: 'نافذة'\nMinimize: 'تصغير'\nClose: 'إغلاق'\nBack: 'رجوع'\nForward: 'إلى الأمام'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'الفيديوهات'\n  Shorts: القصيرة\n  Live: البث المباشر\n  Posts: المنشورات\n  Sort By: ترتيب حسب\n\n# Search Bar\n  Counts:\n    Video Count: 1 فيديو | {count} مقاطع فيديو\n    Channel Count: 1 قناة | {count} قنوات\n    Subscriber Count: 1 مشترك | {count} مشتركين\n    View Count: 1 مشاهدة | {count} مشاهدات\n    Watching Count: 1 مشاهد | {count} مشاهدون\n    Like Count: إعجاب واحد |{count} إعجاب\n    Comment Count: تعليق واحد | {count} تعليقًا\nSearch / Go to URL: 'ابحث / اذهب إلى رابط'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'فلاتر البحث'\n  Sort By:\n    Most Relevant: 'الأكثر صلة'\n    Rating: 'التقييم'\n    Upload Date: 'تاريخ الرفع'\n    View Count: 'عدد المشاهدات'\n  Time:\n    Time: 'الوقت'\n    Any Time: 'أي وقت'\n    Last Hour: 'آخر ساعة'\n    Today: 'اليوم'\n    This Week: 'هذا الأسبوع'\n    This Month: 'هذا الشهر'\n    This Year: 'هذه السنة'\n  Type:\n    Type: 'النوع'\n    All Types: 'كل الأنواع'\n    Videos: 'الفيديوهات'\n    Channels: 'قنوات'\n    #& Playlists\n    Movies: الأفلام\n  Duration:\n    Duration: 'المدة'\n    All Durations: 'كل الآوقات'\n    Short (< 4 minutes): 'قصير (< 4 دقائق)'\n    Long (> 20 minutes): 'طويل (> 20 دقيقة)'\n  # On Search Page\n    Medium (4 - 20 minutes): متوسط (4 - 20 دقيقة)\n  Search Results: 'نتائج البحث'\n  Fetching results. Please wait: 'جاري إحضار النتائج. الرجاء الانتظار'\n  Fetch more results: 'إحضار المزيد من النتائج'\n# Sidebar\n  There are no more results for this search: لا توجد نتائج أخرى لهذا البحث\n  Features:\n    Features: المميزات\n    HD: عالِ الدقة\n    Subtitles: التسميات التوضيحية\n    4K: 4K\n    HDR: المستوى الديناميكي العالي\n    Creative Commons: المشاع الإبداعي\n    3D: ثلاثي الابعاد\n    Live: مباشر\n    360 Video: فيديو ٣٦٠\n    Location: الموقع\n    VR180: VR180\n  Clear Filters: مسح المرشحات\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'الاشتراكات'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'قائمة اشتراكك فارغة حاليًا. إذا كنت ترغب في استيراد اشتراكاتك، فيمكنك الانتقال إلى إعدادات البيانات وتحديد استيراد الاشتراكات أو يمكنك البحث عن قناة والاشتراك فيها.'\n  Load More Videos: حمّل المزيد من الفيديوهات\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: لدى هذا الملف الشخصي عدد كبير من الاشتراكات. يتم فرض وضع RSS لتجنب تقييد الوصول للاشتراكات\n  Error Channels: القنوات التي بها أخطاء\n  Disabled Automatic Fetching: لقد قمت بتعطيل الجلب التلقائي للاشتراك. قم بتحديث الاشتراكات لرؤيتها هنا.\n  Empty Channels: لا تحتوي قنواتك التي اشتركت فيها حاليا على أي مقاطع فيديو.\n  All Subscription Tabs Hidden: جميع علامات تبويب الاشتراك مخفية. لمشاهدة المحتوى هنا ، يرجى إظهار بعض علامات التبويب في قسم \"{subsection}\" في \"{settingsSection}\".\n  Subscriptions Tabs: تبويب الاشتراكات\n  Load More Posts: تحميل المزيد من المشاركات\n  Empty Posts: القنوات التي اشتركت بها حاليا لا تحتوي على أي مشاركات.\nTrending:\n  Trending: 'المحتوى الرائج'\n  Trending Tabs: علامات التبويب الشائعة\n  Gaming: الالعاب\n  Sports: رياضة\nMost Popular: 'الأكثر شعبية'\nPlaylists: 'قوائم التشغيل'\nUser Playlists:\n  Your Playlists: 'قوائم التشغيل الخاصة بك'\n  Search bar placeholder: بحث عن قوائم التشغيل\n  Empty Search Message: لا توجد مقاطع فيديو في قائمة التشغيل هذه تتطابق مع بحثك\n  This playlist currently has no videos.: لا تحتوي قائمة التشغيل هذه حاليًا على مقاطع فيديو.\n  Create New Playlist: إنشاء قائمة تشغيل جديدة\n  Add to Playlist: أضف إلى قائمة التشغيل\n  Move Video Up: نقل الفيديو لأعلى\n  Move Video Down: نقل الفيديو إلى الأسفل\n  Remove from Playlist: إزالة من قائمة التشغيل\n  Playlist Name: اسم قائمة التشغيل\n  Playlist Description: وصف قائمة التشغيل\n  Save Changes: حفظ التغييرات\n  Edit Playlist Info: تعديل معلومات قائمة التشغيل\n  Copy Playlist: نسخ قائمة التشغيل\n  Cancel: إلغاء\n  Delete Playlist: حذف قائمة التشغيل\n  Sort By:\n    LatestCreatedFirst: تم إنشاؤها مؤخرًا\n    LatestUpdatedFirst: تم تحديثه مؤخرا\n    NameAscending: أ-ي\n    NameDescending: ي-أ\n    EarliestCreatedFirst: الاقدم إنشائا\n    EarliestUpdatedFirst: الاحدث إنشائا\n    LatestPlayedFirst: تم تشغيلها مؤخرا\n    EarliestPlayedFirst: الاقدم تشغيلا\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: ‬لا يمكن نقل هذا الفيديو لأعلى.\n      Video has been removed: تمت إزالة الفيديو\n      Playlist name cannot be empty. Please input a name.: لا يمكن أن يكون اسم قائمة التشغيل فارغًا. الرجاء إدخال اسم.\n      There was an issue with updating this playlist.: حدثت مشكلة أثناء تحديث قائمة التشغيل هذه.\n      Playlist has been updated.: تم تحديث قائمة التشغيل.\n      \"{videoCount} video(s) have been removed\": تمت إزالة فيديو واحد | تمت إزالة {videoCount} من مقاطع الفيديو\n      This playlist is protected and cannot be removed.: قائمة التشغيل هذه محمية ولا يمكن إزالتها.\n      There were no videos to remove.: لم تكن هناك مقاطع فيديو لإزالتها.\n      This playlist does not exist: قائمة التشغيل هذه غير موجودة\n      This video cannot be moved down.: لا يمكن نقل هذا الفيديو إلى الأسفل.\n      Playlist {playlistName} has been deleted.: تم حذف قائمة التشغيل {playlistName}.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: لم يتم تحميل بعض مقاطع الفيديو في قائمة التشغيل بعد. انقر هنا للنسخ على أي حال.\n      There was a problem with removing this video: حدثت مشكلة أثناء إزالة هذا الفيديو\n      This playlist is now used for quick bookmark: يتم الآن استخدام قائمة التشغيل هذه للإشارة المرجعية السريعة\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: يتم الآن استخدام قائمة التشغيل هذه للإشارة المرجعية السريعة بدلاً من {oldPlaylistName}. انقر هنا للتراجع\n      Reverted to use {oldPlaylistName} for quick bookmark: تمت العودة لاستخدام {oldPlaylistName} للإشارة المرجعية السريعة\n      This playlist is already being used for quick bookmark.: يتم استخدام قائمة التشغيل هذه بالفعل لوضع إشارة مرجعية سريعة.\n      This playlist has a video with a duration error: تحتوي قائمة التشغيل هذه على مقطع فيديو واحد على الأقل ليس له مدة، وسيتم فرزه كما لو كانت مدته صفرًا.\n      Video has been removed. Click here to undo.: تمت حذف الفيديو. انقر هنا للتراجع.\n    Search for Videos: ‬البحث عن مقاطع الفيديو\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: حدد قائمة تشغيل لإضافة الفيديو الخاص بك إلى | حدد قائمة تشغيل لإضافة مقاطع الفيديو {videoCount} إليها\n    Toast:\n      You haven't selected any playlist yet.: لم تقم بتحديد أي قائمة تشغيل حتى الآن.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Save: حفظ\n    Search in Playlists: البحث في قوائم التشغيل\n    N playlists selected: تم تحديد {playlistCount}\n    Added {count} Times: تمت إضافتها بالفعل | تمت إضافة {count} مرة\n    Allow Adding Duplicate Video(s): السماح بإضافة مقاطع فيديو مكررة\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ستتم إضافة مقاطع فيديو {videoCount}/{totalVideoCount}\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": تمت إضافة {videoCount}/{totalVideoCount} من مقاطع الفيديو بالفعل\n  CreatePlaylistPrompt:\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: توجد بالفعل قائمة تشغيل بهذا الاسم. يرجى اختيار اسم مختلف.\n      There was an issue with creating the playlist.: حدثت مشكلة أثناء إنشاء قائمة التشغيل.\n      Playlist {playlistName} has been successfully created.: تم إنشاء قائمة التشغيل {playlistName} بنجاح.\n    New Playlist Name: اسم قائمة تشغيل جديد\n    Create: انشئ\n  Remove Watched Videos: إزالة مقاطع الفيديو التي تمت مشاهدتها\n  You have no playlists. Click on the create new playlist button to create a new one.: ليس لديك قوائم تشغيل. انقر على زر إنشاء قائمة تشغيل جديدة لإنشاء قائمة تشغيل جديدة.\n  Are you sure you want to delete this playlist? This cannot be undone: هل أنت متأكد أنك تريد حذف قائمة التشغيل هذه؟ هذا لا يمكن التراجع عنه.\n  Add to Favorites: إضافة إلى {playlistName}\n  Remove from Favorites: إزالة من {playlistName}\n  Enable Quick Bookmark With This Playlist: تمكين الإشارة المرجعية السريعة مع قائمة التشغيل هذه\n  Playlists with Matching Videos: قوائم التشغيل مع مقاطع الفيديو المطابقة\n  Quick Bookmark Enabled: تم تمكين الإشارة المرجعية السريعة\n  Cannot delete the quick bookmark target playlist.: لا يمكن حذف قائمة التشغيل المستهدفة للإشارات المرجعية السريعة.\n  Remove Duplicate Videos: إزالة مقاطع الفيديو المكررة\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: هل أنت متأكد أنك تريد إزالة مقطع فيديو واحد تمت مشاهدته من قائمة التشغيل هذه؟ هذا لا يمكن التراجع عنها. | هل أنت متأكد أنك تريد إزالة {playlistItemCount} من مقاطع الفيديو التي تمت مشاهدتها من قائمة التشغيل هذه؟ هذا لا يمكن التراجع عنها.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: هل أنت متأكد أنك تريد إزالة مقطع فيديو مكرر واحد من قائمة التشغيل هذه؟ هذا لا يمكن التراجع عنها. | هل أنت متأكد أنك تريد إزالة {playlistItemCount} من مقاطع الفيديو المكررة من قائمة التشغيل هذه؟ هذا لا يمكن التراجع عنها.\n  Export Playlist: تصدير قائمة التشغيل هذه\n  The playlist has been successfully exported: تم تصدير قائمة التشغيل بنجاح\n  TotalTimePlaylist: 'الوقت الإجمالي: {duration}'\nHistory:\n  # On History Page\n  History: 'السجلّ'\n  Watch History: 'سجلّ المشاهدات'\n  Your history list is currently empty.: 'قائمة سجلّك فارغة حالياً.'\n  Search bar placeholder: البحث في السجل\n  Empty Search Message: لا توجد مقاطع فيديو في السجل الخاص بك تطابق بحثك\n  Case Sensitive Search: ‘بحث مميِّز لحالة الأحرف\n  DateOldestHistory: أول مشاهدة تم مشاهدته أولا\n  DateNewestHistory: آخر مشاهدة تم مشاهدته أولا\nSettings:\n  # On Settings Page\n  Settings: 'الإعدادات'\n  General Settings:\n    General Settings: 'العامة'\n    Fallback to Non-Preferred Backend on Failure: 'الرجوع إلى الواجهة الخلفية الغير مفضلة عند الفشل'\n    Enable Search Suggestions: 'تفعيل الإقتراحات عند البحث'\n    Default Landing Page: 'الصفحة ‪المقصودة الافتراضية'\n    Locale Preference: 'اللغات المفضلة'\n    Preferred API Backend:\n      Preferred API Backend: 'الواجهة الخلفية المفضلة'\n      Local API: 'واجهة برمجة محلية'\n      Invidious API: 'واجهة برمجة \"انفيديوس\"'\n    Video View Type:\n      Video View Type: 'شكل عرض الفيديو'\n      Grid: 'شبكة'\n      List: 'قائمة'\n    Thumbnail Preference:\n      Thumbnail Preference: 'تفضيل الصورة المصغّرة'\n      Default: 'الافتراضي'\n      Beginning: 'بداية'\n      Middle: 'وسط'\n      End: 'نهاية'\n      Hidden: مخفي\n      Blur: الضبابية\n    Region for Trending: 'المنطقة للأكثر شيوعاً'\n        #! List countries\n    Check for Latest Blog Posts: تحقق من أحدث منشورات المدونة\n    Check for Updates: تحقّق من وجود تحديثات\n    View all Invidious instance information: عرض جميع نماذج Invidious\n    System Default: افتراضي النظام\n    Set Current Instance as Default: قم بتعيين المثيل الحالي كافتراضي\n    Current instance will be randomized on startup: سيتم عشوائية المثيل الحالي عند بدء التشغيل\n    No default instance has been set: لم يتم تعيين مثيل افتراضي\n    The currently set default instance is {instance}: المثيل الافتراضي المحدد حاليا هو {instance}\n    Current Invidious Instance: المثيل الحالي Invidious\n    Clear Default Instance: مسح المثيل الافتراضي\n    External Link Handling:\n      No Action: لا يوجد إجراء\n      Ask Before Opening Link: اسأل قبل فتح الرابط\n      Open Link: افتح الرابط\n      External Link Handling: معالجة الارتباط الخارجي\n    Auto Load Next Page:\n      Label: تحميل تلقائي للصفحة التالية\n      Tooltip: قم بتحميل الصفحات والتعليقات الإضافية تلقائيًا.\n    Open Deep Links In New Window: افتح عناوين URL التي تم تمريرها إلى FreeTube في نافذة جديدة\n    Minimize to system tray: تصفير إلى علبة النظام\n  Theme Settings:\n    Theme Settings: 'السِمة'\n    Match Top Bar with Main Color: 'طابق الشريط العلوي مع اللون الأساسي'\n    Base Theme:\n      Base Theme: 'السِمة الأساسية'\n      Black: 'أسود'\n      Dark: 'داكن'\n      Light: 'فاتح'\n      Dracula: 'دراكولا'\n      System Default: افتراضيات النظام\n      Catppuccin Mocha: كاتبوتشين موكا\n      Pastel Pink: الباستيل الوردي\n      Hot Pink: وردي فاقع\n      Nordic: بلدان الشمال الأوروبي\n      Solarized Dark: مظلم مشمس\n      Solarized Light: مشمس داكن\n      Catppuccin Frappe: كاتبوتشين فرابيه\n      Gruvbox Light: صندوق مضيء\n      Gruvbox Dark: صندوق عاتم\n      Everforest Dark Hard: إيفرفورست الداكن القوي\n      Everforest Dark Medium: إيفرفورست الداكن المتوسط\n      Everforest Dark Low: إيفرفورست الداكن المنخفض\n      Everforest Light Hard: إيفرفورست الفاتح القوي\n      Everforest Light Medium: إيفرفورست الفاتح المتوسط\n      Everforest Light Low: إيفرفورست الفاتح المنخفض\n    Main Color Theme:\n      Main Color Theme: 'لون السِمة الأساسي'\n      Red: 'أحمر'\n      Pink: 'وردي'\n      Purple: 'إرجواني'\n      Deep Purple: 'إرجواني داكن'\n      Indigo: 'نيلي'\n      Blue: 'أزرق'\n      Light Blue: 'أزرق فاتح'\n      Cyan: 'سماوي'\n      Teal: 'تركوازي'\n      Green: 'أخضر'\n      Light Green: 'أخضر فاتح'\n      Lime: 'أخضر لايم'\n      Yellow: 'أصفر'\n      Amber: 'كهرماني'\n      Orange: 'برتقالي'\n      Deep Orange: 'برتقالي داكن'\n      Dracula Cyan: 'دراكولا سماوي'\n      Dracula Green: 'دراكولا أخضر'\n      Dracula Orange: 'دراكولا برتقالي'\n      Dracula Pink: 'دراكولا وردي'\n      Dracula Purple: 'دراكولا إرجواني'\n      Dracula Red: 'دراكولا أحمر'\n      Dracula Yellow: 'دراكولا أصفر'\n      Catppuccin Mocha Rosewater: كاتبوتشين موكا ماء الورد\n      Catppuccin Mocha Flamingo: كاتبوتشين موكا فلامنغو\n      Catppuccin Mocha Peach: كاتبوتشين موكا الخوخ\n      Catppuccin Mocha Green: كاتبوتشين موكا اخضر\n      Catppuccin Mocha Teal: كاتبوتشين موكا تيل\n      Catppuccin Mocha Sky: كاتبوتشين موكا سماوي\n      Catppuccin Mocha Sapphire: كاتبوتشين موكا سافير\n      Catppuccin Mocha Blue: كاتبوتشين موكا ازرق\n      Catppuccin Mocha Lavender: كاتبوتشين موكا لافندر\n      Catppuccin Mocha Mauve: كاتبوتشين موكا موف\n      Catppuccin Mocha Pink: كاتبوتشين موكا الوردية\n      Catppuccin Mocha Red: كاتبوتشين موكا أحمر\n      Catppuccin Mocha Maroon: كاتبوتشين موكا مارون\n      Catppuccin Mocha Yellow: كاتبوتشين موكا أصفر\n      Solarized Yellow: مشمس فاتح\n      Solarized Orange: مشمس برتقالي\n      Solarized Red: مشمس أحمر\n      Solarized Magenta: مشمس أرجواني\n      Solarized Violet: مشمس بنفسجي\n      Solarized Blue: مشمس أزرق\n      Solarized Cyan: مشمس سماوي\n      Solarized Green: مشمس أخضر\n      Catppuccin Frappe Sky: كاتبوتشينو فرابيه سماوي\n      Catppuccin Frappe Lavender: كاتبوتشين فرابيه أرجواني\n      Gruvbox Dark Blue: صندوق أزرق غامق\n      Gruvbox Dark Purple: صندوق بنفسجي غامق\n      Gruvbox Dark Orange: صندوق برتقالي غامق\n      Gruvbox Light Red: صندوق أحمر فاتح\n      Gruvbox Dark Yellow: صندوق أصفر غامق\n      Catppuccin Frappe Flamingo: كاتبوتشينو فرابيه فلامنجو\n      Gruvbox Dark Aqua: صندوق مائي داكن\n      Gruvbox Light Blue: صندوق أزرق فاتح\n      Gruvbox Light Purple: صندوق بنفسجي فاتح\n      Catppuccin Frappe Red: كاتبوتشيني فرابيه أحمر\n      Catppuccin Frappe Maroon: كاتبوتشينو فرابيه كستنائي\n      Catppuccin Frappe Green: كاتبوتشيني فرابيه أخضر\n      Catppuccin Frappe Rosewater: كاتبوتشيني فرابيه ماء الورد\n      Catppuccin Frappe Pink: كاتبوتشين فرابيه وردي\n      Catppuccin Frappe Mauve: كاتبوتشيني فرابيه بنفسجي فاتح\n      Catppuccin Frappe Peach: كاتبوتشيني فرابيه خوخ\n      Catppuccin Frappe Yellow: كاتبوتشيني فرابيه أصفر\n      Catppuccin Frappe Teal: كاتبوتشين فرابيه أزرق مخضر\n      Catppuccin Frappe Sapphire: كاتبوتشينو فرابيه ياقوت\n      Catppuccin Frappe Blue: كاتبوتشينو فرابيه أزرق\n      Gruvbox Dark Green: صندوق أخضر غامق\n      Gruvbox Light Orange: صندوق برتقالي فاتح\n      Everforest Light Aqua: إيفرفورست المائي الفاتح\n      Everforest Dark Purple: إيفرفورست الأرجواني الداكن\n      Everforest Dark Red: إيفرفورست الأحمر الداكن\n      Everforest Dark Orange: إيفرفورست البرتقالي الداكن\n      Everforest Dark Green: إيفرفورست الأخضر الداكن\n      Everforest Dark Yellow: إيفرفورست الأصفر الداكن\n      Everforest Dark Aqua: إيفرفورست المائي الداكن\n      Everforest Dark Blue: إيفرفورست الأزرق الداكن\n      Everforest Light Red: إيفرفورست الأحمر الفاتح\n      Everforest Light Orange: إيفرفورست البرتقالي الفاتح\n      Everforest Light Yellow: إيفرفورست الأصفر الفاتح\n      Everforest Light Green: إيفرفورست الأخضر الفاتح\n      Everforest Light Blue: إيفرفورست الأزرق الفاتح\n      Everforest Light Purple: إيفرفورست الأرجواني الفاتح\n    Secondary Color Theme: 'لون السِمة الثانوي'\n        #* Main Color Theme\n    UI Scale: مقياس واجهة المستخدم\n    Disable Smooth Scrolling: عطّل التمرير المتجانس\n    Expand Side Bar by Default: كبّر الشريط الجانبي بشكل افتراضي\n    Hide Side Bar Labels: إخفاء تسميات الشريط الجانبي\n    Hide FreeTube Header Logo: إخفاء شعار رأس FreeTube\n  Player Settings:\n    Player Settings: 'المشغل'\n    Play Next Video: 'التشغيل التلقائي لمقاطع الفيديو الموصى بها'\n    Turn on Subtitles by Default: 'شغّل الترجمات بشكل افتراضي'\n    Autoplay Videos: 'شغًل مقاطع الفيديو تلقائياً'\n    Proxy Videos Through Invidious: 'استخدم Invidious كوسيط للفيديوهات'\n    Autoplay Playlists: 'شغّل قوائم التشغيل تلقائياً'\n    Enable Theatre Mode by Default: 'فعّل وضع المسرح بشكل افتراضي'\n    Default Volume: 'مستوى الصوت الافتراضي'\n    Default Playback Rate: 'معدّل سرعة التشغيل الافتراضية'\n    Default Video Format:\n      Default Video Format: 'تنسيق الفيديو الافتراضي'\n      Dash Formats: 'تنسيقات DASH'\n      Legacy Formats: 'تنسيقات قديمة'\n      Audio Formats: 'تنسيقات الصوت'\n    Default Quality:\n      Default Quality: 'الجودة الافتراضية'\n      Auto: 'تلقائية'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '‍8k'\n    Next Video Interval: العد التنازلي للتشغيل التلقائي\n    Scroll Volume Over Video Player: تمرير مستوى الصوت عبر مشغل الفيديو\n    Display Play Button In Video Player: عرض زر التشغيل في مشغل الفيديو\n    Fast-Forward / Rewind Interval: الفاصل الزمني السريع للأمام / الترجيع\n    Scroll Playback Rate Over Video Player: معدل تمرير التشغيل عبر مشغل الفيديو\n    Max Video Playback Rate: أقصى معدل تشغيل الفيديو\n    Video Playback Rate Interval: الفاصل الزمني لمعدل تشغيل الفيديو\n    Screenshot:\n      Enable: تفعيل لقطة الشاشة\n      Error:\n        Forbidden Characters: أحرف ممنوعة\n        Empty File Name: اسم المِلَفّ فارغ\n      Folder Button: اختر مجلد\n      File Name Label: نمط اسم المِلَفّ\n      Ask Path: اسأل عن موقع الحفظ\n      Folder Label: موقع لقطة الشاشة\n      Format Label: صيغة لقطة الشاشة\n      Quality Label: جودة لقطة الشاشة\n      File Name Tooltip: يمكنك استخدام المتغيرات أدناه. %Y السنة 4 أرقام. %M الشهر رقمان. %D اليوم رقمان. %H الساعة رقمان. %N الدقيقة رقمان. %S الثانية رقمان. %T الجزء من الثانية 3 أرقام. %s الثانية للفيديو رقمان. %t الجزء من الثانية للفيديو 3 أرقام. %i رقم معرف الفيديو.\n    Enter Fullscreen on Display Rotate: وضع ملء الشاشة عند تدوير الشاشة\n    Skip by Scrolling Over Video Player: تخطي بالتمرير فوق مشغل الفيديو\n    Default Viewing Mode:\n      Picture in Picture: صورة في صورة\n      External Player: مشغل خارجي ({externalPlayerName})\n      Default Viewing Mode: وضع العرض الافتراضي\n      Theater: مسرح\n      Full Screen: ملء الشاشة\n    Autoplay Interruption Timer: مؤقت مقاطعة التشغيل التلقائي\n  Privacy Settings:\n    Privacy Settings: 'الخصوصية'\n    Remember History: 'تذكر سجل المشاهدة'\n    Save Watched Progress: 'حفظ نسبة المشاهدة'\n    Clear Search Cache: 'مسح ذاكرة التخزين المؤقت للبحث'\n    Are you sure you want to clear out your search cache?: 'هل أنت متأكد أنك تريد مسح ذاكرة التخزين المؤقت للبحث؟'\n    Search cache has been cleared: 'تم مسح ذاكرة التخزين المؤقت للبحث'\n    Remove Watch History: 'إزالة سجل المشاهدة'\n    Are you sure you want to remove your entire watch history?: 'هل أنت متأكد من أنك تريد إزالة سجل المشاهدة بالكامل؟'\n    Watch history has been cleared: 'تم مسح سجل المشاهدة'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: هل أنت متأكد أنك تريد إزالة جميع الاشتراكات والملفات الشخصية؟ لا يمكن التراجع عن هذا.\n    Remove All Subscriptions / Profiles: إزالة جميع الاشتراكات \\ الملفات الشخصية\n    Save Watched Videos With Last Viewed Playlist: حفظ مقاطع الفيديو التي تمت مشاهدتها مع آخر قائمة تشغيل تم عرضها\n    All playlists have been removed: تمت إزالة جميع قوائم التشغيل\n    Remove All Playlists: إزالة كافة قوائم التشغيل\n    Are you sure you want to remove all your playlists?: هل أنت متأكد أنك تريد إزالة جميع قوائم التشغيل الخاصة بك؟\n    Are you sure you want to clear out your search history and cache?: هل أنت متأكد من أنك تريد مسح سجل البحث وذاكرة التخزين المؤقت؟\n    Remember Search History: تذكر سجل البحث\n    Clear Search History and Cache: مسح سجل البحث وذاكرة التخزين المؤقت\n    Search history and cache have been cleared: تم مسح سجل البحث وذاكرة التخزين المؤقت\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: تلقائي\n        Semi-auto: شبه آلي\n        Never: أبداً\n      Tooltip: 'تلقائي = حفظ عند كل خروج من صفحة الفيديو، عند انتهاء الفيديو وظهور خطأ (مثلاً: معدل محدود أو انتهاء جلسة المشاهدة). شبه تلقائي = يُشبه الوضع التلقائي إلا عند الخروج من صفحة الفيديو، ويمكن حفظ التقدم يدويًا عبر زر \"حفظ تقدم المشاهدة\" الموجود أسفل مشغل الفيديو.'\n  Subscription Settings:\n    Subscription Settings: 'الاشتراك'\n    Fetch Feeds from RSS: 'جلب المحتوى عن طريق RSS'\n    Fetch Automatically: جلب الخلاصة تلقائيا\n    Confirm Before Unsubscribing: تجنب إلغاء الاشتراك عن طريق الخطأ\n\n    To: إلى\n    'Limit the number of videos displayed for each channel': تحديد عدد مقاطع الفيديو المعروضة لكل قناة\n  Data Settings:\n    How do I import my subscriptions?: كيف استورد اشتراكاتي؟\n    Unknown data key: مفتاح البيانات مجهول\n    Unable to write file: غير قادر على كتابة الملف\n    Unable to read file: غير قادر على قراءة الملف\n    All watched history has been successfully exported: تم تصدير السجلّ بنجاح\n    All watched history has been successfully imported: تم استيراد السجلّ بنجاح\n    History object has insufficient data, skipping item: لا يحتوي عنصر السجلّ على بيانات كافية, تخطي العنصر\n    Subscriptions have been successfully exported: تم تصدير الاشتراكات بنجاح\n    Export History: تصدير السجلّ\n    Import History: استيراد السجلّ\n    Invalid history file: ملف السجلّ غير صالح\n    Invalid subscriptions file: ملف الاشتراكات غير صالح\n    All subscriptions have been successfully imported: تم استيراد جميع الاشتراكات بنجاح\n    All subscriptions and profiles have been successfully imported: تم استيراد جميع الاشتراكات والملفات الشخصية بنجاح\n    Profile object has insufficient data, skipping item: لا يحتوي عنصر الملف الشخصي على بيانات كافية, تخطي العنصر\n    Export NewPipe: تصدير NewPipe\n    Export YouTube: تصدير Youtube\n    Export FreeTube: تصدير FreeTube\n    Export Subscriptions: تصدير الاشتراكات\n    Import Subscriptions: استيراد الاشتراكات\n    Select Export Type: حدّد نوع التصدير\n    Data Settings: البيانات\n    Manage Subscriptions: إدارة الإشتراكات\n    All playlists has been successfully imported: تم استيراد جميع قوائم التشغيل بنجاح\n    Playlist insufficient data: 'بيانات غير كافية لقائمة التشغيل \"{playlist}\" ، تخطي العنصر'\n    All playlists has been successfully exported: تم تصدير جميع قوائم التشغيل بنجاح\n    Import Playlists: استيراد قوائم التشغيل\n    Export Playlists: تصدير قوائم التشغيل\n    Subscription File: Subscription ملف\n    History File: ملف التاريخ\n    Playlist File: Playlist ملف\n    Export Playlists For Older FreeTube Versions:\n      Label: تصدير قوائم التشغيل لإصدارات FreeTube الأقدم\n      Tooltip: \"يقوم هذا الخيار بتصدير مقاطع الفيديو من جميع قوائم التشغيل إلى قائمة تشغيل واحدة تسمى \\\"المفضلة\\\".\\nكيفية تصدير واستيراد مقاطع الفيديو في قوائم التشغيل لإصدار أقدم من FreeTube:\\n1. قم بتصدير قوائم التشغيل الخاصة بك مع تمكين هذا الخيار.\\n2. احذف جميع قوائم التشغيل الموجودة لديك باستخدام خيار إزالة جميع قوائم التشغيل ضمن إعدادات الخصوصية.\\n3. قم بتشغيل الإصدار الأقدم من FreeTube واستورد قوائم التشغيل المصدرة.\\\"\"\n  Distraction Free Settings:\n    Hide Live Chat: اخفي الدردشة المباشرة\n    Hide Popular Videos: اخفي الفيديوهات الأكثر شعبية\n    Hide Trending Videos: اخفي الفيديوهات الرائجة\n    Hide Recommended Videos: اخفي الفيديوهات الموصّى بها\n    Hide Comment Likes: اخفي اعجابات التعليقات\n    Hide Channel Subscribers: اخف عدد اشتراكات القناة\n    Hide Video Views: اخف عدد مشاهدات الفيديو\n    Hide Video Likes And Dislikes: إخفاء الإعجاب وعدم الإعجاب للفيديو\n    Distraction Free Settings: عدم الإزعاج\n    Hide Active Subscriptions: اخفي الإشتراكات الناشطة\n    Hide Playlists: إخفاء قوائم التشغيل\n    Hide Video Description: إخفاء وصف الفيديو\n    Hide Comments: إخفاء التعليقات\n    Hide Sharing Actions: إخفاء إجراءات المشاركة\n    Hide Videos on Watch: 'أخفِ الفيديوهات عند مشاهدتها'\n    Hide Live Streams: إخفاء البث المباشر\n    Hide Chapters: إخفاء الفصول\n    Hide Upcoming Premieres: إخفاء العروض الأولى القادمة\n    Hide Channels: إخفاء مقاطع الفيديو من القنوات\n    Hide Channels Placeholder: معرف القناة\n    Display Titles Without Excessive Capitalisation: عرض العناوين بدون استخدام الأحرف الكبيرة وعلامات الترقيم بشكل مفرط\n    Hide Featured Channels: إخفاء القنوات المميزة\n    Hide Channel Playlists: إخفاء علامة التبويب \"قوائم التشغيل\" للقناة\n    Hide Channel Shorts: إخفاء علامة التبويب \"المقاطع القصيرة\" للقناة\n    Sections:\n      Side Bar: الشريط الجانبي\n      Channel Page: صفحة القناة\n      Watch Page: صفحة المشاهدة\n      General: عام\n      Subscriptions Page: صفحة الاشتراكات\n    Hide Channel Podcasts: إخفاء علامة التبويب \"بودكاستات\" للقناة\n    Hide Channel Releases: إخفاء علامة التبويب \"إصدارات\" للقناة\n    Hide Subscriptions Live: إخفاء الاشتراكات مباشرة\n    Hide Subscriptions Shorts: إخفاء الاشتراكات الفيدوهات القصيرة\n    Hide Subscriptions Videos: إخفاء مقاطع فيديو الاشتراكات\n    Hide Profile Pictures in Comments: إخفاء صور الملف الشخصي في التعليقات\n    Hide Channels Invalid: معرف القناة المقدم غير صالح\n    Hide Channels Disabled Message: تم حظر بعض القنوات باستخدام المعرّف ولم تتم معالجتها. يتم حظر الميزة أثناء تحديث هذه المعرفات\n    Hide Channels Already Exists: معرف القناة موجود بالفعل\n    Hide Channels API Error: ‬حدث خطأ أثناء استرداد المستخدم بالمعرف المدخل. يرجى التحقق مرة أخرى إذا كان المعرف صحيحا.\n    Hide Videos, Playlists and Channels Containing Text: إخفاء مقاطع الفيديو وقوائم التشغيل التي تحتوي على نص\n    Hide Videos, Playlists and Channels Containing Text Placeholder: كلمة أو جزء كلمة أو عبارة\n    Hide Channel Home: إخفاء علامة التبويب \"الصفحة الرئيسية\" للقناة\n    Show Added Items: إظهار العناصر المضافة\n    Hide Channel Courses: إخفاء علامة التبويب \"دورات\" القناة\n    Hide Channel Posts: إخفاء علامة تبويب \"المنشورات\" للقناة\n    Hide Subscriptions Posts: إخفاء منشورات الاشتراكات\n  The app needs to restart for changes to take effect. Restart and apply change?: البرنامج يحتاج لإعادة التشغيل كي يسري مفعول التغييرات. هل تريد إعادة التشغيل و تطبيق التغييرات؟\n  Proxy Settings:\n    City: المدينة\n    Region: المنطقة\n    Country: البلد\n    Ip: عنوان الإيبي\n    Your Info: معلوماتك\n    Test Proxy: اختبار البروكسي\n    Proxy Port Number: رقم منفذ البروكسي\n    Proxy Host: خادوم البروكسي\n    Proxy Protocol: بروتوكول البروكسي\n    Enable Tor / Proxy: تفعيل تور / البروكسي\n    Proxy Settings: البروكسي\n    Error getting network information. Is your proxy configured properly?: هنالك خطأ في جلب معلومات الشبكة. هل ضبطت إعدادات وكيلك بصورة صحيحة؟\n    Clicking on Test Proxy will send a request to: النقر على اختبار البروكسي سيؤدي إلى إرسال طلب إلى\n    Proxy Warning: لا يحتوي FreeTube على وكيل مدمج ولكن يمكنه الاتصال بوكيل خارجي، مثل وكيل يعمل على جهازك مثل Tor أو وكيل خارجي مثل وكيل SOCKS5 الذي توفره بعض شبكات VPN. إذا تم التمكين، فتأكد من تكوين الوكيل/الاختصاص الخاص بك بشكل صحيح، وإلا فلن يتمكن FreeTube من جلب أي بيانات.\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: تنبيه عندما يتم تخطي شريحة الراعي\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API عنوان (الافتراضي هو https://sponsor.ajay.app)\n    Enable SponsorBlock: تفعيل حجب الرعاة\n    SponsorBlock Settings: حظر الرعاة\n    Category Color: لون الفئة\n    Skip Options:\n      Auto Skip: تخطي تلقائي\n      Prompt To Skip: موجه للتخطي\n      Skip Option: تخطي الخِيار\n      Show In Seek Bar: إظهار في الشريط\n      Do Nothing: لا تفعل شيئا\n    UseDeArrowTitles: استخدام عناوين فيديو DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': عنوان URL لواجهة برمجة التطبيقات DeArrow Thumbnail Generator (الافتراضي هو https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: استخدم DeArarrow للصور المصغرة\n  External Player Settings:\n    External Player: المشغل الخارجي\n    Custom External Player Arguments: وسيطات المشغل الخارجي المخصصة\n    Custom External Player Executable: مشغل خارجي مخصص قابل للتنفيذ\n    Ignore Unsupported Action Warnings: تجاهل تحذيرات الإجراءات غير المدعومة\n    External Player Settings: المشغل الخارجي\n    Players:\n      None:\n        Name: لاشيء\n    Ignore Default Arguments: تجاهل الحجج الافتراضية\n  Parental Control Settings:\n    Hide Search Bar: إخفاء شريط البحث\n    Parental Control Settings: الرقابة الأبوية\n    Hide Unsubscribe Button: إخفاء زر إلغاء الاشتراك\n    Show Family Friendly Only: عرض مناسب للعائلة فقط\n    Hide Uploader on Watch page: إخفاء الرافع من صفحة المشاهدة\n  Experimental Settings:\n    Replace HTTP Cache: استبدال ذاكرة التخزين المؤقت HTTP\n    Experimental Settings: الاختبارية\n    Warning: هذه الإعدادات تجريبية ، فهي تسبب أعطال أثناء تمكينها. يوصى بشدة بعمل نسخ احتياطية. استخدمها على مسؤوليتك الخاصة!\n  Password Settings:\n    Set Password To Prevent Access: تعيين كلمة مرور لمنع الوصول إلى الإعدادات\n    Remove Password: إزالة كلمة المرور\n    Password Settings: كلمة المرور\n    Set Password: ضبط كلمة السر\n  Password Dialog:\n    Password: كلمة السر\n    Enter Password To Unlock: أدخل كلمة المرور لإلغاء قفل الإعدادات\n  Sort Settings Sections (A-Z): أقسام إعدادات الفرز (من الألف إلى الياء)\n  Return to Settings Menu: العودة إلى قائمة الإعدادات\nAbout:\n  #On About page\n  About: 'حول'\n  #& About\n  Donate: التبرع\n  Translate: ساعدنا في ترجمة Freetube\n  Chat on Matrix: الدردشة على ماتريكس\n  Mastodon: ماستدون\n  Email: البريد الإلكتروني\n  Blog: المدوّنة\n  Website: موقع الويب\n  Report a problem: الإبلاغ عن مشكلة\n  FAQ: الأسئلة المتداولة\n  Help: المساعدة\n  Source code: الشفرة المصدرية\n  Beta: تجريبي\n  these people and projects: هؤلاء الناس والمشاريع\n  Credits: الاعتمادات\n  room rules: قواعد الغرفة\n  Please check for duplicates before posting: يرجى التحقق من التكرارات قبل النشر\n  GitHub issues: مشاكل GitHub\n  FreeTube Wiki: ويكي Freetube\n  GitHub releases: إصدارات GitHub\n  Downloads / Changelog: التحميلات\\التغييرات\n  Discussions: المناقشات\n  AGPLv3: رخصة أفيرو العمومية الإصدار ٣\nProfile:\n  All Channels: 'جميع القنوات'\n  Profile Manager: 'مدير الملف الشخصي'\n  Create New Profile: 'إنشاء ملف شخصي جديد'\n  Edit Profile: 'تعديل الملف الشخصي'\n  Color Picker: 'أداة انتقاء اللون'\n  Custom Color: 'لون مخصص'\n  Profile Preview: 'معاينة الملف الشخصي'\n  Create Profile: 'إنشاء ملف شخصي'\n  Update Profile: 'تحديث الملف الشخصي'\n  Make Default Profile: 'اجعله ملف شخصي افتراضي'\n  Delete Profile: 'حذف الملف الشخصي'\n  Are you sure you want to delete this profile?: 'هل أنت متأكد أنك تريد حذف هذا الملف الشخصي؟'\n  All subscriptions will also be deleted.: 'ستُمحى جميع الاشتراكات أيضاً.'\n  Your profile name cannot be empty: 'لا يمكن أن يكون اسم ملفك الشخصي فارغاً'\n  Profile has been created: 'تم إنشاء الملف الشخصي'\n  Profile has been updated: 'تم تحديث الملف الشخصي'\n  Your default profile has been set to {profile}: 'تم تعيين ملف التعريف الافتراضي الخاص بك إلى {profile}'\n  Removed {profile} from your profiles: 'تمت إزالة {profile} من ملفاتك الشخصية'\n  Your default profile has been changed to your primary profile: 'تم تغيير ملفك الشخصي الافتراضي إلى ملفك الشخصي الأساسي'\n  '{profile} is now the active profile': '{profile} هو الآن الملف الشخصي النشط'\n#On Channel Page\n  Profile Select: اختيار الملف الشخصي\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: هل أنت متأكد أنك تريد حذف القنوات المُحددة؟ لن يؤدي هذا إلى حذف القناة من أي ملف شخصي آخر.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : هذا هو ملفك الشخصي الأساسي. هل أنت متأكد أنك تريد حذف القنوات المُحددة؟ سيتم حذف القنوات نفسها إن وجدت في أي ملف شخصي.\n  No channel(s) have been selected: لم يتم تحديد أي قناة/قنوات\n  Add Selected To Profile: إضافة المُحدد إلى الملف الشخصي\n  Delete Selected: حذف المُحدد\n  Select None: إلغاء التحديد\n  Select All: تحديد الكل\n  '{number} selected': '{number} محدد'\n  Other Channels: قنوات أُخرى\n  Subscription List: قائمة الاشتراكات\n  Profile Filter: مرشح الملف الشخصي\n  Profile Settings: الملف الشخصي\n  Toggle Profile List: تبديل قائمة الملف الشخصي\n  Open Profile Dropdown: فتح القائمة المنسدلة للملف الشخصي\n  Close Profile Dropdown: إغلاق القائمة المنسدلة للملف الشخصي\n  Profile Name: اسم الملف الشخصي\n  Edit Profile Name: تحرير اسم الملف الشخصي\n  Create Profile Name: إنشاء اسم الملف الشخصي\nChannel:\n  Subscribe: 'اشتراك'\n  Unsubscribe: 'إلغاء الاشتراك'\n  Search Channel: 'ابحث في القناة'\n  Your search results have returned 0 results: 'لم تُعد نتيجة بحثك أي نتائج'\n  Videos:\n    Videos: 'الفيديوهات'\n    This channel does not currently have any videos: 'لا تحتوي هذه القناة على أي فيديوهات حالياً'\n    Sort Types:\n      Newest: 'الأحدث'\n      Oldest: 'الأقدم'\n      Most Popular: 'الأكثر شهرة'\n  Playlists:\n    Playlists: 'قوائم التشغيل'\n    This channel does not currently have any playlists: 'لا تحتوي هذه القناة حالياً على أي قوائم تشغيل'\n    Sort Types:\n      Last Video Added: 'آخر فيديو تمت إضافته'\n      Newest: 'الأحدث'\n      Oldest: 'الأقدم'\n  About:\n    About: 'حول'\n    Channel Description: 'وصف القناة'\n    Featured Channels: 'القنوات المميزة'\n    Tags:\n      Tags: الوسوم\n      Search for: ابحث عن «{tag}»\n    Details: التفاصيل\n    Joined: انضم\n    Location: الموقع\n  Added channel to your subscriptions: تم إضافة القناة إلى اشتراكاتك\n  Removed subscription from {count} other channel(s): 'تمت إزالة الاشتراك من {count} قناة (قنوات) أخرى'\n  Channel has been removed from your subscriptions: تمت إزالة القناة من اشتراكاتك\n  Channel Tabs: علامات تبويب القنوات\n  This channel does not exist: هذه القناة غير موجودة\n  This channel does not allow searching: هذه القناة لا تسمح بالبحث\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: هذه القناة مصنفة حسب العمر ولا يمكن عرضها حاليا في FreeTube.\n  Posts:\n    This channel currently does not have any posts: لا تحتوي هذه القناة حاليا على أي مشاركات\n    Hide Answers: إخفاء الأجوبة\n    votes: '{votes} أصوات'\n    Reveal Answers: كشف الإجابات\n    Video hidden by FreeTube: تم إخفاء الفيديو بواسطة FreeTube\n    Viewing Posts Only Supported By Invidious: عرض المنشورات مدعوم فقط من قبل Invidious. توجه إلى علامة التبويب مجتمع القناة لعرض المحتوى هناك دون Invidious.\n    View Full Post: عرض المنشور كاملا\n  Live:\n    Live: مباشر\n    This channel does not currently have any live streams: لا يوجد حاليا أي بث مباشر على هذه القناة\n  Shorts:\n    This channel does not currently have any shorts: هذه القناة ليس لديها حاليا أي أفلام قصيرة (shorts)\n  Podcasts:\n    Podcasts: البودكاست\n    This channel does not currently have any podcasts: لا تحتوي هذه القناة حاليا على أي بودكاست\n  Releases:\n    Releases: الاصدارات\n    This channel does not currently have any releases: هذه القناة ليس لديها أي إصدارات حاليا\n  Home:\n    Home: الصفحة الرئيسية\n    View Playlist: إظهار قائمة التشغيل\n  Courses:\n    Courses: الدورات\n    This channel does not currently have any courses: هذه القناة لا تحتوي حاليًا على أي دورات\nVideo:\n  Mark As Watched: 'علّمه كفيديو تمت مشاهدته'\n  Remove From History: 'إزالة من سجلّ المشاهدة'\n  Video has been marked as watched: 'تم تعليم الفيديو كمُشاهد'\n  Video has been removed from your history: 'تم إزالة الفيديو من سجّلك'\n  Open in YouTube: 'افتح في اليوتيوب'\n  Copy YouTube Link: '‫انسخ رابط اليوتيوب'\n  Open YouTube Embedded Player: 'افتح في مشغّل اليوتيوب المُضمّن'\n  Copy YouTube Embedded Player Link: 'انسخ رابط مشغل اليوتيوب المُضمّن'\n  Open in Invidious: 'إفتح على انفيديوس'\n  Copy Invidious Link: 'انسخ رابط انفيديوس'\n  Views: 'مشاهدات'\n  Watched: 'مُشاهد'\n  # As in a Live Video\n  Live: '‏‏‪مُباشر'\n  Live Now: 'مُباشر الآن'\n  Live Chat: 'محادثة مباشرة'\n  Enable Live Chat: 'فعّل المحادثة المباشرة'\n  Live Chat is currently not supported in this build.: 'المحادثة المباشرة غير مدعومة حالياً في هذا الإصدار.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'تم تمكين المحادثة المباشرة. ستظهر رسائل المحادثة هنا بمجرد إرسالها.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'المحادثة المباشرة غير مدعومة حالياً مع Invidious API. يلزم الاتصال المباشر بيوتيوب.'\n  Published:\n    In less than a minute: في أقل من دقيقة\n  Published on: 'نُشر في'\n#& Videos\n  Autoplay: تشغيل تلقائي\n  Previous: السابق\n  Next: التالي\n  Reverse Playlist: عكس قائمة التشغيل\n  Shuffle Playlist: ‮خلط قائمة التشغيل\n  Loop Playlist: تكرار قائمة التشغيل\n  Starting soon, please refresh the page to check again: سيبدأ قريباً ، يرجى تحديث الصفحة للتحقق مرة أخرى\n  Started streaming on: بدأ البث على\n  Streamed on: تبث على\n  Copy Invidious Channel Link: انسخ رابط قناة انفيديوس\n  Open Channel in Invidious: افتح القناة على انفيديوس\n  Copy YouTube Channel Link: انسخ رابط قناة اليوتيوب\n  Open Channel in YouTube: افتح القناة على يوتيوب\n  Video has been saved: تم حفظ الفيديو\n  Save Video: احفظ الفيديو\n  Video has been removed from your saved list: تمت إزالة الفيديو من قائمتك المحفوظة\n  Sponsor Block category:\n    music offtopic: موسيقى خارجة عن المألوف\n    interaction: تفاعل\n    self-promotion: الترويج الذاتي\n    outro: الخاتمة\n    intro: المقدمة\n    sponsor: الرعاة\n    filler: حشو\n    recap: الخلاصة\n  External Player:\n    Unsupported Actions:\n      looping playlists: تكرار قوائم التشغيل\n      shuffling playlists: خلط قوائم التشغيل\n      reversing playlists: عكس قوائم التشغيل\n      opening specific video in a playlist (falling back to opening the video): فتح فيديو محدد في قائمة التشغيل (العودة إلى فتح الفيديو)\n      opening playlists: فتح قوائم التشغيل\n      setting a playback rate: ضبط معدل التشغيل\n      starting video at offset: بدء تشغيل الفيديو عند الإزاحة\n    UnsupportedActionTemplate: '{externalPlayer} لا يدعم: {action}'\n    OpeningTemplate: 'جارٍ فتح {videoOrPlaylist} في {externalPlayer} ...'\n    playlist: قائمة التشغيل\n    video: فيديو\n    OpenInTemplate: فتح في {externalPlayer}\n  Premieres: العرض الأولي\n  Scroll to Bottom: انتقل إلى الأسفل\n  Show Super Chat Comment: إظهار تعليق Super Chat\n  Upcoming: القادمة\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': الدردشة المباشرة غير متاحة لهذا البث. ربما تم تعطيلها من قبل القائم بالتحميل.\n  Unhide Channel: عرض القناة\n  Hide Channel: إخفاء القناة\n  More Options: المزيد من الخيارات\n  Player:\n    TranslatedCaptionTemplate: '{language} (مترجمة من \"{originalLanguage}\")'\n    Stats:\n      Volume: 'الحجم: {volumePercentage}%'\n      CodecAudio: 'برنامج الترميز: {audioCodec} ({audioItag})'\n      Media Formats: 'تنسيقات الوسائط: {formats}'\n      Player Dimensions: 'أبعاد المشغل: {width}×{height}'\n      Bitrate: 'معدل البت: {bitrate} كيلوبت في الثانية'\n      CodecsVideoAudioNoItags: 'برامج الترميز: {videoCodec} / {audioCodec}'\n      Buffered: 'المخزن المؤقت: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'الإطارات المسقطة: {droppedFrames} / إجمالي الإطارات: {totalFrames}'\n      CodecsVideoAudio: 'برامج الترميز: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Stats: الاحصائيات\n      Video ID: 'معرف الفيديو: {videoId}'\n      Resolution: 'الدقة: {width}x{height}{''@''}{frameRate}'\n      Bandwidth: 'عرض النطاق الترددي: {bandwidth} كيلوبت في الثانية'\n    Skipped segment: تم تخطي شريحة {segmentCategory}\n    Theatre Mode: وضع المسرح\n    Exit Theatre Mode: الخروج من وضع المسرح\n    Show Stats: عرض الاحصائيات\n    You appear to be offline: يبدو أنك غير متصل بالإنترنت.\n    Playback will resume automatically when your connection comes back: سيتم استئناف التشغيل تلقائيًا عندما يعود اتصالك.\n    Audio Tracks: المسارات الصوتية\n    Full Window: الشاشة كاملة\n    Exit Full Window: الخروج من وضع الشاشة الكاملة\n    Take Screenshot: اخذ لقطة الشاشة\n    Hide Stats: اخفاء الاحصائيات\n    Autoplay is off: التشغيل التلقائي متوقف\n    Autoplay is on: التشغيل التلقائي مفعل\n  IP block: حظر YouTube عنوان IP الخاص بك من مشاهدة مقاطع الفيديو. يرجى محاولة التبديل إلى VPN أو وكيل مختلف.\n  Unlisted: غير مدرج\n  AgeRestricted: لا يمكن مشاهدة مقاطع الفيديو المقيدة حسب العمر مع FreeTube لأنها تتطلب تسجيل الدخول إلى Google واستخدام حساب YouTube تم التحقق من عمره.\n  MembersOnly: لا يمكن مشاهدة مقاطع الفيديو الخاصة بالأعضاء فقط مع FreeTube لأنها تتطلب تسجيل الدخول إلى Google والعضوية المدفوعة لقناة القائم بالتحميل.\n#& Playlists\n  DeArrow:\n    Show Modified Details: إظهار التفاصيل المعدلة\n    Show Original Details: إظهار التفاصيل الأصلية\n  DRMProtected: لا يمكن تشغيل مقاطع الفيديو المحمية بنظام إدارة الحقوق الرقمية في FreeTube، لأنها تتطلب مكونات خاصة ومغلقة المصدر. إذا كنت ترغب في مشاهدة هذا الفيديو، فيرجى مشاهدته على موقع يوتيوب الرسمي في متصفح ويب يدعم إدارة الحقوق الرقمية.\n  Save Watched Progress: حفظ التقدم الذي تمت مشاهدته\n  Watched Progress Saved: تم مشاهدة التقدم المحفوظ\nPlaylist:\n  #& About\n  View Full Playlist: 'عرض قائمة التشغيل بالكامل'\n  Last Updated On: 'تم إجراء التعديل الأخير في'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: قائمة التشغيل\n  Sort By:\n    DateAddedNewest: آخر مضاف أولا\n    DateAddedOldest: الأقدم إضافتا أولا\n    AuthorAscending: الكاتب (A-Z)\n    AuthorDescending: الكاتب (Z-A)\n    VideoTitleAscending: العنوان (A-Z)\n    VideoTitleDescending: العنوان (Z-A)\n    Custom: مُخصّص\n    VideoDurationDescending: المدة (الاطول أولاً)\n    VideoDurationAscending: المدة (الأقصر أولاً)\n    PublishedNewest: أحدث منشور أولاً\n    PublishedOldest: أقدم منشور أولاً\nChange Format:\n  Change Media Formats: 'تغيير تنسيقات الفيديو'\n  Use Dash Formats: 'استخدم تنسيقات DASH'\n  Use Legacy Formats: 'استخدم التنسيقات التراثية'\n  Use Audio Formats: 'استخدم تنسيقات الصوت'\n  Audio formats are not available for this video: تنسيقات الصوت غير متوفرة لهذا الفيديو\n  Dash formats are not available for this video: تنسيقات DASH غير متوفرة لهذا الفيديو\n  Legacy formats are not available for this video: لا تتوفر التنسيقات القديمة لهذا الفيديو\nShare:\n  Share Video: 'شارك الفيديو'\n  Share Playlist: 'مشاركة قائمة التشغيل'\n  Copy Link: 'انسخ الرابط'\n  Open Link: 'افتح الرابط'\n  Copy Embed: 'انسخ المُضمّن'\n  Open Embed: 'افتح التضمين'\n  # On Click\n  Invidious URL copied to clipboard: 'تم نسخ رابط Invidious إلى الحافظة'\n  Invidious Embed URL copied to clipboard: 'تم نسخ رابط Invidious المُضمّن إلى الحافظة'\n  YouTube URL copied to clipboard: 'تم نسخ رابط اليوتيوب إلى الحافظة'\n  YouTube Embed URL copied to clipboard: 'تم نسخ رابط يوتيوب المُضمّن إلى الحافظة'\n  Include Timestamp: تضمين الختم الزمني\n  YouTube Channel URL copied to clipboard: تم نسخ رابط قناة اليوتيوب\n  Invidious Channel URL copied to clipboard: تم نسخ رابط قناة انفيديوس\n  Share Channel: مشاركة القناة\nMini Player: 'المشغل المصغّر'\nComments:\n  Comments: 'التعليقات'\n  Click to View Comments: 'انقر لمشاهدة التعليقات'\n  Getting comment replies, please wait: 'جاري الحصول على ردود التعليق, يرجى الانتظار'\n  Hide Comments: 'إخفاء التعليقات'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'لا يتوفر تعليقات لهذا الفيديو'\n  Load More Comments: 'تحميل المزيد من التعليقات'\n  There are no more comments for this video: لا يوجد المزيد من التعليقات لهذا الفيديو\n  Newest first: الأحدث أولاً\n  Top comments: أهم التعليقات\n  Show More Replies: إظهار المزيد من الردود\n  Pinned by: تم التثبيت بواسطة\n  Member: عضو\n  View {replyCount} replies: عرض {replyCount} ردود\n  Hearted: القلب\n  Subscribed: مشترك\n  There are no comments available for this post: لا توجد تعليقات متاحة لهذا المنشور\nUp Next: 'التالي'\n\n# Toast Messages\nLocal API Error (Click to copy): 'خطأ API المحلي (انقر للنسخ)'\nInvidious API Error (Click to copy): 'خطأ Invidious API ( انقر للنسخ)'\nFalling back to Invidious API: 'التراجع إلى Invidious API'\nFalling back to Local API: 'التراجع إلى API المحلي'\nLoop is now disabled: 'تم تعطيل التكرار'\nLoop is now enabled: 'تم تمكين التكرار'\nShuffle is now disabled: 'تم تعطيل التبديل العشوائي'\nShuffle is now enabled: 'تم تمكين التبديل العشوائي'\nPlaying Next Video: 'جاري تشغيل الفيديو التالي'\nPlaying Previous Video: 'جاري تشغيل الفيديو السابق'\nCanceled next video autoplay: 'تم إلغاء التشغيل التلقائي للفيديو التالي'\n'The playlist has ended. Enable loop to continue playing': 'انتهت قائمة التشغيل. قم بتمكن التكرار لمواصلة التشغيل'\n\nYes: 'نعم'\nNo: 'لا'\nThe playlist has been reversed: تم عكس قائمة التشغيل\nA new blog is now available, {blogTitle}. Click to view more: 'هناك مدونة جديدة متاحة الآن ، {blogTitle}. انقر لعرض المزيد'\nDownload From Site: تنزيل من الموقع\nVersion {versionNumber} is now available!  Click for more details: 'الإصدار {versionNumber} متاح الآن!  انقر لمزيد من التفاصيل'\nTooltips:\n  General Settings:\n    Thumbnail Preference: كلّ الصّور المصغّرة في FreeTube سيتمّ استبدالها بإطار من الفيديو، يكون ضبابيًا أو مخفيًا، بدل من الصّورة المصغّرة الافتراضيّة.\n    Preferred API Backend: اختر الواجهة الخلفية التي يستخدمها FreeTube لجلب البيانات. الواجهة البرمجية المحلية للتطبيق هي مستخرج محلي. الواجهة البرمجية للتطبيق التابعة لInvidious (بديل لموقع يوتيوب) يتطلب التواصل مع خادم شبكة Invidious.\n    Invidious Instance: مثيل Invidious الذي سيتصل به FreeTube لاستدعاءات API.\n    Fallback to Non-Preferred Backend on Failure: عند التفعيل اذا واجه الAPI المفضّل لديك أيّ مشكلة، سيحاول FreeTube استخدام الAPI الغير مفضّل لديك تلقائيّاً كإجراء التراجع.\n    External Link Handling: \"اختر السلوك الافتراضي عند النقر فوق رابط، لا يمكن فتحه في FreeTube.\\nبشكل افتراضي، سيفتح FreeTube الرابط الذي تم النقر عليه في المتصفح الافتراضي.\\n\"\n    Region for Trending: الانتشار المحلي (Trend) يسمح لك بأن تشاهد الفيديوهات الأكثر انتشارا حسب الدولة. ليست كل الدول المعروضة في هذه القائمة مدعومة من طرف يوتيوب.\n    Open Deep Links In New Window: يتم فتح عناوين URL التي تم تمريرها إلى FreeTube، مثل إعادة توجيه ملحقات المتصفح أو حجج سطر الأوامر، في نافذة جديدة.\n  Player Settings:\n    Proxy Videos Through Invidious: سيتم الاتصال بـ Invidious لعرض مقاطع الفيديو بدلاً من إجراء اتصال مباشر بـ YouTube.\n    Default Video Format: حدّد التنسيقات المستخدمة عند تشغيل الفيديو. تنسيق داش (التدفق الميكانيكي المتكيّف عبر بروتوكول نقل النص التشعبي) يمكنها أن تُشغِّل جودات أعلى. التنسيقات القديمة محدودة بجودة 360p كحدّ أقصى لكنها تستخدم عرضًا أقل للنطاق. التنسيقات الصوتية هي للتدفق الصوتي فقط.\n    Scroll Playback Rate Over Video Player: أثناء وجود المؤشر فوق الفيديو، اضغط مع الاستمرار على مفتاح التحكم (مفتاح القيادة على Mac) ومرر عجلة الماوس للأمام أو للخلف للتحكم في معدل التشغيل. اضغط مع الاستمرار على مفتاح التحكم (مفتاح الأوامر على Mac) ثم انقر فوق الماوس للعودة بسرعة إلى معدل التشغيل الافتراضي (1x ما لم يتم تغييره في الإعدادات).\n    Skip by Scrolling Over Video Player: استخدم عجلة التمرير لتخطي الفيديو بنمط MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: عند التفعيل، سيستخدم FreeTube بروتوكول RSS بدلاً من طريقته الافتراضية لجلب خلاصة الاشتراكات. يعتبر RSS أسرع ويساعد على منع حظر عنوان الـIP، لكنه لا يوفر بعض المعلومات مثل مدة الفيديو، حالة البث المباشر أو المنشورات\n    Fetch Automatically: عند التفعيل، سيقوم FreeTube تلقائيًا بجلب خلاصة الاشتراكات عند بدء التشغيل وعند فتح نافذة جديدة.\n  External Player Settings:\n    Custom External Player Arguments: أي وسيطات سطر أوامر مخصصة تريد تمريرها إلى المشغل الخارجي.\n    Ignore Warnings: منع التحذيرات عندما لا يدعم اللاعب الخارجي الحالي الإجراء الحالي (على سبيل المثال، عكس قوائم التشغيل، وما إلى ذلك).\n    Custom External Player Executable: بشكل افتراضي ، ستفترض FreeTube أنه يمكن العثور على المشغل الخارجي المختار عبر متغير بيئة PATH. إذا لزم الأمر ، يمكن تعيين مسار مخصص هنا.\n    External Player: سيؤدي اختيار مشغل خارجي إلى عرض رمز لفتح الفيديو (قائمة التشغيل إذا كانت مدعومة) في المشغل الخارجي على الصورة المصغرة. تحذير ، لا تؤثر إعدادات Invidious على المشغلات الخارجية.\n    DefaultCustomArgumentsTemplate: \"(الافتراضي: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: لا ترسل أي وسائط افتراضية إلى المشغل الخارجي بخلاف عنوان URL للفيديو (مثل معدل التشغيل وعنوان URL لقائمة التشغيل وما إلى ذلك). سيستمر تمرير الوسائط المخصصة.\n  Experimental Settings:\n    Replace HTTP Cache: تعطيل ذاكرة التخزين المؤقت HTTP المستندة إلى قرص Electron وتمكين ذاكرة تخزين مؤقت للصور في الذاكرة. سيؤدي إلى زيادة استخدام ذاكرة الوصول العشوائي.\n  Distraction Free Settings:\n    Hide Channels: أدخل معرف القناة لإخفاء جميع مقاطع الفيديو وقوائم التشغيل والقناة نفسها من الظهور في نتائج البحث والشائعة والأكثر شهرة والموصى بها. يجب أن يكون معرف القناة الذي تم إدخاله متطابقًا تمامًا وأن يكون حساسًا لحالة الأحرف.\n    Hide Subscriptions Live: يتم تجاوز هذا الإعداد من خلال إعداد \"{appWideSetting}\" على مستوى التطبيق، في قسم \"{subsection}\" من \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: أدخل كلمة أو جزء كلمة أو عبارة (غير حساسة لحالة الأحرف) لإخفاء جميع مقاطع الفيديو وقوائم التشغيل التي تحتوي عناوينها الأصلية عليها في جميع أنحاء FreeTube، باستثناء السجل وقوائم التشغيل الخاصة بك ومقاطع الفيديو الموجودة داخل قوائم التشغيل فقط.\n    Hide Videos on Watch: إخفاء مقاطع الفيديو التي تمت مشاهدتها من علامات التبويب \"مقاطع الفيديو\" و \"الفيديوهات القصيرة\" و \"البث المباشر\" في صفحتي الاشتراك والقناة. هذا لا يؤثر على علامة التبويب الرئيسية على صفحات القناة\n  SponsorBlock Settings:\n    UseDeArrowTitles: استبدل عناوين الفيديو بالعناوين التي أرسلها المستخدم من DeArrow.\n    UseDeArrowThumbnails: استبدل الصور المصغرة للفيديو بالصور المصغرة من DeArrow.\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: هذا الفيديو غير متاح الآن لعدم وجود ملفات فيديو . هذا قد يكون بسبب أن الفيديو غير متاح في بلدك.\nMore: المزيد\nPlaying Next Video Interval: سيتم تشغيل الفيديو التالي على الفور.| إضغط للإلغاء.| سيبدأ الفيديو التالي في {nextVideoInterval} ثانية.| إضغط للإلغاء.\nUnknown YouTube url type, cannot be opened in app: نوع URL غير معروف على YouTube، لا يمكن فتحه في التطبيق\nOpen New Window: افتح نافذة جديدة\nDefault Invidious instance has been cleared: تم مسح مثيل Invidious الافتراضي\nDefault Invidious instance has been set to {instance}: تم تعيين المثيل الافتراضي Invidious إلى {instance}\nSearch Bar:\n  Clear Input: مسح المدخلات\n  Remove: إزالة\nExternal link opening has been disabled in the general settings: تم تعطيل فتح الارتباط الخارجي في الإعدادات العامة\nAre you sure you want to open this link?: هل أنت متأكد أنك تريد فتح هذا الرابط؟\nScreenshot Success: تم حفظ لقطة الشاشة\nScreenshot Error: فشل أخذ لقطة للشاشة. {error}\nNew Window: نافذة جديدة\nChannels:\n  Count: تم العثور على قناة (قنوات) {number}.\n  Channels: القنوات\n  Title: قائمة القنوات\n  Search bar placeholder: البحث في القنوات\n  Empty: قائمة قنواتك فارغة حاليا.\n  Unsubscribe Prompt: 'هل أنت متأكد من أنك تريد إلغاء الاشتراك من \"{channelName}\"؟'\nClipboard:\n  Cannot access clipboard without a secure connection: لا يمكن الوصول إلى الحافظة دون اتصال آمن\n  Copy failed: فشل النسخ إلى الحافظة\nChapters:\n  Chapters: الفصول\n  Key Moments: ‌العناصر الرئيسية\nPreferences: التفضيلات\nOk: موافق\nHashtag:\n  This hashtag does not currently have any videos: هذا الهاشتاج ليس لديه حاليا أي مقاطع فيديو\n  Hashtag: هاشتاج\nChannel Hidden: تم إضافة {channel} إلى مرشح القناة\nGo to page: إذهب إلى {page}\nChannel Unhidden: تمت إزالة {channel} من مرشح القناة\nTrimmed input must be at least N characters long: يجب أن يكون طول الإدخال المقتطع حرفًا واحدًا على الأقل | يجب أن يبلغ طول الإدخال المقتطع {length} من الأحرف على الأقل\nTag already exists: العلامة \"{tagName}\" موجودة بالفعل\nAge Restricted:\n  This channel is age restricted: هذه القناة مقيدة بالعمر\n  This video is age restricted: هذا الفيديو مقيد بالفئة العمرية\nClose Banner: إغلاق الشعار\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nMoments Ago: منذ لحظات\nFeed:\n  Feed Last Updated: 'آخر تحديث لخلاصة {feedName}: {date}'\n  Refresh Feed: تحديث {subscriptionName}\nYes, Delete: نعم ، احذف\nYes, Restart: نعم، إعادة تشغيل\nYes, Open Link: نعم، افتح الرابط\nCancel: إلغاء\nSearch character limit: تجاوز استعلام البحث حد الأحرف {searchCharacterLimit}\nSearch Listing:\n  Label:\n    4K: 4K\n    Closed Captions: التعاليق مغلقة\n    Subtitles: التسميات التوضيحية\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: جديد\n    3D: ثلاثي الابعاد\nRight-click or hold to see history: انقر زر الفارة الأيمن أو اضغط مطولا لعرض السجل\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: تبديل أدوات المطور\n  Zoom In: تقريب\n  Zoom Out: تبعيد\n  Last Frame: الإطار السابق (أثناء التوقف مؤقتا)\n  Next Frame: الإطار التالي (أثناء التوقف مؤقتا)\n  Minimize Window: تصغير النافذة\n  Close Window: أغلاق النافذة\n  Reset Zoom: إعادة تعيين مستوى التكبير/مقياس واجهة المستخدم\n  Skip by Tenths: تخطي الفيديو حسب النسبة المئوية (3 تخطيات إلى 30٪ من المدة)\n  Small Fast Forward: للأمام السريع X ثواني استنادا إلى الفاصل الزمني للأمام السريع ومعدل تشغيل الفيديو الحالي\n  Keyboard Shortcuts: اختصارات لوحة المفاتيح\n  Sections:\n    Video:\n      Playback: 'فيديو: تشغيل'\n      General: 'فيديو: عام'\n    App:\n      Situational: 'التطبيق: ظرفي'\n      General: 'التطبيق: عام'\n  Show Keyboard Shortcuts: إظهار اختصارات لوحة المفاتيح\n  History Backward: انتقل إلى الخلف صفحة واحدة\n  Navigate to History: انتقل إلى صفحة السجل التاريخي\n  Refresh: تحديث الخلاصة بأحدث محتوى\n  Focus Secondary Search: التركيز على شريط البحث الثانوي (إذا كان موجودا)\n  Mute: تبديل كتم الصوت\n  Focus Search: التركيز على شريط البحث\n  Search in New Window: البحث في نافذة جديدة\n  Volume Up: زيادة الحجم\n  Volume Down: تقليل الحجم\n  Small Rewind: الترجيع X ثانية استنادا إلى فاصل الترجيع ومعدل تشغيل الفيديو الحالي\n  Last Chapter: الفصل الأخير\n  Next Chapter: الفصل التالي\n  Decrease Video Speed: تقليل سرعة الفيديو بناء على الفاصل الزمني لمعدل تشغيل الفيديو\n  Increase Video Speed: زيادة سرعة الفيديو استنادا إلى الفاصل الزمني لمعدل تشغيل الفيديو\n  Full Window: تبديل النافذة الكاملة\n  Theatre Mode: تبديل وضع المسرح\n  Take Screenshot: أخذ لقطة شاشة\n  History Forward: انتقل إلى الأمام صفحة واحدة\n  New Window: إنشاء نافذة جديدة\n  Navigate to Settings: انتقل إلى صفحة الإعدادات\n  Captions: تبديل التسميات التوضيحية مفعل/معطل\n  Large Fast Forward: إلى الأمام 10 ثوان / فيديو سريع إلى الأمام استنادا إلى معدل تشغيل الفيديو الحالي\n  Fullscreen: تبديل ملء الشاشة\n  Stats: إظهار إحصائيات الفيديو\n  Picture in Picture: تبديل وضع الصورة داخل الصورة\n  Large Rewind: الترجيع 10 ثوان / الترجيع الفيديو استنادا إلى معدل تشغيل الفيديو الحالي\n  Play: تبديل التشغيل/الإيقاف المؤقت\n  Home: انتقل إلى بداية الفيديو\n  End: انتقل إلى نهاية الفيديو\n  Skip to Next Video: تخطي إلى الفيديو التالي في قائمة التشغيل أو الفيديو الموصى التالي\n  Skip to Previous Video: تخطي إلى الفيديو السابق في قائمة التشغيل\nKeys:\n  arrowright: ‫ السهم الأيمن\n  enter: Enter\n  plus: Plus\n  arrowup: السهم لأعلى\n  ctrl: Ctrl\n  alt: Alt\n  shift: Shift\n  arrowdown: السهم لأسفل\n  arrowleft: السهم الأيسر\nDescription:\n  Collapse Description: إظهار أقل\n  Expand Description: '...المزيد'\nAutoplay Interruption Timer: تم إلغاء التشغيل التلقائي بسبب {autoplayInterruptionIntervalHours} ساعات من عدم النشاط\nshortcutJoinOperator: +\nshortcutLabelSeparator: '{''|''}'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\n"
  },
  {
    "path": "static/locales/as.yaml",
    "content": "# Currently on Subscriptions, Playlists, and History\nFile: 'ফাইল'\nQuit: 'অন্ত কৰক'\nEdit: 'সম্পাদনা'\nUndo: 'পূৰ্বৰ দৰে কৰক'\nRedo: 'পুনঃকৰক'\nCut: 'ছেদ কৰক'\nCopy: 'প্রতিলিপি কৰক'\nPaste: 'লেপন কৰক'\nDelete: 'বিলোপ কৰক'\nSelect all: 'সকলোক বাছক'\nSearch Filters:\n  Type:\n    Videos: ভিডিঅ\nSettings:\n  # On Settings Page\n  Theme Settings: {}\n  Subscription Settings: {}\nChannel:\n  Playlists: {}\n  Videos:\n    Videos: ভিডিঅ\nVideo: {}\nLocale Name: অসমীয়া\nGlobal:\n  Videos: ভিডিঅ\n  Live: লাইভ\n  Sort By: বস্তু অনুযায়ী সজাওক\n  Counts:\n    Comment Count: ১ টা মন্তব্য | {count} মন্তব্য\n    Like Count: ১ ৰ দৰে | {count} লাইক\n    Subscriber Count: ১ জন গ্ৰাহক | {count} গ্ৰাহক\n    Watching Count: ১ চাই থকা | {count} চাই আছে\n    View Count: ১ দৰ্শন | {count} দৰ্শন\n    Video Count: ১ ভিডিঅ' | {count} ভিডিঅ'\n    Channel Count: ১ চেনেল | {count} চেনেল\n  Shorts: শ্বৰ্ট\n  Posts: পোষ্ট\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\n    VR180: ভিআৰ১৮০\nProfile:\n  Select All: সকলোক বাছক\nPreferences: পছন্দসমূহ\nToggle Developer Tools: ডেভেলপাৰ সঁজুলিসমূহ টগল কৰক\nActual size: প্ৰকৃত আকাৰ\nZoom in: জুম ইন কৰক\nNew Window: নতুন উইণ্ড'\nZoom out: জুম আউট কৰক\nToggle fullscreen: সম্পূৰ্ণ পৰ্দা টগল কৰক\nWindow: খিৰিকী\nMinimize: নূন্যতম কৰক\nClose: বন্ধ\nSearch Bar:\n  Clear Input: ইনপুট পৰিষ্কাৰ কৰক\n  Remove: আঁতৰোৱা\nSearch character limit: সন্ধান প্ৰশ্ন {searchCharacterLimit} আখৰৰ সীমাৰ ওপৰত\nSearch / Go to URL: সন্ধান / URL লৈ যাওক\nAre you sure you want to open this link?: আপুনি নিশ্চিতভাৱে এই লিংকটো খুলিব বিচাৰেনে?\nA new blog is now available, {blogTitle}. Click to view more: এতিয়া এটা নতুন ব্লগ\n  উপলব্ধ, {blogTitle}। অধিক চাবলৈ ক্লিক কৰক\nDownload From Site: চাইটৰ পৰা ডাউনলোড কৰক\n"
  },
  {
    "path": "static/locales/awa.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'अवधी'\n\n# Webkit Menu Bar\nFile: 'फाइल'\nNew Window: 'नई बिंडो'\nPreferences: 'प्राथमिकता'\nQuit: 'बाहेर निकरा'\nEdit: 'एडिट (बदला)'\nUndo: 'पहिले जइसा करा'\nRedo: 'फिर से करा'\nCut: 'काटा'\nCopy: 'कॉपी करा'\nPaste: 'पेस्ट करा (चिपकावा)'\nDelete: 'मिटावा'\nSelect all: 'सगरौ चुना'\nToggle Developer Tools: 'टागल डेबलपर टूल्स'\nActual size: 'सही साइज'\nZoom in: 'जूम करा'\nZoom out: 'छोट करा (जूम आउट)'\nToggle fullscreen: 'टागल पूरी स्क्रीन'\nWindow: 'बिंडो'\nMinimize: 'स्क्रीन छोट करा'\nClose: 'बंद करा'\nBack: 'पीछे'\nForward: 'आगे'\nRight-click or hold to see history: 'इतिहास देखै के बरे राइट-क्लिक या होल्ड करा'\nOpen New Window: 'नई बिंडो खोला'\nGo to page: '{page} पै जा'\nClose Banner: 'बैनर बंद करा'\n\nVersion {versionNumber} is now available!  Click for more details: 'वर्जन {versionNumber}\n  अब मौजूद अहइ! अउर जानकारी के बरे क्लिक करा'\nDownload From Site: 'साइट से डाउनलोड करा'\nA new blog is now available, {blogTitle}. Click to view more: 'एक नया ब्लॉग अब मौजूद\n  बाटै, {blogTitle}। अउर देखै की ताईं क्लिक करा'\nAre you sure you want to open this link?: 'का तू पक्का ई लिंक खोलै चाहत हौ?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'वीडियोज'\n  Shorts: 'सार्ट्स'\n  Live: 'लाइव'\n  Sort By: 'लाइन से लगावा'\n  Counts:\n    Video Count: '1 वीडियो | {count} वीडियोज'\n    Channel Count: '1 चैनल | {count} चैनल्स'\n    Subscriber Count: '1 सब्सक्राइबर | {count} सब्सक्राइबर्स'\n    View Count: '1 ब्यू | {count} ब्यूज'\n    Like Count: '1 पसन्द | {count} पसन्द'\n    Comment Count: '1 कमेंट | {count} कमेंट'\n    Watching Count: '1 जने देखत हैं | {count} जने देखत हैं'\n\n# Search Bar\nSearch / Go to URL: 'हेरा / यूआरएल पै जा'\nSearch Bar:\n  Clear Input: 'इनपुट साफ़ करा'\n  Remove: 'हटावा'\nSearch character limit: 'सर्च क्वेरी {searchCharacterLimit} करेक्टर सीमा से उप्पर\n  है'\nSearch Listing:\n  Label:\n    4K: '4के'\n    8K: '8के'\n    VR180: 'VR180'\n    360 Video: '360°'\n    Subtitles: 'दुसरी भासा मा अच्छर'\n    New: 'नवा'\n    3D: '3डी'\n    # Aria labels\n    Closed Captions: 'बंद कैप्सन'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'हेरय कै फिलटर'\n  Sort By:\n    Most Relevant: 'सबसे ठीक'\n    Rating: 'रेटिंग'\n    Upload Date: 'अपलोड तारिख'\n    View Count: 'ब्यू कै गिनती'\n  Time:\n    Time: 'समय'\n    Any Time: 'कबो भी'\n    Last Hour: 'पिछले घंटा'\n    Today: 'आज'\n    This Week: 'यहि हफ्ता'\n    This Month: 'यहि महीना'\n    This Year: 'यहि साल'\n  Type:\n    Type: 'परकार'\n    All Types: 'सब परकार कै'\n    Videos: 'वीडिओज़'\n    Channels: 'चैनल्स'\n    Movies: 'मूवीज'\n    #& Playlists\n  Duration:\n    Duration: 'मियाद'\n    All Durations: 'सब अवधि (मियाद)'\n    Short (< 4 minutes): '4 मिनट से छोट'\n    Medium (4 - 20 minutes): 'मद्धिम 4 से 20 मिनट कै'\n    Long (> 20 minutes): 'बड़वार 20 मिनट से जादा'\n  Features:\n    Features: 'सुबिधा'\n    HD: 'एचडी'\n    Subtitles: 'दूसर भासा मा अच्छर'\n    Creative Commons: 'क्रिएटिव कॉमन्स'\n    3D: '3डी'\n    Live: 'लाइव'\n    4K: '4के'\n    360 Video: '360 वीडियो'\n    Location: 'लोकेसन'\n    HDR: 'एचडीआर'\n    VR180: 'वीआर180'\n  # On Search Page\n  Search Results: 'खोजा गवा परिनाम'\n  Fetching results. Please wait: 'परिनाम लावत अहै। इन्तजार करा'\n  Fetch more results: 'अउर परिनाम लावा'\n  There are no more results for this search: 'यहि खोज के बरे अउर कवनो परिनाम नाही\n    है'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'सब्सक्रिप्सन'\n  # channels that were likely deleted\n  Error Channels: 'गलती वाले चैनल'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'यहि\n    प्रोफ़ाइल के पास ढेर सब्सक्रिप्शनस है।  RSS का जोर से परयोग कइके रेट लिमिटिंग\n    से बचावा'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'तोहाय\n    सदस्सता सूची येह समय खाली अहै। अगर तू आपन सदस्यता इम्पोर्ट करै चाहत हैं तौ तू\n    डेटा सेटिंग्स मा जाइ सकत हौ अउर सदस्सता इम्पोर्ट करै का चुनि सकत हौ या तू एक चैनल\n    हेर सकत हौ अउर उनकै सदस्सता लइ सकत हौ।'\n  Disabled Automatic Fetching: 'तू अपने आप सदस्सता लावै का स्वचालित सदस्यता लावै का\n    बंद केहे अहा। उनका हिंया देखै की ताईं सदस्सता का रिफ्रेस करा।'\n  Empty Channels: 'तुम्हार सब्सक्राइब कीन गवा चैनल पै येह समय कवनो वीडियो नाही है।'\n  Empty Posts: 'तोहरे सब्सक्राइब किहे चैनलन मा फिलहाल कौनो पोस्ट नाय अहै।'\n  Load More Videos: 'अउर वीडियो अपलोड करैं'\n  Load More Posts: 'अउर पोस्ट लोड करा'\n  Subscriptions Tabs: 'सब्सक्रिप्सन टैब्स'\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Export Playlist: ''\n  The playlist has been successfully exported: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      Video has been removed. Click here to undo.: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n\n      This playlist has a video with a duration error: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Autoplay Playlists: ''\n    Autoplay Videos: ''\n    Turn on Subtitles by Default: ''\n    Proxy Videos Through Invidious: ''\n    Default Viewing Mode:\n      Theater: ''\n      Default Viewing Mode: ''\n      Full Screen: ''\n      Picture in Picture: ''\n      External Player: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Remember Search History: ''\n    Save Watched Progress: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search History and Cache: ''\n    Are you sure you want to clear out your search history and cache?: ''\n    Search history and cache have been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Export Playlists For Older FreeTube Versions:\n      Label: ''\n      # |- = Keep newlines, No newline at end\n      Tooltip: |\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: 'सगरौ चुना'\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: 'वीडियोज'\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\n    Viewing Posts Only Supported By Invidious: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Autoplay is off: ''\n    Autoplay is on: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nshortcutLabelSeparator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: 'टागल पूरी स्क्रीन'\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: 'टागल डेबलपर टूल्स'\n  Reset Zoom: ''\n  Zoom In: 'जूम करा'\n  Zoom Out: 'छोट करा (जूम आउट)'\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n"
  },
  {
    "path": "static/locales/az.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Azərbaycanca'\nFreeTube: 'FreeTube'\n\n# Webkit Menu Bar\nFile: 'Fayl'\nQuit: 'Çıxış'\nEdit: 'Düzəliş et'\nUndo: 'Geri al'\nRedo: 'Təkrarla'\nCut: 'Kəs'\nCopy: 'Köçür'\nPaste: 'Yapışdır'\nDelete: 'Sil'\nSelect all: 'Hamısını seç'\nToggle Developer Tools: 'Tərtibatçı Seçimlərini Aç/Bağla'\nActual size: 'Həqiqi Ölçü'\nZoom in: 'Yaxınlaşdır'\nZoom out: 'Uzaqlaşdır'\nToggle fullscreen: 'Tam ekran göstər'\nWindow: 'Pəncərə'\nMinimize: 'Kiçilt'\nClose: 'Bağla'\nBack: 'Geri'\nForward: 'İrəli'\nOpen New Window: 'Yeni Pəncərə Aç'\n\nVersion {versionNumber} is now available!  Click for more details: '{versionNumber} versiyası indi mövcuddur!  Daha çox məlumat üçün kliklə'\nDownload From Site: 'Saytdan Yüklə'\nA new blog is now available, {blogTitle}. Click to view more: 'İndi yeni elan mövcuddur, {blogTitle}. Daha çoxun görmək üçün kliklə'\nAre you sure you want to open this link?: 'Bu linki açmaq istədiyinizə əminsiniz?'\n\n# Search Bar\nSearch / Go to URL: 'Axtarış / URL-ə Keçin'\nSearch Bar:\n  Clear Input: 'Girişi Təmizlə'\n  # In Filter Button\n  Remove: Sil\nSearch Filters:\n  Search Filters: 'Axtarış Filtrləri'\n  Sort By:\n    Most Relevant: 'Ən Münasib'\n    Rating: 'Qiymətləndirmə'\n    Upload Date: 'Yükləmə Tarixi'\n    View Count: 'Baxış Sayı'\n  Time:\n    Time: 'Vaxt'\n    Any Time: 'İstənilən Vaxt'\n    Last Hour: 'Son Saat'\n    Today: 'Bu gün'\n    This Week: 'Bu Həftə'\n    This Month: 'Bu Ay'\n    This Year: 'Bu İl'\n  Type:\n    Type: 'Növ'\n    All Types: 'Bütün Növlər'\n    Videos: 'Videolar'\n    Channels: 'Kanallar'\n    #& Playlists\n    Movies: Film\n  Duration:\n    Duration: 'Müddət'\n    All Durations: 'Bütün Müddətlər'\n    Short (< 4 minutes): 'Qısa (<4 dəqiqədən az)'\n    Long (> 20 minutes): 'Uzun (> 20 dəqiqədən çox)'\n  # On Search Page\n    Medium (4 - 20 minutes): Orta (4-20 dəqiqə)\n  Search Results: 'Axtarış Nəticələri'\n  Fetching results. Please wait: 'Nəticələr alınır. Zəhmət olmasa, gözləyin'\n  Fetch more results: 'Daha çox nəticə əldə edin'\n  There are no more results for this search: 'Bu axtarış üçün başqa nəticə yoxdur'\n# Sidebar\n  Features:\n    Features: Xüsusiyyətlər\n    HD: HD\n    Creative Commons: Yaradıcı İnsanlar\n    3D: 3D\n    Subtitles: Titrlər\n    Live: Canlı\n    360 Video: 360° Video\n    HDR: HDR\n    VR180: VR180\n    4K: 4K\n    Location: Məkan\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abunəliklər'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Bu profilin çoxlu sayda abunəsi var. Sürət məhdudiyyətinin qarşısını almaq üçün RSS-i zorlanır'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Abunəlik siyahınız hazırda boşdur. Abunəliklərinizi idxal etmək istəyirsinizsə, Məlumat Parametrlərinə gedib ''Abunəlikləri İdxal Et'' seçimini edə bilərsiniz və ya bir kanal axtarıb abunə ola bilərsiniz.'\n  Load More Videos: 'Daha çox Video Yüklə'\n  Error Channels: Xətalı Kanallar\n  Load More Posts: Daha çox elan yüklə\n  Subscriptions Tabs: Abunəliklər Səhifələri\n  All Subscription Tabs Hidden: Bütün abunəlik səhifələri gizlidir. Məzmunu burada görmək üçün \"{settingsSection}\" bölməsində \"{subsection}\"-da bəzi səhifələri gizlətməyin.\n  Empty Channels: Abunə olduğunuz kanallarda hazırda heç bir video yoxdur.\n  Empty Posts: Abunə olduğunuz kanallarda hazırda heç bir elan yoxdur.\n  Disabled Automatic Fetching: Siz avtomatik abunəlik əldə etməyi bağlamısız. Abunəlikləri burada görmək üçün yeniləyin.\nMore: 'Daha Çox'\nTrending:\n  Trending: 'Trenddədir'\n  Gaming: 'Oyun'\n  Trending Tabs: 'Trend Səhifələr'\nMost Popular: 'Ən Tanınmış'\nPlaylists: 'Pleylistlər'\nUser Playlists:\n  Your Playlists: 'Pleylistləriniz'\n  Empty Search Message: 'Bu pleylistdə axtarışınıza uyğun video yoxdur'\n  Search bar placeholder: 'Pleylist Axtar'\n  Playlists with Matching Videos: Uyğun videolar olan pleylistlər\n  Add to Playlist: Pleylistə əlavə et\n  You have no playlists. Click on the create new playlist button to create a new one.: Pleylistiniz yoxdur. Yenisini yaratmaq üçün yeni pleylist yarat düyməsini kliklə.\n  Create New Playlist: Yeni Pleylist Yarat\n  This playlist currently has no videos.: Bu pleylistdə hazırda video yoxdur.\n  Add to Favorites: '{playlistName} pleylistinə əlavə et'\n  Move Video Up: Videonu Yuxarı Köçür\n  Move Video Down: Videonu Aşağı Köçür\n  Remove from Favorites: '{playlistName} pleylistindən sil'\n  Remove from Playlist: Pleylistdən Silin\n  Playlist Name: Pleylist Adı\n  Playlist Description: Pleylist Açıqlaması\n  Cancel: Ləğv et\n  Edit Playlist Info: Pleylist məlumatına düzəliş et\n  Enable Quick Bookmark With This Playlist: Bu Pleylistlə Tez Əlfəcini Aktivləşdir\n  Copy Playlist: Pleylisti Köçür\n  Remove Watched Videos: Baxılan Videoları Sil\n  Delete Playlist: Pleylisti Sil\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: Bu video yuxarı köçürülə bilməz.\n      This video cannot be moved down.: Bu video aşağı köçürülə bilməz.\n      Video has been removed: Video silindi\n      There was a problem with removing this video: Bu videonu silərkən problem yarandı\n      Playlist name cannot be empty. Please input a name.: Pleylist adı boş ola bilməz. Xahiş olunur, ad daxil edin.\n      Playlist {playlistName} has been deleted.: '{playlistName} pleylist silindi.'\n      This playlist does not exist: Bu pleylist yoxdur\n      This playlist is protected and cannot be removed.: Bu pleylist qorunur və silinə bilməz.\n      There were no videos to remove.: Silinəcək video yox idi.\n      This playlist is already being used for quick bookmark.: Bu pleylist artıq sürətli əlfəcin üçün istifadə olunur.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Bu pleylist indi {oldPlaylistName} əvəzinə sürətli əlfəcin üçün istifadə olunur. Geri almaq üçün bura kliklə\n      Playlist has been updated.: Pleylist yeniləndi.\n      Reverted to use {oldPlaylistName} for quick bookmark: Sürətli əlfəcin üçün {oldPlaylistName} istifadəsinə geri qaytarıldı\n      This playlist is now used for quick bookmark: Bu pleylist indi sürətli əlfəcin üçün istifadə olunur\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Pleylistdəki bəzi videolar hələ yüklənməyib. Yenə də köçürmək üçün bura klikləyin.\n      There was an issue with updating this playlist.: Bu pleylisti yeniləyərkən problem oldu.\n      \"{videoCount} video(s) have been removed\": 1 video silindi | {videoCount} video silindi\n      Video has been removed. Click here to undo.: Video silindi. Geri gətirmək üçün klik edin.\n    Search for Videos: Videoları Axtar\n  Sort By:\n    EarliestUpdatedFirst: Ən Tez Yenilənib\n    EarliestCreatedFirst: Ən Tez Yaradılıb\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: Yenicə Yaradılıb\n    LatestUpdatedFirst: Yenicə Yenilənib\n    LatestPlayedFirst: Yenicə Oynadılıb\n    EarliestPlayedFirst: Daha Tez Oynadılıb\n  Save Changes: Dəyişiklikləri Saxla\n  Quick Bookmark Enabled: Tez Əlfəcin Aktivləşdirildi\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 1 baxılmış videonu bu pleylistdən silmək istədiyinizə əminsiniz? Bu geri alına bilməz. | {playlistItemCount} baxılmış videonu bu pleylistdən silmək istədiyinizə əminsiniz? Bu geri alına bilməz.\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} Seçildi'\n    Search in Playlists: Pleylistlərdə Axtar\n    Select a playlist to add your N videos to: Videonuzu |-ə əlavə etmək üçün pleylist seçin {videoCount} videonuzu əlavə etmək üçün pleylist seçin\n    Allow Adding Duplicate Video(s): Eyni Video(lar) Əlavə Etməyə İcazə Ver\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videolar Əlavə Olunacaq'\n    Save: Saxla\n    Added {count} Times: Artıq Əlavə Edilib | {count} dəfə əlavə edildi\n    Toast:\n      You haven't selected any playlist yet.: Siz hələ heç bir pleylist seçməmisiniz.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Video Artıq Əlavə Edilib'\n  Remove Duplicate Videos: Eyni Videoları Sil\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Bu pleylistdən 1 eyni videonu silmək istədiyinizə əminsiniz? Bu geri alına bilməz | {playlistItemCount} eyni videonu bu pleylistdən silmək istədiyinizə əminsiniz? Bu geri alına bilməz.\n  Cannot delete the quick bookmark target playlist.: Sürətli əlfəcin hədəf pleylisti silinmir.\n  Are you sure you want to delete this playlist? This cannot be undone: Bu pleylisti silmək istədiyinizə əminsiniz? Bu geri alına bilməz.\n  CreatePlaylistPrompt:\n    New Playlist Name: Yeni Pleylist Adı\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Artıq bu adda pleylist var. Lütfən, fərqli ad seçin.\n      Playlist {playlistName} has been successfully created.: '{playlistName} pleylist uğurla yaradıldı.'\n      There was an issue with creating the playlist.: Pleylist yaradarkən problem oldu.\n    Create: Yarat\n  The playlist has been successfully exported: Bu pleylist uğurla ixrac edildi\n  Export Playlist: Bu Pleylisti İxrac Et\nHistory:\n  # On History Page\n  History: 'Tarixçə'\n  Watch History: 'Baxış Tarixçəsi'\n  Your history list is currently empty.: 'Tarixçə siyahınız hazırda boşdur.'\n  Empty Search Message: 'Tarixçənizdə axtarışınıza uyğun video yoxdur'\n  Search bar placeholder: \"Tarixçədə Axtarın\"\nSettings:\n  # On Settings Page\n  Settings: 'Tənzimləmələr'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Dəyişikliklərin qüvvəyə minməsi üçün tətbiq yenidən başladılmalıdır. Yenidən başladılsın və dəyişiklik tətbiq edilsin?'\n  General Settings:\n    General Settings: 'Ümumi'\n    Check for Updates: 'Yeniləmələri Yoxlayın'\n    Check for Latest Blog Posts: 'Ən Son Elanları Yoxlayın'\n    Fallback to Non-Preferred Backend on Failure: 'Uğursuzluqda Üstünlük Verilməyən Arxa Uca Qayıdış'\n    Enable Search Suggestions: 'Axtarış Təkliflərini Aktivləşdirin'\n    Default Landing Page: 'İlkin Açılış Səhifəsi'\n    Locale Preference: 'Yerləşdirilən Seçim'\n    System Default: 'Sistem Standartı'\n    Preferred API Backend:\n      Preferred API Backend: 'Tərcih Edilən API Arxa Ucu'\n      Local API: 'Yerli API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Video Görünüş Növü'\n      Grid: 'Şəbəkə'\n      List: 'Siyahı'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatür Üstünlüyü'\n      Default: 'İlkin'\n      Beginning: 'Başlanğıc'\n      Middle: 'Orta'\n      End: 'Son'\n      Hidden: Gizli\n      Blur: Bulanıqlıq\n    Current Invidious Instance: 'Cari Invidious Serveri'\n    The currently set default instance is {instance}: 'Hazırda təyin edilmiş ilkin server {instance}-dır'\n    No default instance has been set: 'İlkin server təyin edilməyib'\n    Current instance will be randomized on startup: 'Cari server başlanğıcda təsadüfi olacaq'\n    Set Current Instance as Default: 'Cari serveri ilkin olaraq təyin et'\n    Clear Default Instance: 'İlkin serveri sil'\n    View all Invidious instance information: 'Bütün Invidious instansiya məlumatına bax'\n    Region for Trending: 'Trendlər Üçün Bölgə'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Xarici Keçid Hazırlama'\n      Open Link: 'Linki Açın'\n      No Action: Fəaliyyət Olmadan\n      Ask Before Opening Link: Keçidi Açmazdan Əvvəl Soruş\n    Auto Load Next Page:\n      Label: Növbəti Səhifəni Avtomatik Yüklə\n      Tooltip: Əlavə səhifələri və şərhləri avtomatik yüklə.\n  Theme Settings:\n    Main Color Theme:\n      Pink: Çəhrayı\n      Indigo: Göy rəng\n      Amber: Sarı-qonur\n      Orange: Narıncı\n      Light Blue: Açıq Mavi\n      Main Color Theme: Əsas Rəng Teması\n      Deep Purple: Tünd Bənövşəyi\n      Teal: Dəniz Mavisi\n      Green: Yaşıl\n      Deep Orange: Tünd Narıncı\n      Red: Qırmızı\n      Purple: Bənövşəyi\n      Blue: Mavi\n      Light Green: Açıq Yaşıl\n      Yellow: Sarı\n      Dracula Red: Drakula Qırmızı\n      Dracula Cyan: Dracula Cyan\n      Dracula Green: Drakula Yaşıl\n      Dracula Orange: Drakula Narıncı\n      Dracula Pink: Drakula Çəhrayı\n      Catppuccin Frappe Pink: Catppuccin Frappe Çəhrayı\n      Catppuccin Frappe Red: Catppuccin Frappe Qırmızı\n      Catppuccin Frappe Maroon: Catppuccin Frappe Tünd Qırmızı\n      Catppuccin Frappe Peach: Catppuccin Frappe Şaftalı Rəngi\n      Catppuccin Frappe Blue: Catppuccin Frappe Mavi\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavanda\n      Cyan: Siyanid rəngi\n      Lime: Limon yaşılı\n      Dracula Purple: Drakula Bənövşəyi\n      Dracula Yellow: Drakula Sarı\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flaminqo\n      Catppuccin Frappe Mauve: Catppuccin Frappe Çəhrayı Çalarlı Bənövşəyi\n      Catppuccin Frappe Yellow: Catppuccin Frappe Sarı\n      Catppuccin Frappe Green: Catppuccin Frappe Yaşıl\n      Catppuccin Frappe Teal: Catppuccin Frappe Dəniz rəngi\n      Catppuccin Frappe Sky: Catppuccin Frappe Səma rəngi\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Yaqut\n    UI Scale: UI (Ekran) Ölçüsü\n    Base Theme:\n      Pastel Pink: Pastel Çəhrayı\n      Black: Qara\n      Dark: Qaranlıq\n      Hot Pink: Coşqun Çəhrayı\n      Solarized Dark: Günəşli Qaranlıq\n      Solarized Light: Günəşli İşıq\n      System Default: Sistem Standartı\n      Nordic: Nordic\n      Base Theme: Əsas Tema\n      Light: İşıqlı\n      Dracula: Dracula\n      Catppuccin Mocha: Catppuccin Mocha\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Light\n      Catppuccin Frappe: Catppuccin Frappe\n    Match Top Bar with Main Color: Üst Hissəni Əsas Rənglə Uyğunlaşdır\n    Disable Smooth Scrolling: Hamar Sürüşdürməni Bağla\n    Hide Side Bar Labels: Kənar Hissə Etiketlərini Gizlət\n    Theme Settings: Tema\n    Expand Side Bar by Default: Kənar Hissəni İlkin Olaraq Genişləndir\n    Hide FreeTube Header Logo: FreeTube Başlıq Simvolunu Gizlət\n  Player Settings:\n    Screenshot: {}\n  SponsorBlock Settings: {}\n  Sort Settings Sections (A-Z): Tənzimləmələr Bölmələrin Çeşidlə (AZ)\n  Return to Settings Menu: Parametrlər Menyusuna Qayıt\nChannel:\n  Videos:\n    Videos: Videolar\n  Playlists: {}\nVideo:\n  External Player: {}\nTooltips: {}\nNew Window: Yeni Pəncərə\nPreferences: Seçimlər\nGlobal:\n  Counts:\n    Subscriber Count: 1 abunəçi | {count} abunəçi\n    View Count: 1 baxış | {count} baxış\n    Video Count: 1 video | {count} video\n    Watching Count: 1 baxır | {count} baxır\n    Channel Count: 1 kanal | {count} kanal\n    Like Count: 1 bəyəni | {count} bəyənmələr\n    Comment Count: 1 şərh | {count} şərhlər\n  Videos: Videolar\n  Live: Canlı\n  Posts: Postlar\n  Shorts: Shorts\n  Sort By: 'Çeşidləmə'\nSearch Listing:\n  Label:\n    Closed Captions: Titrlər Bağlandı\n    4K: 4K\n    Subtitles: Titrlər\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Yeni\n    3D: 3D\nChannels:\n  Empty: Kanal siyahınız hazırda boşdur.\n  Unsubscribe Prompt: '\"{channelName}\" / abunəliyi ləğv etmək istədiyinizə əminsiniz?'\n  Channels: Kanallar\n  Count: '{number} kanal tapıldı.'\n  Title: Kanal Siyahısı\n  Search bar placeholder: Kanalları Axtar\nFeed:\n  Feed Last Updated: '{feedName} axının son yeniləmə: {date}'\n  Refresh Feed: '{subscriptionName} / yenilə'\nSearch character limit: Axtarış sorğusu {searchCharacterLimit} simvol həddindən çoxdur\nGo to page: '{page} səhifəyə keç'\nClose Banner: Banneri Bağla\nDisplay Label: '{label}: {value}'\nYes, Delete: Bəli, Sil\nYes, Restart: Bəli, Yenidən Başlat\nCancel: Ləğv et\ncheckmark: ✓\nYes: Bəli\nOk: Oldu\nNo: Xeyr\nRight-click or hold to see history: Tarixçəni görmək üçün sağ düyməyə klik edin və ya sıxıb saxlayın\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Tərtibatçı Seçimlərini Aç/Bağla\n  Zoom Out: Uzaqlaşdır\n  Zoom In: Yaxınlaşdır\n  Fullscreen: Tam ekran göstər\nProfile:\n  Select All: Hamısını seç\n"
  },
  {
    "path": "static/locales/be.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Беларуская'\n\n# Webkit Menu Bar\nFile: 'Файл'\nNew Window: 'Новае акно'\nPreferences: 'Параметры'\nQuit: 'Выйсці'\nEdit: 'Рэдагаваць'\nUndo: 'Адрабіць'\nRedo: 'Паўтарыць'\nCut: 'Выразаць'\nCopy: 'Скапіяваць'\nPaste: 'Уставіць'\nDelete: 'Выдаліць'\nSelect all: 'Вылучыць усё'\nToggle Developer Tools: 'Пераключыць інструменты распрацоўшчыка'\nActual size: 'Фактычны памер'\nZoom in: 'Павялічыць'\nZoom out: 'Паменшыць'\nToggle fullscreen: 'Пераключыць поўнаэкранны рэжым'\nWindow: 'Акно'\nMinimize: 'Згарнуць'\nClose: 'Закрыць'\nBack: 'Назад'\nForward: 'Наперад'\nOpen New Window: 'Адкрыць новае акно'\n\nVersion {versionNumber} is now available!  Click for more details: 'Даступна версія {versionNumber}!  Націсніце, каб даведацца больш'\nDownload From Site: 'Спампаваць з сайта'\nA new blog is now available, {blogTitle}. Click to view more: 'Даступны новы блог, {blogTitle}. Націсніце, каб паглядзець больш'\nAre you sure you want to open this link?: 'Сапраўды хочаце адкрыць гэтую спасылку?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Відэа'\n  Shorts: 'Кароткія відэа'\n  Live: 'Ужывую'\n  Posts: 'Публікацыі'\n  Sort By: Сартаванне\n  Counts:\n    Video Count: '1 відэа | {count} відэа'\n    Channel Count: '1 канал | {count} каналаў'\n    Subscriber Count: '1 падпісчык | {count} падпісчыкаў'\n    View Count: '1 прагляд | {count} праглядаў'\n    Watching Count: '1 глядач | {count} гледачоў'\n\n# Search Bar\n    Like Count: 1 лайк | {count} лайкаў\n    Comment Count: 1 каментарый | {count} каментарыяў\nSearch / Go to URL: 'Пошук / Перайсці да URL'\nSearch Bar:\n  Clear Input: 'Ачысціць поле ўводу'\n  # In Filter Button\n  Remove: Выдаліць\nSearch Filters:\n  Search Filters: 'Фільтры пошуку'\n  Sort By:\n    Most Relevant: 'Найбольш рэлевантныя'\n    Rating: 'Рэйтынг'\n    Upload Date: 'Дата запампоўвання'\n    View Count: 'Колькасць праглядаў'\n  Time:\n    Time: 'Час'\n    Any Time: 'За ўвесь час'\n    Last Hour: 'За апошнюю гадзіну'\n    Today: 'Сёння'\n    This Week: 'За гэты тыдзень'\n    This Month: 'За гэты месяц'\n    This Year: 'За гэты год'\n  Type:\n    Type: 'Тып'\n    All Types: 'Усе тыпы'\n    Videos: 'Відэа'\n    Channels: 'Каналы'\n    Movies: 'Фільмы'\n    #& Playlists\n  Duration:\n    Duration: 'Працягласць'\n    All Durations: 'Любая працягласць'\n    Short (< 4 minutes): 'Кароткія (< 4 хвілін)'\n    Medium (4 - 20 minutes): 'Сярэднія (4-20 хвілін)'\n    Long (> 20 minutes): 'Доўгія (> 20 хвілін)'\n  # On Search Page\n  Search Results: 'Вынікі пошуку'\n  Fetching results. Please wait: 'Атрыманне вынікаў. Калі ласка, пачакайце'\n  Fetch more results: 'Атрымаць больш вынікаў'\n  There are no more results for this search: 'Для гэтага пошуку больш няма вынікаў'\n# Sidebar\n  Features:\n    HD: HD\n    Subtitles: Субцітры\n    3D: 3D\n    4K: 4K\n    HDR: HDR\n    Features: Асаблівасці\n    VR180: VR180\n    Live: Ужывую\n    360 Video: 360°\n    Location: Месцазнаходжанне\n    Creative Commons: Creative Commons\n  Clear Filters: Ачысціць фільтры\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Падпіскі'\n  # channels that were likely deleted\n  Error Channels: 'Каналы з памылкамі'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'У гэтага профілю вялікая колькасць падпісак.  Прымусовае выкарыстанне RSS, каб пазбегнуць абмежавання хуткасці'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Ваш спіс падпісак зараз пусты. Калі вы хочаце імпартаваць свае падпіскі, вы можаце перайсці ў Налады даных і выбраць Імпартаваць падпіскі або вы можаце знайсці каналы і падпісацца на іх.'\n  Disabled Automatic Fetching: 'Вы адключылі аўтаматычнае загрузку падпісак. Каб убачыць іх тут, абнавіце падпіскі.'\n  Empty Channels: 'На каналах, на якія вы падпісаны, зараз няма відэа.'\n  Empty Posts: 'На каналах, на якія вы падпісаны, зараз няма паведамленняў.'\n  Load More Videos: 'Загрузіць больш відэа'\n  Load More Posts: 'Загрузіць больш паведамленняў'\n  Subscriptions Tabs: 'Укладкі падпісак'\n  All Subscription Tabs Hidden: 'Усе ўкладкі падпісак схаваныя. Каб убачыць змесціва, уключыце некаторыя ўкладкі ў раздзеле \"{subsection}\" у \"{settingsSection}\".'\nMore: 'Больш'\nChannels:\n  Channels: 'Каналы'\n  Title: 'Спіс каналаў'\n  Search bar placeholder: 'Пошук каналаў'\n  Count: '{number} каналы(аў) знойдзена.'\n  Empty: 'Ваш спіс каналаў зараз пусты.'\n  Unsubscribe Prompt: 'Сапраўды хочаце адпісацца ад «{channelName}»?'\nTrending:\n  Trending: 'У трэндзе'\n  Gaming: 'Гульні'\n  Trending Tabs: 'Укладкі Трэндаў'\n  Sports: Спорт\nMost Popular: 'Папулярныя'\nPlaylists: 'Плэй-лісты'\nUser Playlists:\n  Your Playlists: 'Вашы плэй-лісты'\n  Empty Search Message: 'У гэтым плэй-лісце няма відэа, якія б адпавядалі вашаму пошуку'\n  Search bar placeholder: 'Пошук плэй-лістоў'\n  Create New Playlist: Стварыць новы плэй-ліст\n  Add to Playlist: Дадаць у плэй-ліст\n  Add to Favorites: Дадаць у {playlistName}\n  Remove from Favorites: Выдаліць з {playlistName}\n  Cancel: Адмена\n  AddVideoPrompt:\n    Save: Захаваць\n    N playlists selected: '{playlistCount} выбрана'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} відэа ўжо дададзена'\n    Toast:\n      You haven't selected any playlist yet.: Вы яшчэ не выбралі плэй-ліст.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Select a playlist to add your N videos to: Выберыце плэй-ліст, каб дадаць сваё відэа | Выберыце плэй-ліст, каб дадаць у яго {videoCount} відэа\n    Search in Playlists: Пошук у плэй-лістах\n    Added {count} Times: Ужо дададзена | Дададзена {count} разоў\n    Allow Adding Duplicate Video(s): Дазволіць дадаваць дублікаты відэа\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} відэа будзе дададзена'\n  CreatePlaylistPrompt:\n    Create: Стварыць\n    New Playlist Name: Назва новага плэй-ліста\n    Toast:\n      There was an issue with creating the playlist.: Узнікла праблема пры стварэнні плэй-ліста.\n      There is already a playlist with this name. Please pick a different name.: Плэй-ліст з такой назвай ужо існуе. Выберыце іншую назву.\n      Playlist {playlistName} has been successfully created.: Плэй-ліст {playlistName} быў паспяхова створаны.\n  SinglePlaylistView:\n    Toast:\n      This playlist is protected and cannot be removed.: Гэты плэй-ліст абаронены і не можа быць выдалены.\n      This video cannot be moved up.: Гэта відэа нельга перамясціць уверх.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Некаторыя відэа ў плэй-лісце яшчэ не загружаныя. Націсніце тут, каб усё роўна скапіяваць.\n      Playlist {playlistName} has been deleted.: Плэй-ліст {playlistName} быў выдалены.\n      This playlist does not exist: Гэты плэй-ліст не існуе\n      This playlist is now used for quick bookmark: Цяпер гэты плэй-ліст выкарыстоўваецца для хуткай закладкі\n      Playlist name cannot be empty. Please input a name.: Назва плэй-ліста не можа быць пустой. Калі ласка, увядзіце назву.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Гэты плэй-ліст цяпер выкарыстоўваецца для хуткай закладкі замест {oldPlaylistName}. Націсніце тут, каб адмяніць\n      Reverted to use {oldPlaylistName} for quick bookmark: Вернута да выкарыстання {oldPlaylistName} для хуткай закладкі\n      Playlist has been updated.: Плэй-ліст абноўлены.\n      \"{videoCount} video(s) have been removed\": 1 відэа было выдалена | {videoCount} відэа былі выдалены\n      There were no videos to remove.: Не было відэа для выдалення.\n      There was an issue with updating this playlist.: Узнікла праблема з абнаўленнем гэтага плэй-ліста.\n      This video cannot be moved down.: Гэта відэа нельга перамясціць уніз.\n      Video has been removed: Відэа было выдалена\n      There was a problem with removing this video: Узнікла праблема з выдаленнем гэтага відэа\n      This playlist is already being used for quick bookmark.: Гэты плэй-ліст ужо выкарыстоўваецца для хуткай закладкі.\n      This playlist has a video with a duration error: Гэты плэй-ліст змяшчае прынамсі адно відэа без працягласці. Яно будзе адсартаваны так, як быццам іх працягласць роўная нулю.\n      Video has been removed. Click here to undo.: Відэа было выдалена. Націсніце сюды, каб адрабіць.\n    Search for Videos: Пошук відэа\n  You have no playlists. Click on the create new playlist button to create a new one.: У вас няма плэй-лістоў. Націсніце на кнопку стварыць новы плэй-ліст, каб стварыць новы.\n  Playlists with Matching Videos: Плэй-лісты з адпаведнымі відэа\n  Move Video Up: Перамясціць відэа ўверх\n  Move Video Down: Перамясціць відэа ўніз\n  Remove from Playlist: Выдаліць з плэй-лісту\n  Playlist Name: Назва плэй-ліста\n  Playlist Description: Апісанне плэй-ліста\n  Edit Playlist Info: Рэдагаваць інфармацыю пра плэй-ліст\n  Copy Playlist: Скапіяваць плэй-ліст\n  Remove Watched Videos: Выдаліць прагледжаныя відэа\n  Delete Playlist: Выдаліць плэй-ліст\n  Are you sure you want to delete this playlist? This cannot be undone: Сапраўды выдаліць плэй-ліст? Гэта дзеянне нельга адмяніць.\n  Sort By:\n    EarliestPlayedFirst: Раней прайгравалі\n    NameDescending: Я-А\n    LatestCreatedFirst: Нядаўна створаны\n    EarliestCreatedFirst: Створаныя раней\n    NameAscending: А-Я\n    LatestUpdatedFirst: Нядаўна абноўлены\n    EarliestUpdatedFirst: Раней абноўленыя\n    LatestPlayedFirst: Нядаўна прайгравалі\n  Quick Bookmark Enabled: Хуткая закладка ўключана\n  Cannot delete the quick bookmark target playlist.: Немагчыма выдаліць мэтавы плэй-ліст хуткай закладкі.\n  This playlist currently has no videos.: Зараз у гэтым плэй-лісце няма відэа.\n  Save Changes: Захаваць змены\n  Enable Quick Bookmark With This Playlist: Уключыць хуткую закладку для гэтага плэй-ліста\n  Remove Duplicate Videos: Выдаліць дублікаты відэа\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Сапраўды выдаліць 1 прагледжанае відэа з плэй-ліста? Гэта дзеянне нельга адмяніць. | Сапраўды выдаліць {playlistItemCount} прагледжаных відэа з плэй-ліста? Гэта дзеянне нельга адмяніць.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Сапраўды выдаліць 1 дублікат відэа з плэй-ліста? Гэта дзеянне нельга адмяніць. | Сапраўды выдаліць {playlistItemCount} дублікатаў відэа з плэй-ліста? Гэта дзеянне нельга адмяніць.\n  Export Playlist: Экспартаваць плэй-ліст\n  The playlist has been successfully exported: Плэй-ліст паспяхова экспартаваны\n  TotalTimePlaylist: 'Агульны час: {duration}'\nHistory:\n  # On History Page\n  History: 'Гісторыя'\n  Watch History: 'Гісторыя прагляду'\n  Your history list is currently empty.: 'Ваша гісторыя прагляду зараз пустая.'\n  Empty Search Message: 'У вашай гісторыі няма відэа, якія б адпавядалі вашаму пошуку'\n  Search bar placeholder: \"Пошук у гісторыі\"\n  Case Sensitive Search: Пошук з улікам рэгістра\nSettings:\n  # On Settings Page\n  Settings: 'Налады'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Праграму трэба перазапусціць, каб змены ўступілі ў сілу. Перазапусціць і прымяніць змены?'\n  General Settings:\n    General Settings: 'Агульныя'\n    Check for Updates: 'Правяраць наяўнасць абнаўленняў'\n    Check for Latest Blog Posts: 'Правяраць апошнія паведамленні ў блогу'\n    Fallback to Non-Preferred Backend on Failure: 'Вяртанне да непераважнага бэкэнда ў выпадку няўдачы'\n    Enable Search Suggestions: 'Уключыць прапановы пошуку'\n    Default Landing Page: 'Хатняя старонка'\n    Locale Preference: 'Рэгіянальныя налады'\n    System Default: 'З налад сістэмы'\n    Preferred API Backend:\n      Preferred API Backend: 'Пераважны бэкэнд API'\n      Local API: 'Лакальны API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Тып прагляду відэа'\n      Grid: 'Сетка'\n      List: 'Спіс'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Налады эскізаў'\n      Default: 'Па змаўчанні'\n      Beginning: 'Пачатак'\n      Middle: 'Сярэдзіна'\n      End: 'Канец'\n      Hidden: 'Схавана'\n      Blur: Размыты\n    Current Invidious Instance: 'Бягучы экзэмпляр Invidious'\n    The currently set default instance is {instance}: 'Бягучы экзэмпляр па змаўчанні: {instance}'\n    No default instance has been set: 'Экзэмпляр па змаўчанні не зададзены'\n    Current instance will be randomized on startup: 'Бягучы экзэмпляр будзе рандомізаваны пры запуску'\n    Set Current Instance as Default: 'Усталяваць бягучы экзэмпляр па змаўчанні'\n    Clear Default Instance: 'Ачысціць экзэмпляр па змаўчанні'\n    View all Invidious instance information: 'Праглядзіце ўсю інфармацыю пра экзэмпляр Invidious'\n    Region for Trending: 'Рэгіён для Трэндаў'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Апрацоўка знешніх спасылак'\n      Open Link: 'Адкрыць спасылку'\n      Ask Before Opening Link: 'Спытаць, перш чым адкрываць спасылку'\n      No Action: 'Без дзеянняў'\n    Auto Load Next Page:\n      Label: Аўтаматычная загрузка наступнай старонкі\n      Tooltip: Аўтаматычна загружаць дадатковыя старонкі і каментарыі.\n    Open Deep Links In New Window: Адкрываць URL-адрасы, перададзеныя FreeTube, у новым акне\n  Theme Settings:\n    Theme Settings: 'Тэма'\n    Match Top Bar with Main Color: 'Выкарыстоўваць асноўны колер да верхняй панэлі'\n    Expand Side Bar by Default: 'Разгортваць бакавую панэль па змаўчанні'\n    Disable Smooth Scrolling: 'Адключыць плаўную прагортку'\n    UI Scale: 'Маштаб інтэрфейсу'\n    Hide Side Bar Labels: 'Схаваць надпісы на бакавой панэлі'\n    Hide FreeTube Header Logo: 'Схаваць лагатып загалоўка FreeTube'\n    Base Theme:\n      Base Theme: 'Базавая тэма'\n      Black: 'Чорная'\n      Dark: 'Цёмная'\n      System Default: 'Сістэмная'\n      Light: 'Светлая'\n      Dracula: 'Dracula'\n      Catppuccin Mocha: 'Catppuccin Mocha'\n      Pastel Pink: 'Пастэльна-ружовая'\n      Hot Pink: 'Ярка-ружовая'\n      Nordic: Nordic\n      Solarized Dark: Solarized цёмная\n      Solarized Light: Solarized светлая\n      Gruvbox Dark: Gruvbox цёмная\n      Catppuccin Frappe: Catppuccin Frappe\n      Gruvbox Light: Gruvbox светлая\n      Everforest Dark Hard: Эверфорэст Дарк Хард\n      Everforest Dark Medium: Эверфорэст Дарк Хард\n      Everforest Dark Low: Эверфорэст Дарк Хард\n      Everforest Light Hard: Эверфорэст Лігхт Хард\n      Everforest Light Medium: Эверфорэст Лігхт Медыум\n      Everforest Light Low: Эверфорэст Лігхт Лоў\n    Main Color Theme:\n      Main Color Theme: 'Асноўны колер тэмы'\n      Red: 'Чырвоны'\n      Pink: 'Ружовы'\n      Purple: 'Фіялетавы'\n      Deep Purple: 'Насычаны фіялетавы'\n      Indigo: 'Індыга'\n      Blue: 'Сіні'\n      Light Blue: 'Светла-сіні'\n      Cyan: 'Блакітны'\n      Teal: 'Бірузовы'\n      Green: 'Зялёны'\n      Light Green: 'Светла-зялёны'\n      Lime: 'Лаймавы'\n      Yellow: 'Жоўты'\n      Amber: 'Бурштынавы'\n      Orange: 'Аранжавы'\n      Deep Orange: 'Насычаны аранжавы'\n      Dracula Cyan: 'Dracula Блакітны'\n      Dracula Green: 'Dracula Зялёны'\n      Dracula Orange: 'Dracula Аранжавы'\n      Dracula Pink: 'Dracula Ружовы'\n      Dracula Purple: 'Dracula Фіялетавы'\n      Dracula Red: 'Dracula Чырвоны'\n      Dracula Yellow: 'Dracula Жоўты'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mocha Ружовая вада'\n      Catppuccin Mocha Flamingo: 'Catppuccin Mocha Фламінга'\n      Catppuccin Mocha Pink: 'Catppuccin Mocha Ружовы'\n      Catppuccin Mocha Mauve: 'Catppuccin Mocha Ліловы'\n      Catppuccin Mocha Red: 'Catppuccin Mocha Чырвоны'\n      Catppuccin Mocha Maroon: 'Catppuccin Mocha Бардовы'\n      Catppuccin Mocha Peach: 'Catppuccin Mocha Персікавы'\n      Catppuccin Mocha Yellow: 'Catppuccin Mocha Жоўты'\n      Catppuccin Mocha Green: 'Catppuccin Mocha Зялёны'\n      Catppuccin Mocha Teal: 'Catppuccin Mocha Бірузовы'\n      Catppuccin Mocha Sky: 'Catppuccin Mocha Неба'\n      Catppuccin Mocha Sapphire: 'Catppuccin Mocha Сапфір'\n      Catppuccin Mocha Blue: 'Catppuccin Mocha Сіні'\n      Catppuccin Mocha Lavender: 'Catppuccin Mocha Лаванда'\n      Solarized Magenta: Solarized Пурпурны\n      Solarized Violet: Solarized Фіялетавы\n      Solarized Cyan: Solarized Блакітны\n      Solarized Orange: Solarized Аранжавы\n      Solarized Red: Solarized Чырвоны\n      Solarized Green: Solarized Зялёны\n      Solarized Blue: Solarized Сіні\n      Solarized Yellow: Solarized Жоўты\n      Catppuccin Frappe Red: Catppuccin Frappe Чырвоны\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Ружовая вада\n      Catppuccin Frappe Pink: Catppuccin Frappe Ружовы\n      Catppuccin Frappe Maroon: Catppuccin Frappe Бардовы\n      Catppuccin Frappe Peach: Catppuccin Frappe Персікавы\n      Catppuccin Frappe Yellow: Catppuccin Frappe Жоўты\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Сапфір\n      Catppuccin Frappe Blue: Catppuccin Frappe Сіні\n      Catppuccin Frappe Lavender: Catppuccin Frappe Лаванда\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Фламінга\n      Catppuccin Frappe Mauve: Catppuccin Frappe Ліловы\n      Catppuccin Frappe Green: Catppuccin Frappe Зялёны\n      Catppuccin Frappe Sky: Catppuccin Frappe Неба\n      Catppuccin Frappe Teal: Catppuccin Frappe Бірузовы\n      Gruvbox Dark Aqua: Gruvbox Цёмная Аква\n      Gruvbox Light Orange: Gruvbox Светла-аранжавы\n      Gruvbox Dark Purple: Gruvbox Цёмна-фіялетавы\n      Gruvbox Light Blue: Gruvbox Светла-сіні\n      Gruvbox Light Purple: Gruvbox Светла-фіялетавы\n      Gruvbox Dark Green: Gruvbox Цёмна-зялёны\n      Gruvbox Dark Yellow: Gruvbox Цёмна-жоўты\n      Gruvbox Dark Blue: Gruvbox Цёмна-сіні\n      Gruvbox Dark Orange: Gruvbox Цёмна-аранжавы\n      Gruvbox Light Red: Gruvbox Светла-чырвоны\n      Everforest Dark Red: Everforest Цёмна-чырвоны\n      Everforest Dark Orange: Everforest Цёмна-аранжавы\n      Everforest Dark Yellow: Everforest Цёмна-жоўты\n      Everforest Dark Green: Everforest Цёмна-зялёны\n      Everforest Dark Aqua: Everforest Цёмная Аква\n      Everforest Dark Blue: Everforest Цёмна-сіні\n      Everforest Dark Purple: Everforest Цёмна-фіялетавы\n      Everforest Light Red: Everforest Светла-чырвоны\n      Everforest Light Orange: Everforest Светла-аранжавы\n      Everforest Light Yellow: Everforest Светла-жоўты\n      Everforest Light Green: Everforest Светла-зялёны\n      Everforest Light Aqua: Everforest Светлая Аква\n      Everforest Light Blue: Everforest Светла-сіні\n      Everforest Light Purple: Everforest Светла-фіялетавы\n    Secondary Color Theme: 'Другасны колер тэмы'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'Прайгравальнік'\n    Play Next Video: 'Аўтапрайграванне рэкамендаваных відэа'\n    Turn on Subtitles by Default: 'Уключыць субцітры па змаўчанні'\n    Autoplay Videos: 'Запускаць відэа аўтаматычна'\n    Proxy Videos Through Invidious: 'Прагляд відэа праз проксі Invidious'\n    Autoplay Playlists: 'Аўтапрайграванне відэа з плэй-лістоў'\n    Enable Theatre Mode by Default: 'Уключыць рэжым тэатра па змаўчанні'\n    Scroll Volume Over Video Player: 'Над відэапрайгравальнікам змяняць гучнасць колам мышы'\n    Scroll Playback Rate Over Video Player: 'Над відэапрайгравальнікам змяняць хуткасць прайгравання колам мышы'\n    Skip by Scrolling Over Video Player: 'Над відэапрайгравальнікам прапускаць відэа колам мышы'\n    Display Play Button In Video Player: 'Паказваць кнопку прайгравання ў відэапрайгравальніку'\n    Enter Fullscreen on Display Rotate: 'Пераходзіць у поўнаэкранны рэжым пры павароце дысплэя'\n    Next Video Interval: 'Час зваротнага адліку для аўтапрайгравання'\n    Fast-Forward / Rewind Interval: 'Інтэрвал перамоткі наперад / назад'\n    Default Volume: 'Гучнасць па змаўчанні'\n    Default Playback Rate: 'Хуткасць прайгравання па змаўчанні'\n    Max Video Playback Rate: 'Максімальная хуткасць прайгравання відэа'\n    Video Playback Rate Interval: 'Інтэрвал хуткасці прайгравання відэа'\n    Default Video Format:\n      Default Video Format: 'Фармат відэа па змаўчанні'\n      Dash Formats: 'Фарматы DASH'\n      Legacy Formats: 'Састарэлыя фарматы'\n      Audio Formats: 'Аўдыяфарматы'\n    Default Quality:\n      Default Quality: 'Якасць па змаўчанні'\n      Auto: 'Аўта'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: 'Уключыць здымак экрана'\n      Format Label: 'Фармат здымка'\n      Quality Label: 'Якасць здымка'\n      Ask Path: 'Пытаць папку для захоўвання'\n      Folder Label: 'Папка для здымкаў'\n      Folder Button: 'Выбраць папку'\n      File Name Label: 'Шаблон назвы файла'\n      File Name Tooltip: 'Вы можаце выкарыстоўваць пераменныя ніжэй. %Y Год 4 лічбы. %M Месяц 2 лічбы. %D Дні 2 лічбы. %H Гадзіны 2 лічбы. %N Хвіліны 2 лічбы. %S Секунды 2 лічбы. %T Мілісекунды 3 лічбы. %s Секунды відэа. %t Мілісекунды відэа 3 лічбы. %i Ідэнтыфікатар відэа.'\n      Error:\n        Forbidden Characters: 'Забароненыя сімвалы'\n        Empty File Name: 'Пустая назва файла'\n    Default Viewing Mode:\n      Theater: Тэатр\n      Default Viewing Mode: Рэжым прагляду па змаўчанні\n      Full Screen: Поўны экран\n      External Player: Знешні прайгравальнік ({externalPlayerName})\n      Picture in Picture: Выява ў Выяве\n    Autoplay Interruption Timer: Час перапынення аўтапрайгравання\n  External Player Settings:\n    External Player Settings: 'Знешні прайгравальнік'\n    External Player: 'Знешні прайгравальнік'\n    Ignore Unsupported Action Warnings: 'Ігнараваць папярэджанні аб дзеяннях, якія не падтрымліваюцца'\n    Custom External Player Executable: 'Шлях да ўласнага знешняга прайгравальніка'\n    Custom External Player Arguments: 'Аргументы знешняга прайгравальніка'\n    Players:\n      None:\n        Name: 'Ніякі'\n    Ignore Default Arguments: Ігнараваць аргументы па змаўчанні\n  Privacy Settings:\n    Privacy Settings: 'Прыватнасць'\n    Remember History: 'Памятаць гісторыю прагляду'\n    Save Watched Progress: 'Захоўваць прагрэс прагляду'\n    Save Watched Videos With Last Viewed Playlist: 'Захоўваць прагледжаныя відэа з апошнім прагледжаным плэй-лістам'\n    Clear Search Cache: 'Ачысціць кэш пошуку'\n    Are you sure you want to clear out your search cache?: 'Вы ўпэўнены, што хочаце ачысціць кэш пошуку?'\n    Search cache has been cleared: 'Кэш пошуку ачышчаны'\n    Remove Watch History: 'Выдаліць гісторыю праглядаў'\n    Are you sure you want to remove your entire watch history?: 'Сапраўды выдаліць усю гісторыю праглядаў?'\n    Watch history has been cleared: 'Гісторыя праглядаў ачышчана'\n    Remove All Subscriptions / Profiles: 'Выдаліць усе падпіскі / профілі'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Сапраўды выдаліць усе падпіскі і профілі?  Гэта дзеянне нельга адмяніць.'\n    Are you sure you want to remove all your playlists?: Сапраўды хочаце выдаліць усе свае плэй-лісты?\n    Remove All Playlists: Выдаліць усе плэй-лісты\n    All playlists have been removed: Усе плэй-лісты былі выдалены\n    Clear Search History and Cache: Ачысціць гісторыю пошуку і кэш\n    Are you sure you want to clear out your search history and cache?: Сапраўды ачысціць гісторыю пошуку і кэш?\n    Search history and cache have been cleared: Гісторыя пошуку і кэш ачышчаны\n    Remember Search History: Памятаць гісторыю пошуку\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Аўтаматычна\n        Semi-auto: Паўаўтаматычна\n        Never: Ніколі\n      Tooltip: Аўта = Захоўваць пры кожным выхадзе са старонкі відэа, калі відэа скончылася і ўзнікла памылка (напрыклад, хуткасць абмежавана і сеанс прагляду скончыўся). Паўаўтаматычны = як і аўтаматычны, за выключэннем выхаду з відэастаронкі і захавання прагрэсу ўручную з дапамогай кнопкі пад назвай \"Захаваць прагледжаны прагрэс\", размешчанай пад відэаплэерам.\n  Subscription Settings:\n    Subscription Settings: 'Падпіскі'\n    Fetch Feeds from RSS: 'Атрымліваць стужкі з RSS'\n    Fetch Automatically: 'Атрымліваць стужку аўтаматычна'\n    Confirm Before Unsubscribing: Пацвярджаць адпісванне\n    To: Да\n    'Limit the number of videos displayed for each channel': Абмежаваць колькасць відэа, якія паказваюцца на кожным канале\n  Distraction Free Settings:\n    Distraction Free Settings: 'Адцягненне ўвагі'\n    Sections:\n      Side Bar: 'Бакавая панэль'\n      Subscriptions Page: 'Старонка падпісак'\n      Channel Page: 'Старонка канала'\n      Watch Page: 'Старонка прагляду'\n      General: 'Агульныя'\n    Hide Video Views: 'Хаваць прагляды відэа'\n    Hide Video Likes And Dislikes: 'Хаваць лайкі і дызлайкі да відэа'\n    Hide Channel Subscribers: 'Хаваць падпісчыкаў канала'\n    Hide Comment Likes: 'Хаваць лайкі да каментарыяў'\n    Hide Recommended Videos: 'Хаваць рэкамендаваныя відэа'\n    Hide Trending Videos: 'Хаваць відэа ў трэндзе'\n    Hide Popular Videos: 'Хаваць папулярныя відэа'\n    Hide Playlists: 'Хаваць плэй-лісты'\n    Hide Live Chat: 'Хаваць жывы чат'\n    Hide Active Subscriptions: 'Хаваць актыўныя падпіскі'\n    Hide Video Description: 'Хаваць апісанне відэа'\n    Hide Comments: 'Хаваць каментарыі'\n    Hide Profile Pictures in Comments: 'Хаваць фатаграфіі профіляў у каментарыях'\n    Display Titles Without Excessive Capitalisation: 'Паказваць загалоўкі без празмерных вялікіх літар і знакаў прыпынку'\n    Hide Live Streams: 'Хаваць жывыя эфіры'\n    Hide Upcoming Premieres: 'Хаваць будучыя прэм''еры'\n    Hide Sharing Actions: 'Хаваць дзеянні абагульвання'\n    Hide Videos on Watch: 'Хаваць відэа пасля прагляду'\n    Hide Chapters: 'Хаваць раздзелы'\n    Hide Channels: 'Хаваць відэа з каналаў'\n    Hide Channels Placeholder: 'Ідэнтыфікатар канала'\n    Hide Featured Channels: 'Хаваць прапанаваныя каналы'\n    Hide Channel Playlists: 'Хаваць укладку «Плэй-лісты»'\n    Hide Channel Shorts: 'Хаваць укладку «Кароткія відэа»'\n    Hide Channel Podcasts: 'Хаваць укладку «Падкасты»'\n    Hide Channel Releases: 'Хаваць укладку «Выпускі»'\n    Hide Subscriptions Videos: 'Хаваць відэа з падпісак'\n    Hide Subscriptions Shorts: 'Хаваць кароткія відэа з падпісак'\n    Hide Subscriptions Live: 'Хаваць трансляцыі з падпісак'\n    Hide Channels Already Exists: Ідэнтыфікатар канала ўжо існуе\n    Hide Videos, Playlists and Channels Containing Text: Хаваць відэа і плэй-лісты, якія змяшчаюць тэкст\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Слова, фрагмент слова або фраза\n    Hide Channels Disabled Message: Некаторыя каналы былі заблакіраваны з дапамогай ідэнтыфікатара і не былі апрацаваны. Функцыя заблакіравана, пакуль гэтыя ідэнтыфікатары абнаўляюцца\n    Hide Channels Invalid: Памылковы ідэнтыфікатар канала\n    Hide Channels API Error: Памылка атрымання карыстальніка з указаным ідэнтыфікатарам. Праверце яшчэ раз, ці правільны ідэнтыфікатар.\n    Hide Channel Home: Хаваць укладку «Галоўная старонка»\n    Show Added Items: Паказаць дададзеныя элементы\n    Hide Channel Courses: Схаваць укладку «Курсы» канала\n    Hide Channel Posts: Хаваць укладку «Публікацыі»\n    Hide Subscriptions Posts: Хаваць публікацыі з падпісак\n  Data Settings:\n    Data Settings: 'Даныя'\n    Select Export Type: 'Выбраць тып экспарту'\n    Import Subscriptions: 'Імпарт падпісак'\n    Subscription File: 'Файл падпіскі'\n    History File: 'Файл гісторыі'\n    Playlist File: 'Файл плэй-ліста'\n    Export Subscriptions: 'Экспарт падпісак'\n    Export FreeTube: 'Экспарт FreeTube'\n    Export YouTube: 'Экспарт YouTube'\n    Export NewPipe: 'Экспарт NewPipe'\n    Import History: 'Імпарт гісторыі'\n    Export History: 'Экспарт гісторыі'\n    Import Playlists: 'Імпарт плэй-лістоў'\n    Export Playlists: 'Экспарт плэй-лістоў'\n    Profile object has insufficient data, skipping item: 'Аб''ект профілю мае недастаткова даных, пропуск элемента'\n    All subscriptions and profiles have been successfully imported: 'Усе падпіскі і профілі былі паспяхова імпартаваны'\n    All subscriptions have been successfully imported: 'Усе падпіскі былі паспяхова імпартаваны'\n    Invalid subscriptions file: 'Няправільны файл падпісак'\n    Invalid history file: 'Няправільны файл гісторыі'\n    Subscriptions have been successfully exported: 'Падпіскі былі паспяхова экспартаваныя'\n    History object has insufficient data, skipping item: 'Аб''ект гісторыі мае недастаткова даных, пропуск элемента'\n    All watched history has been successfully imported: 'Уся гісторыя праглядаў была паспяхова імпартавана'\n    All watched history has been successfully exported: 'Уся гісторыя праглядаў была паспяхова экспартавана'\n    Playlist insufficient data: 'Недастаткова даных для плэй-ліста \"{playlist}\", пропуск элемента'\n    All playlists has been successfully imported: 'Усе плэй-лісты былі паспяхова імпартаваны'\n    All playlists has been successfully exported: 'Усе плэй-лісты былі паспяхова экспартаваны'\n    Unable to read file: 'Немагчыма прачытаць файл'\n    Unable to write file: 'Немагчыма запісаць файл'\n    Unknown data key: 'Невядомы ключ даных'\n    How do I import my subscriptions?: 'Як мне імпартаваць свае падпіскі?'\n    Manage Subscriptions: 'Кіраванне падпіскамі'\n    Export Playlists For Older FreeTube Versions:\n      Label: Экспарт плэй-лістоў для старых версій FreeTube\n      Tooltip: \"Гэты параметр экспартуе відэа з усіх плэй-лістоў у адзін плэй-ліст пад назвай «Выбранае».\\nЯк экспартаваць і імпартаваць відэа ў плэй-лісты для старой версіі FreeTube:\\n1. Экспартуйце свае плэй-лісты з уключанай опцыяй.\\n 2. Выдаліце ўсе існуючыя плэй-лісты, выкарыстоўваючы опцыю «Выдаліць усе плэй-лісты» ў раздзеле «Налады прыватнасці».\\n3. Запусціце старую версію FreeTube і імпартуйце экспартаваныя плэй-лісты.\\\"\"\n  Proxy Settings:\n    Proxy Settings: 'Проксі'\n    Enable Tor / Proxy: 'Уключыць Tor / Проксі'\n    Proxy Protocol: 'Пратакол проксі'\n    Proxy Host: 'Адрас проксі'\n    Proxy Port Number: 'Нумар порта проксі'\n    Clicking on Test Proxy will send a request to: 'Пры націску на \"Тэст проксі\" будзе адпраўлены запыт на'\n    Test Proxy: 'Тэст проксі'\n    Your Info: 'Ваша інфармацыя'\n    Ip: 'IP'\n    Country: 'Краіна'\n    Region: 'Рэгіён'\n    City: 'Горад'\n    Error getting network information. Is your proxy configured properly?: 'Памылка атрымання інфармацыі аб сетцы. Ці правільна наладжаны ваш проксі?'\n    Proxy Warning: FreeTube не мае ўбудаванага проксі-сервера, але можа падключацца да знешняга проксі-сервера, напрыклад, да таго, які працуе на вашым кампутары, як Tor, або да знешняга проксі-сервера, напрыклад, да проксі-сервера SOCKS5, які прадастаўляецца некаторымі VPN. Калі гэта ўключана, пераканайцеся, што ваш проксі/Tor наладжаны належным чынам, інакш FreeTube не зможа атрымаць якія-небудзь дадзеныя.\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'SponsorBlock'\n    Enable SponsorBlock: 'Уключыць SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'URL-адрас SponsorBlock API (па змаўчанні https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'Апавяшчаць, калі сегмент спонсара прапушчаны'\n    UseDeArrowTitles: 'Выкарыстоўваць загалоўкі відэа DeArrow'\n    Skip Options:\n      Skip Option: 'Прапусціць варыянт'\n      Auto Skip: 'Аўтаматычны пропуск'\n      Show In Seek Bar: 'Паказваць на панэлі перамоткі'\n      Prompt To Skip: 'Прапаноўваць прапусціць'\n      Do Nothing: 'Нічога не рабіць'\n    Category Color: 'Колер катэгорыі'\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL-адрас API генератара мініяцюр DeArrow (па змаўчанні https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Выкарыстоўваць DeArrow для мініяцюр\n  Parental Control Settings:\n    Parental Control Settings: 'Бацькоўскі кантроль'\n    Hide Unsubscribe Button: 'Хаваць кнопку адпіскі'\n    Show Family Friendly Only: 'Паказаць толькі для сямейнага прагляду'\n    Hide Search Bar: 'Хаваць панэль пошуку'\n  Experimental Settings:\n    Experimental Settings: 'Эксперыменты'\n    Warning: 'Гэтыя налады эксперыментальныя і могуць выклікаць збоі праграмы. Вы выкарыстоўвайце іх на свой страх і рызыку. Настойліва рэкамендуем рабіць рэзервовыя копіі!'\n    Replace HTTP Cache: 'Замяніць кэш HTTP'\n  Password Dialog:\n    Password: 'Пароль'\n    Enter Password To Unlock: 'Каб разблакіраваць налады, увядзіце пароль'\n  Password Settings:\n    Password Settings: 'Пароль'\n    Set Password To Prevent Access: 'Задайце пароль, каб забараніць доступ да налад'\n    Set Password: 'Задаць пароль'\n    Remove Password: 'Выдаліць пароль'\n  Sort Settings Sections (A-Z): Упарадкаваць раздзелы налад (А-Я)\n  Return to Settings Menu: Вярнуцца ў меню налад\nAbout:\n  #On About page\n  About: 'Пра FreeTube'\n  Beta: 'Бэта-версія'\n  Source code: 'Зыходны код'\n  Downloads / Changelog: 'Спампоўванне / Журнал змяненняў'\n  GitHub releases: 'Выпускі GitHub'\n  Help: 'Даведка'\n  FreeTube Wiki: 'FreeTube Вікі'\n  FAQ: 'Частыя пытанні'\n  Discussions: 'Абмеркаванні'\n  Report a problem: 'Паведаміць пра праблему'\n  GitHub issues: 'Праблемы на GitHub'\n  Please check for duplicates before posting: 'Перад публікацыяй праверце наяўнасць дублікатаў'\n  Website: 'Вэб-сайт'\n  Blog: 'Блог'\n  Email: 'Электронная пошта'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Чат у Matrix'\n  room rules: 'правілы пакоя'\n  Translate: 'Пераклад'\n  Credits: 'Удзельнікі'\n  these people and projects: 'гэтым людзям і праектам'\n  Donate: 'Ахвяраваць'\n\n  AGPLv3: AGPLv3\nProfile:\n  Profile Settings: 'Профіль'\n  Toggle Profile List: 'Пераключыць спіс профіляў'\n  Profile Select: 'Выбар профілю'\n  Profile Filter: 'Фільтр профілю'\n  All Channels: 'Усе каналы'\n  Profile Manager: 'Кіраванне профілямі'\n  Create New Profile: 'Стварыць новы профіль'\n  Edit Profile: 'Рэдагаваць профіль'\n  Color Picker: 'Выбар колеру'\n  Custom Color: 'Нестандартны колер'\n  Profile Preview: 'Папярэдні прагляд профілю'\n  Create Profile: 'Стварыць профіль'\n  Update Profile: 'Абнавіць профіль'\n  Make Default Profile: 'Зрабіць профілем па змаўчанні'\n  Delete Profile: 'Выдаліць профіль'\n  Are you sure you want to delete this profile?: 'Сапраўды выдаліць гэты профіль?'\n  All subscriptions will also be deleted.: 'Усе падпіскі таксама будуць выдалены.'\n  Your profile name cannot be empty: 'Назва вашага профілю не можа быць пустой'\n  Profile has been created: 'Профіль створаны'\n  Profile has been updated: 'Профіль абноўлены'\n  Your default profile has been set to {profile}: 'Профілем па змаўчанні зададзены {profile}'\n  Removed {profile} from your profiles: '{profile} выдалены з вашых профіляў'\n  Your default profile has been changed to your primary profile: 'Ваш профіль па змаўчанні быў зменены на асноўны'\n  '{profile} is now the active profile': '{profile} цяпер актыўны профіль'\n  Subscription List: 'Спіс падпісак'\n  Other Channels: 'Іншыя каналы'\n  '{number} selected': '{number} выбрана'\n  Select All: 'Выбраць усе'\n  Select None: 'Ачысціць'\n  Delete Selected: 'Выдаліць выбранае'\n  Add Selected To Profile: 'Дадаць выбранае ў профіль'\n  No channel(s) have been selected: 'Канал(-ы) не выбраны'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Гэта ваш асноўны профіль.  Сапраўды выдаліць выбраныя каналы?  Яны будуць выдалены з кожнага профілю, у якім знаходзяцца.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Сапраўды выдаліць выбраныя каналы?  Канал не будзе выдалены з іншых профіляў.'\n#On Channel Page\n  Edit Profile Name: Рэдагаваць назву профілю\n  Create Profile Name: Стварыце назву профілю\n  Profile Name: Назва профілю\n  Close Profile Dropdown: Закрыць выпадное меню профілю\n  Open Profile Dropdown: Адкрыць выпадное меню профілю\nChannel:\n  Subscribe: 'Падпісацца'\n  Unsubscribe: 'Адпісацца'\n  Channel has been removed from your subscriptions: 'Канал быў выдалены з вашых падпісак'\n  Removed subscription from {count} other channel(s): 'Падпіска выдалена з {count} іншага канала(ў)'\n  Added channel to your subscriptions: 'Канал дададзены да вашых падпісак'\n  Search Channel: 'Пошук на канале'\n  Your search results have returned 0 results: 'Пошук даў 0 вынікаў'\n  This channel does not exist: 'Гэты канал не існуе'\n  This channel does not allow searching: 'Гэты канал не дазваляе шукаць'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'Гэты канал абмежаваны па ўзросце, і зараз яго нельга праглядаць у FreeTube.'\n  Channel Tabs: 'Укладкі канала'\n  Videos:\n    Videos: 'Відэа'\n    This channel does not currently have any videos: 'Зараз на гэтым канале няма відэа'\n    Sort Types:\n      Newest: 'Самае новае'\n      Oldest: 'Самае старое'\n      Most Popular: 'Самае папулярнае'\n  Shorts:\n    This channel does not currently have any shorts: 'Зараз на гэтым канале няма кароткіх відэа'\n  Live:\n    Live: 'Ужывую'\n    This channel does not currently have any live streams: 'Зараз на гэтым канале няма жывых трансляцый'\n  Playlists:\n    Playlists: 'Плэй-лісты'\n    This channel does not currently have any playlists: 'Зараз на гэтым канале няма плэй-лістоў'\n    Sort Types:\n      Last Video Added: 'Апошняе дададзенае відэа'\n      Newest: 'Самае новае'\n      Oldest: 'Самае старое'\n  Podcasts:\n    Podcasts: 'Падкасты'\n    This channel does not currently have any podcasts: 'Зараз на гэтым канале няма падкастаў'\n  Releases:\n    Releases: 'Выпускі'\n    This channel does not currently have any releases: 'Зараз на гэтым канале няма выпускаў'\n  About:\n    About: 'Пра канал'\n    Channel Description: 'Апісанне канала'\n    Tags:\n      Tags: 'Цэтлікі'\n      Search for: 'Шукаць \"{tag}\"'\n    Details: 'Падрабязнасці'\n    Joined: 'Далучыўся'\n    Location: 'Месцазнаходжанне'\n    Featured Channels: 'Рэкамендаваныя каналы'\n  Posts:\n    This channel currently does not have any posts: 'Зараз на гэтым канале няма паведамленняў'\n    votes: '{votes} галасоў'\n    Reveal Answers: 'Адкрыць адказы'\n    Hide Answers: 'Схаваць адказы'\n    Video hidden by FreeTube: Відэа схавана FreeTube'ам\n    View Full Post: Глядзець поўны пост\n    Viewing Posts Only Supported By Invidious: Прагляд паведамленняў падтрымліваецца толькі ў Invidious. Перайдзіце на ўкладку супольнасці канала, каб праглядзець там змесціва без Invidious.\n  Home:\n    Home: Галоўная старонка\n    View Playlist: Праглядзець плэй-ліст\n  Courses:\n    This channel does not currently have any courses: Зараз на гэтым канале няма курсаў\n    Courses: Курсы\nVideo:\n  Mark As Watched: 'Пазначыць як прагледжанае'\n  Remove From History: 'Выдаліць з гісторыі'\n  Video has been marked as watched: 'Відэа было пазначана як прагледжанае'\n  Video has been removed from your history: 'Відэа было выдалена з вашай гісторыі'\n  Save Video: 'Захаваць відэа'\n  Video has been saved: 'Відэа захавана'\n  Video has been removed from your saved list: 'Відэа было выдалена з вашага спісу захаваных'\n  Open in YouTube: 'Адкрыць у YouTube'\n  Copy YouTube Link: 'Скапіяваць спасылку YouTube'\n  Open YouTube Embedded Player: 'Адкрыць убудаваны прайгравальнік YouTube'\n  Copy YouTube Embedded Player Link: 'Скапіяваць спасылку на ўбудаваны прайгравальнік YouTube'\n  Open in Invidious: 'Адкрыць у Invidious'\n  Copy Invidious Link: 'Скапіяваць спасылку Invidious'\n  Open Channel in YouTube: 'Адкрыць канал у YouTube'\n  Copy YouTube Channel Link: 'Скапіяваць спасылку на канал YouTube'\n  Open Channel in Invidious: 'Адкрыць канал у Invidious'\n  Copy Invidious Channel Link: 'Скапіяваць спасылку на канал Invidious'\n  Views: 'Прагляды'\n  Loop Playlist: 'Зацыкліць плэй-ліст'\n  Shuffle Playlist: 'Перамяшаць плэй-ліст'\n  Reverse Playlist: 'Перавернуць плэй-ліст'\n  Previous: 'Назад'\n  Next: 'Наступнае'\n  Watched: 'Прагледжанае'\n  Autoplay: 'Аўтапрайграванне'\n  Starting soon, please refresh the page to check again: 'Хутка пачнецца, абнавіце старонку, каб праверыць яшчэ раз'\n  # As in a Live Video\n  Premieres: 'Прэм''еры'\n  Upcoming: 'Хутка'\n  Live: 'Ужывую'\n  Live Now: 'Зараз у эфіры'\n  Live Chat: 'Жывы чат'\n  Enable Live Chat: 'Уключыць жывы чат'\n  Live Chat is currently not supported in this build.: 'Жывы чат зараз не падтрымліваецца ў гэтай зборцы.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Жывы чат уключаны.  Паведамленні чата з''явяцца тут пасля адпраўкі.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Жывы чат зараз не падтрымліваецца Invidious API.  Патрабуецца прамое падключэнне да YouTube.'\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'Жывы чат недаступны для гэтай трансляцыі. Магчыма, ён быў адключаны запампавальнікам.'\n  Show Super Chat Comment: 'Паказаць каментарый Суперчата'\n  Scroll to Bottom: 'Пракруціць уніз'\n  Published:\n    In less than a minute: 'Менш чым праз хвіліну'\n  Published on: 'Апублікавана'\n  Streamed on: 'Транслявалася'\n  Started streaming on: 'Трансляцыя пачалася'\n  Sponsor Block category:\n    sponsor: 'Спонсар'\n    intro: 'Увядзенне'\n    outro: 'Канцоўка'\n    self-promotion: 'Самарэклама'\n    interaction: 'Узаемадзеянне'\n    music offtopic: 'Музыка не па тэме'\n    recap: 'Падвядзенне вынікаў'\n    filler: 'Напаўняльнік'\n  External Player:\n    OpenInTemplate: 'Адкрыць у {externalPlayer}'\n    video: 'відэа'\n    playlist: 'плэй-ліст'\n    OpeningTemplate: 'Адкрыццё {videoOrPlaylist} у {externalPlayer}...'\n    UnsupportedActionTemplate: '{externalPlayer} не падтрымлівае: {action}'\n    Unsupported Actions:\n      starting video at offset: 'пачатак відэа са зрушэннем'\n      setting a playback rate: 'налада хуткасці прайгравання'\n      opening playlists: 'адкрыццё плэй-лістоў'\n      opening specific video in a playlist (falling back to opening the video): 'адкрыццё пэўнага відэа ў плэй-лісце (вяртанне да адкрыцця відэа)'\n      reversing playlists: 'пераварочванне плэй-ліста'\n      shuffling playlists: 'перамешванне плэй-лістоў'\n      looping playlists: 'зацыкліванне плэй-лістоў'\n#& Videos\n  Hide Channel: Схаваць канал\n  Unhide Channel: Паказаць канал\n  More Options: Іншыя параметры\n  IP block: YouTube заблакіраваў ваш IP-адрас для прагляду відэа. Паспрабуйце пераключыцца на іншы VPN або проксі.\n  Player:\n    Audio Tracks: Гукавыя дарожкі\n    Full Window: Поўнаэкранны рэжым\n    Stats:\n      Stats: Статыстыка\n      Video ID: 'Ідэнтыфікатар відэа: {videoId}'\n      Media Formats: 'Фарматы медыя: {formats}'\n      Player Dimensions: 'Памеры прайгравальніка: {width}x{height}'\n      Bitrate: 'Бітрэйт: {bitrate} кбіт/с'\n      Buffered: 'Буферызавана: {bufferedPercentage}%'\n      Resolution: 'Раздзяляльнасць: {width}x{height}{''@''}{frameRate}'\n      Dropped Frames / Total Frames: 'Прапушчаныя кадры: {droppedFrames} / Усяго кадраў: {totalFrames}'\n      CodecsVideoAudio: 'Кодэкі: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Кодэкі: {videoCodec} / {audioCodec}'\n      Volume: 'Гучнасць: {volumePercentage}%'\n      Bandwidth: 'Паласа прапускання: {bandwidth} кбіт/с'\n      CodecAudio: 'Кодэк: {audioCodec} ({audioItag})'\n    Skipped segment: Прапушчаны сегмент {segmentCategory}\n    TranslatedCaptionTemplate: '{language} (пераклад з \"{originalLanguage}\")'\n    Theatre Mode: Рэжым тэатра\n    Exit Full Window: Выйсці з поўнаэкраннага рэжыму\n    Hide Stats: Схаваць статыстыку\n    Take Screenshot: Зрабіць здымак\n    Show Stats: Паказаць статыстыку\n    Exit Theatre Mode: Выйдзіце з рэжыму тэатра\n    You appear to be offline: Здаецца, вы па-за сеткай.\n    Playback will resume automatically when your connection comes back: Прайграванне ўзновіцца аўтаматычна, калі падключэнне адновіцца.\n#& Playlists\n    Autoplay is off: Аўтапрайграванне выключана\n    Autoplay is on: Аўтапрайграванне ўключана\n  Unlisted: Не ў спісе\n  DeArrow:\n    Show Original Details: Паказаць арыгінальныя дэталі\n    Show Modified Details: Паказаць змененыя дэталі\n  MembersOnly: Відэа толькі для спонсараў нельга глядзець з дапамогай FreeTube, бо яны патрабуюць уваходу ў Google і платнага членства на канале загрузчыка.\n  AgeRestricted: Відэа з абмежаваннем па ўзросце нельга глядзець з дапамогай FreeTube, бо яны патрабуюць уваходу ў Google і выкарыстання ўліковага запісу YouTube, праверанага па ўзросце.\n  DRMProtected: Відэа, абароненыя DRM, нельга прайграваць у FreeTube, бо для іх патрэбны прапрыетарныя кампаненты з закрытым зыходным кодам. Калі вы хочаце паглядзець гэтае відэа, праглядзіце яго на афіцыйным сайце YouTube у вэб-браўзеры з падтрымкай DRM.\n  Save Watched Progress: Захаваць назіраны прагрэс\n  Watched Progress Saved: Працэс захаваны\nPlaylist:\n  #& About\n  Playlist: 'Плэй-ліст'\n  View Full Playlist: 'Праглядзець увесь плэй-ліст'\n  Last Updated On: 'Апошняе абнаўленне'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    AuthorAscending: Аўтар (А-Я)\n    Custom: Карыстальніцкі\n    AuthorDescending: Аўтар (Я-А)\n    DateAddedNewest: Новыя спачатку\n    DateAddedOldest: Старыя спачатку\n    VideoTitleAscending: Назва (А-Я)\n    VideoTitleDescending: Назва (Я-А)\n    VideoDurationAscending: Працягласць (спачатку кароткія)\n    VideoDurationDescending: Працягласць (спачатку доўгія)\n    PublishedNewest: Апошнія апублікаваныя спачатку\n    PublishedOldest: Раней апублікаваныя спачатку\nChange Format:\n  Change Media Formats: 'Змяніць фарматы медыя'\n  Use Dash Formats: 'Выкарыстоўваць фарматы DASH'\n  Use Legacy Formats: 'Выкарыстоўваць старыя фарматы'\n  Use Audio Formats: 'Выкарыстоўваць аўдыяфарматы'\n  Dash formats are not available for this video: 'Фарматы DASH недаступныя для гэтага відэа'\n  Audio formats are not available for this video: 'Аўдыяфарматы недаступныя для гэтага відэа'\n  Legacy formats are not available for this video: Састарэлыя фарматы недаступныя для гэтага відэа\nShare:\n  Share Video: 'Падзяліцца відэа'\n  Share Channel: 'Падзяліцца каналам'\n  Share Playlist: 'Падзяліцца плэй-лістам'\n  Include Timestamp: 'Дадаць метку часу'\n  Copy Link: 'Скапіяваць спасылку'\n  Open Link: 'Адкрыць спасылку'\n  Copy Embed: 'Капіяваць для ўбудавання'\n  Open Embed: 'Адкрыць убудаванае'\n  # On Click\n  Invidious URL copied to clipboard: 'URL-адрас Invidious скапіяваны ў буфер абмену'\n  Invidious Embed URL copied to clipboard: 'Invidious URL-адрас для ўбудавання скапіяваны ў буфер абмену'\n  Invidious Channel URL copied to clipboard: 'URL-адрас канала Invidious скапіяваны ў буфер абмену'\n  YouTube URL copied to clipboard: 'URL-адрас YouTube скапіяваны ў буфер абмену'\n  YouTube Embed URL copied to clipboard: 'URL-адрас YouTube для ўбудавання скапіяваны ў буфер абмену'\n  YouTube Channel URL copied to clipboard: 'URL-адрас канала YouTube скапіяваны ў буфер абмену'\nClipboard:\n  Copy failed: 'Не атрымалася скапіяваць у буфер абмену'\n  Cannot access clipboard without a secure connection: 'Немагчыма атрымаць доступ да буфера абмену без бяспечнага злучэння'\n\nChapters:\n  Chapters: 'Раздзелы'\n  Key Moments: Ключавыя моманты\nMini Player: 'Міні плэер'\nComments:\n  Comments: 'Каментарыі'\n  Click to View Comments: 'Націсніце, каб праглядзець каментарыі'\n  Getting comment replies, please wait: 'Атрымліваюцца адказы на каментарыі, пачакайце'\n  There are no more comments for this video: 'Да гэтага відэа больш няма каментарыяў'\n  Hide Comments: 'Схаваць каментарыі'\n  Top comments: 'Папулярныя каментарыі'\n  Newest first: 'Спачатку новыя'\n  View {replyCount} replies: 'Праглядзець {replyCount} адказаў'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'Паказаць больш адказаў'\n  There are no comments available for this video: 'Да гэтага відэа няма каментарыяў'\n  Load More Comments: 'Загрузіць больш каментарыяў'\n  Pinned by: 'Замацавана'\n  Member: 'Член'\n  Subscribed: 'Падпісан'\n  Hearted: 'З сэрцам'\n  There are no comments available for this post: Да гэтай публікацыі няма каментарыяў\nUp Next: 'Далей'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Выберыце бэкэнд, які FreeTube выкарыстоўвае для атрымання даных. Лакальны API - гэта ўбудаваны экстрактар. Для падключэння Invidious API патрабуецца сервер Invidious.'\n    Fallback to Non-Preferred Backend on Failure: 'Калі ў вашым абраным API ўзнікае праблема, FreeTube аўтаматычна паспрабуе выкарыстаць непрыярытэтны API у якасці рэзервовага метаду, калі ён уключаны.'\n    Thumbnail Preference: 'Усе мініяцюры FreeTube будуць заменены кадрам відэа, размыты або схаваны замест мініяцюр па змаўчанні.'\n    Invidious Instance: 'Экзэмпляр Invidious, да якога FreeTube будзе падключацца для выклікаў API.'\n    Region for Trending: 'Рэгіён трэндаў дазваляе вам выбраць папулярныя відэа краіны, якія вы жадаеце паказваць.'\n    External Link Handling: |\n      Выберыце паводзіны па змаўчанні, калі націскаецца спасылка, якую нельга адкрыць у FreeTube..\n      Па змаўчанні FreeTube адкрые націснутую спасылку ў браўзеры па змаўчанні.\n    Open Deep Links In New Window: URL-адрасы, якія перадаюцца FreeTube, напрыклад, шляхам перанакіравання пашырэнняў браўзера або аргументаў каманднага радка, адкрываюцца ў новым акне.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Будзе падключацца да Invidious для прагляду відэа замест прамога падключэння да YouTube.'\n    Default Video Format: 'Задайце фарматы, якія выкарыстоўваюцца пры прайграванні відэа. Фарматы DASH могуць прайграваць больш высокія якасці. Састарэлыя фарматы абмежаваныя максімумам 360p, але выкарыстоўваюць меншую паласу прапускання. Аўдыяфарматы - гэта толькі аўдыяпатокі.'\n    Scroll Playback Rate Over Video Player: 'Калі курсор знаходзіцца над відэа, націсніце і ўтрымлівайце клавішу Control (клавіша Command на Mac) і круціце кола мышы ўверх або ўніз, каб кіраваць хуткасцю прайгравання. Націсніце і ўтрымлівайце клавішу Control (клавіша Command на Mac) і націсніце левай кнопкай мышы, каб хутка вярнуцца да хуткасці прайгравання па змаўчанні (1x, калі яна не была зменена ў наладах).'\n    Skip by Scrolling Over Video Player: 'Выкарыстоўваць кола мышы, каб прапускаць відэа як у MPV.'\n  External Player Settings:\n    External Player: 'Пры выбары знешняга прайгравальніка на мініяцюры будзе адлюстроўвацца значок для адкрыцця відэа (плэй-ліста, калі падтрымліваецца) у знешнім прайгравальніку. Увага, налады Invidious не ўплываюць на знешнія прайгравальнікі.'\n    Custom External Player Executable: 'Па змаўчанні FreeTube мяркуе, што абраны знешні прайгравальнік можна знайсці праз пераменную асяроддзя PATH. Пры неабходнасці тут можна задаць уласны шлях.'\n    Ignore Warnings: 'Адключыць папярэджанні, калі бягучы знешні прайгравальнік не падтрымлівае бягучае дзеянне (напрыклад, пераварочванне плэй-ліста і г.д.).'\n    Custom External Player Arguments: 'Любыя карыстальніцкія аргументы каманднага радка, якія вы хочаце перадаць знешняму прайгравальніку.'\n    DefaultCustomArgumentsTemplate: \"(Па змаўчанні: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Не адпраўляйце ніякіх аргументаў па змаўчанні на знешні прайгравальнік, акрамя URL-адраса відэа (напрыклад, частата прайгравання, URL-адрас плэй-ліста і г.д.). Карыстальніцкія аргументы ўсё роўна будуць перадавацца.\n  Distraction Free Settings:\n    Hide Channels: 'Увядзіце ідэнтыфікатар канала, каб схаваць усе відэа, плэй-лісты і сам канал ад з''яўлення ў пошукавых, трэндавых, самых папулярных і рэкамендаваных. Уведзены ідэнтыфікатар канала павінен цалкам супадаць і ўлічваць рэгістр.'\n    Hide Subscriptions Live: 'Гэта налада перавызначаецца наладай \"{appWideSetting}\" для ўсёй праграмы ў раздзеле \"{subsection}\" у \"{settingsSection}\"'\n    Hide Videos, Playlists and Channels Containing Text: Увядзіце слова, фрагмент слова або фразу (без уліку рэгістра), каб схаваць усе відэа і плэй-лісты, арыгінальныя назвы якіх утрымліваюць гэта, ва ўсім FreeTube, за выключэннем толькі Гісторыі, Вашых плэй-лістоў і відэа ў плэй-лістах.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Пры ўключэнні FreeTube будзе выкарыстоўваць RSS замест метаду па змаўчанні для атрымання вашай стужкі падпіскі. RSS працуе хутчэй і прадухіляе блакіроўку IP-адрасоў, але не дае пэўнай інфармацыі, такой як працягласць відэа, стан у прамым эфіры або паведамленняў у супольнасці'\n    Fetch Automatically: 'Калі ўключана, FreeTube будзе аўтаматычна атрымліваць стужку з вашых падпісак падчас запуску і пры адкрыцці новага акна.'\n  Experimental Settings:\n    Replace HTTP Cache: 'Адключае HTTP кэш Electron''у на дыску і ўключае карыстальніцкі кэш малюнкаў у памяці. Прывядзе да павелічэння выкарыстання аператыўнай памяці.'\n  SponsorBlock Settings:\n    UseDeArrowTitles: 'Заменіце загалоўкі відэа на загалоўкі, прадстаўленыя карыстальнікамі з DeArrow.'\n\n# Toast Messages\n    UseDeArrowThumbnails: Заменіце мініяцюры відэа на мініяцюры ад DeArrow.\nLocal API Error (Click to copy): 'Памылка лакальнага API (націсніце, каб скапіяваць)'\nInvidious API Error (Click to copy): 'Памылка API Invidious (Націсніце, каб скапіяваць)'\nFalling back to Invidious API: 'Вяртанне да Invidious API'\nFalling back to Local API: 'Вяртанне да лакальнага API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Гэта відэа недаступнае з-за адсутнасці фарматаў. Гэта можа адбыцца з-за недаступнасці краіны.'\nUnknown YouTube url type, cannot be opened in app: 'Невядомы тып URL-адраса YouTube, немагчыма адкрыць у праграме'\nLoop is now disabled: 'Цыкл адключаны'\nLoop is now enabled: 'Цыкл уключаны'\nShuffle is now disabled: 'Перамешванне выключана'\nShuffle is now enabled: 'Перамешванне ўключана'\nThe playlist has been reversed: 'Плэй-ліст перавернуты'\nPlaying Next Video: 'Прайграванне наступнага відэа'\nPlaying Previous Video: 'Прайграванне папярэдняга відэа'\nPlaying Next Video Interval: 'Прайграванне наступнага відэа ў самыя кароткія тэрміны. Націсніце, каб адмяніць. | Прайграванне наступнага відэа праз {nextVideoInterval} секунды. Націсніце, каб адмяніць. | Прайграванне наступнага відэа праз {nextVideoInterval} секунд. Націсніце, каб адмяніць.'\nCanceled next video autoplay: 'Аўтапрайграванне наступнага відэа адменена'\n\nDefault Invidious instance has been set to {instance}: 'Экзэмпляр Invidious па змаўчанні быў усталяваны ў {instance}'\nDefault Invidious instance has been cleared: 'Экзэмпляр Invidious па змаўчанні быў выдалены'\n'The playlist has ended. Enable loop to continue playing': 'Плэй-ліст скончыўся.  Каб працягнуць прайграванне, уключыце цыкл'\nExternal link opening has been disabled in the general settings: 'Адкрыццё знешніх спасылак было адключана ў агульных наладах'\nScreenshot Success: 'Здымак захаваны'\nScreenshot Error: 'Здымак не ўдаўся. {error}'\n\nHashtag:\n  Hashtag: 'Цэтлік'\n  This hashtag does not currently have any videos: 'Гэты цэтлік зараз не змяшчае відэа'\nYes: 'Так'\nNo: 'Не'\nOk: 'Ок'\nSearch Listing:\n  Label:\n    Subtitles: Субцітры\n    4K: 4K\n    Closed Captions: Субцітры\n    360 Video: 360°\n    8K: 8K\n    VR180: VR180\n    New: Новае\n    3D: 3D\nYes, Delete: Так, выдаліць\nFeed:\n  Refresh Feed: Абнавіць {subscriptionName}\n  Feed Last Updated: 'Апошняе абнаўленне стужкі «{feedName}»: {date}'\nDisplay Label: '{label}: {value}'\nCancel: Адмена\ncheckmark: ✓\nClose Banner: Закрыць банер\nGo to page: Перайсці да {page}\nMoments Ago: толькі што\nYes, Restart: Так, перазапусціць\nYes, Open Link: Так, адкрыць спасылку\nTag already exists: Цэтлік \"{tagName}\" ужо існуе\nSearch character limit: Пошукавы запыт перавышае ліміт сімвалаў у {searchCharacterLimit}\nTrimmed input must be at least N characters long: Скарочаны ўвод павінен змяшчаць не менш за 1 сімвал | Скарочаны ўвод павінен змяшчаць не менш за {length} сімвалаў\nChannel Hidden: '{channel} дададзены ў фільтр каналаў'\nAge Restricted:\n  This channel is age restricted: Гэты канал мае ўзроставыя абмежаванні\n  This video is age restricted: Гэты відэа мае ўзроставыя абмежаванні\nChannel Unhidden: '{channel} выдалены з фільтра каналаў'\nKeyboardShortcutPrompt:\n  Show Keyboard Shortcuts: Паказаць спалучэнні клавіш\n  Last Frame: Папярэдні кадр (падчас паўзы)\n  Take Screenshot: Зрабіць здымак экрана\n  Keyboard Shortcuts: Спалучэнні клавіш\n  Sections:\n    Video:\n      Playback: Відэа: Прайграванне\n      General: Відэа: Агульныя\n    App:\n      General: Праграма: Агульныя\n      Situational: 'Праграма: Сітуацыйныя'\n  History Forward: Перайсці на адну старонку наперад\n  New Window: Стварыць новае акно\n  Navigate to Settings: Перайсці на старонку налад\n  Navigate to History: Перайсці на старонку гісторыі\n  Refresh: Абнавіць стужку з новым змесцівам\n  Captions: Уключыць/выключыць субцітры\n  Stats: Паказаць статыстыку відэа\n  Fullscreen: Уключыць/выключыць поўнаэкранны рэжым\n  Play: Уключыць прайграванне/паўзу\n  Toggle Developer Tools: Уключыць/выключыць інструменты распрацоўшчыка\n  Zoom In: Павялічыць\n  Next Frame: Наступны кадр (падчас паўзы)\n  Volume Down: Паменшыць гучнасць\n  Volume Up: Павялічыць гучнасць\n  Next Chapter: Наступны раздзел\n  History Backward: Вярнуцца на адну старонку назад\n  Mute: Уключыць/выключыць гук\n  Theatre Mode: Пераключыць рэжым тэатра\n  Minimize Window: Згарнуць акно\n  Close Window: Закрыць акно\n  Zoom Out: Паменшыць\n  Search in New Window: Пошук у новым акне\n  Picture in Picture: Уключыць/выключыць міні-прайгравальнік\n  Large Rewind: Пераматаць назад на 10 секунд / Пераматаць назад згодна з бягучай хуткасцю прайгравання\n  Large Fast Forward: Пераматаць уперад на 10 секунд / Пераматаць уперад згодна з бягучай хуткасцю прайгравання\n  Reset Zoom: Скінуць узровень павелічэння / UI шкалу\n  Focus Search: Перанесці фокус на панэль пошуку\n  Full Window: Пераключыць поўнае акно\n  Last Chapter: Апошні раздзел\n  Focus Secondary Search: Перанесці фокус на другасную панэль пошуку (калі яна ёсць)\n  Skip by Tenths: Прапускаць відэа ў працэнтах (3 пераходу да 30% працягласці)\n  Increase Video Speed: Павялічыць хуткасць відэа на аснове інтэрвалу хуткасці прайгравання відэа\n  Decrease Video Speed: Паменшыць хуткасць відэа на аснове інтэрвалу хуткасці прайгравання відэа\n  Small Fast Forward: Перамотка наперад X секунд на аснове інтэрвалу перамоткі наперад і бягучай хуткасці прайгравання відэа\n  Small Rewind: Перамотка на X секунд на аснове інтэрвалу перамоткі і бягучай хуткасці прайгравання відэа\n  Home: Пераматаць на пачатак відэа\n  End: Пераматаць на канец відэа\nKeys:\n  arrowup: Стрэлка ўверх\n  arrowright: Стрэлка ўправа\n  arrowdown: Стрэлка ўніз\n  arrowleft: Стрэлка ўлева\n  plus: Плюс\n  enter: Enter\n  shift: Shift\n  alt: Alt\n  ctrl: Ctrl\nshortcutLabelSeparator: ｜\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nDescription:\n  Expand Description: '...больш'\n  Collapse Description: Паказаць менш\nRight-click or hold to see history: ПКМ або працяглае націсканне, каб праглядзець гісторыю\nAutoplay Interruption Timer: Аўтапрайграванне адменена з-за {autoplayInterruptionIntervalHours} гадзін бяздзейнасці\n"
  },
  {
    "path": "static/locales/bg.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Български'\n\n# Webkit Menu Bar\nFile: 'Файл'\nQuit: 'Изход'\nEdit: 'Редакция'\nUndo: 'Отмяна'\nRedo: 'Възстановяване'\nCut: 'Изрязване'\nCopy: 'Копиране'\nPaste: 'Поставяне'\nDelete: 'Изтриване'\nSelect all: 'Избиране на всичко'\nToggle Developer Tools: 'Показване на инструменти за разработчици'\nActual size: 'Действителен размер'\nZoom in: 'Увеличаване'\nZoom out: 'Намаляване'\nToggle fullscreen: 'Превключване на цял екран'\nWindow: 'Прозорец'\nMinimize: 'Минимизиране'\nClose: 'Затваряне'\nBack: 'Назад'\nForward: 'Напред'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Видеа'\n  Shorts: Кратки видеа\n  Live: На живо\n  Posts: Публикации\n  Sort By: Подреждане по\n\n  Counts:\n    Video Count: 1 видео | {count} видеа\n    Channel Count: 1 канал | {count} канала\n    Subscriber Count: 1 абонат | {count} абоната\n    View Count: 1 преглед | {count} прегледа\n    Watching Count: 1 гледане | {count} гледания\n    Like Count: 1 харесване | {count} харесвания\n    Comment Count: 1 коментар | {count} коментара\nVersion {versionNumber} is now available!  Click for more details: 'Версия {versionNumber} е вече налична! Щракнете за повече детайли'\nDownload From Site: 'Сваляне от сайта'\nA new blog is now available, {blogTitle}. Click to view more: 'Нова публикация в блога, {blogTitle}. Щракнете за преглед'\n\n# Search Bar\nSearch / Go to URL: 'Търсене / Отиване на адрес'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Филтри за търсене'\n  Sort By:\n    Most Relevant: 'Най-уместно'\n    Rating: 'Оценка'\n    Upload Date: 'Дата на качване'\n    View Count: 'Брой показвания'\n  Time:\n    Time: 'Време'\n    Any Time: 'Независимо кога'\n    Last Hour: 'Последния час'\n    Today: 'Днес'\n    This Week: 'Тази седмица'\n    This Month: 'Този месец'\n    This Year: 'Тази година'\n  Type:\n    Type: 'Тип'\n    All Types: 'Всички типове'\n    Videos: 'Видеа'\n    Channels: 'Канали'\n    #& Playlists\n    Movies: Филми\n  Duration:\n    Duration: 'Продължителност'\n    All Durations: 'Всички продължителности'\n    Short (< 4 minutes): 'Кратки (< 4 минути)'\n    Long (> 20 minutes): 'Дълги (> 20 минути)'\n  # On Search Page\n    Medium (4 - 20 minutes): Средни (4 - 20 минути)\n  Search Results: 'Резултати от търсенето'\n  Fetching results. Please wait: 'Събиране на резултати. Моля, изчакайте'\n  Fetch more results: 'Намиране на още резултати'\n# Sidebar\n  There are no more results for this search: Няма повече резултати за това търсене\n  Features:\n    Features: Функции\n    Subtitles: Субтитри\n    Live: На живо\n    Creative Commons: '\"Криейтив комънс\"'\n    360 Video: 360°\n    Location: Местоположение\n    HDR: HDR\n    VR180: VR180\n    HD: HD\n    3D: 3D\n    4K: 4K\n  Clear Filters: Изчистване на филтрите\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Абонаменти'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Списъкът с абонаменти е празен. Ако искате да внесете абонаментите си, отидете в \"Настройки на данни\" и изберете \"Внасяне на абонаменти\" или можете да потърсите канал и да се абонирате за него.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Този профил има голям брой абонаменти. Принудително използване на RSS за заобикаляне на ограниченията\n  Load More Videos: Зареждане на още видеа\n  Error Channels: Канали с грешки\n  Disabled Automatic Fetching: Автоматичното извличане на абонаменти е деактивирано. Обновете абонаментите, за да ги видите тук.\n  Empty Channels: Каналите, за които сте абонирани, в момента нямат никакви видеа.\n  Subscriptions Tabs: Раздели с абонаменти\n  All Subscription Tabs Hidden: Всички раздели на абонамента са скрити. За да виждате съдържанието тук, моля, премахнете скриването на някои раздели в секция \"{subsection}\" на \"{settingsSection}\".\n  Load More Posts: Зареждане на още публикации\n  Empty Posts: В момента в абонираните от вас канали няма публикации.\nTrending:\n  Trending: 'Набиращи популярност'\n  Trending Tabs: Раздели за набиращи популярност\n  Gaming: Игри\n  Sports: Спорт\nMost Popular: 'Най-популярни'\nPlaylists: 'Плейлисти'\nUser Playlists:\n  Your Playlists: 'Вашите плейлисти'\n  Search bar placeholder: Търсене за плейлисти\n  Empty Search Message: В този плейлист няма видеа, които да отговарят на търсенето ви\n  This playlist currently has no videos.: В този плейлист в момента няма видеа.\n  Add to Favorites: Добавяне към {playlistName}\n  Are you sure you want to delete this playlist? This cannot be undone: Сигурни ли сте, че искате да изтриете този плейлист? Това не може да бъде отменено.\n  SinglePlaylistView:\n    Toast:\n      Reverted to use {oldPlaylistName} for quick bookmark: Възстановено е използването на {oldPlaylistName} за бързи отметки\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Някои видеа в плейлиста все още не са заредени. Щракнете тук, за да копирате.\n      Playlist {playlistName} has been deleted.: Плейлиста {playlistName} е изтрит.\n      There were no videos to remove.: Няма видеа за премахване.\n      This video cannot be moved up.: Това видео не може да бъде преместено нагоре.\n      This video cannot be moved down.: Това видео не може да бъде преместено надолу.\n      Video has been removed: Видеото е премахнато\n      There was a problem with removing this video: Имаше проблем с премахването на това видео\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Този плейлист вече се използва за бързи отметки вместо {oldPlaylistName}. Щракнете тук, за отмяна\n      This playlist is now used for quick bookmark: Този плейлист вече се използва за бързи отметки\n      Playlist name cannot be empty. Please input a name.: Името на плейлиста не може да бъде празно. Моля, въведете име.\n      Playlist has been updated.: Плейлиста е актуализиран.\n      There was an issue with updating this playlist.: Имаше проблем с актуализирането на този плейлист.\n      \"{videoCount} video(s) have been removed\": 1 видео е премахнато | {videoCount} видеа са премахнати\n      This playlist is protected and cannot be removed.: Този плейлист е защитен и не може да бъде премахнат.\n      This playlist does not exist: Този плейлист не съществува\n      This playlist is already being used for quick bookmark.: Този плейлист вече се използва за бързи отметки.\n      This playlist has a video with a duration error: Този плейлист съдържа поне едно видео, което няма продължителност, той ще бъде подреден така, сякаш продължителността му е нула.\n      Video has been removed. Click here to undo.: Видеото е премахнато. Щракнете тук, за отмяна.\n    Search for Videos: Търсене за видеа\n  CreatePlaylistPrompt:\n    Toast:\n      Playlist {playlistName} has been successfully created.: Плейлиста {playlistName} е създаден успешно.\n      There is already a playlist with this name. Please pick a different name.: Вече има плейлист с това име. Моля, изберете друго.\n      There was an issue with creating the playlist.: Имаше проблем при създаването на плейлиста.\n    New Playlist Name: Име на нов плейлист\n    Create: Създаване\n  You have no playlists. Click on the create new playlist button to create a new one.: Нямате плейлисти. Щракнете върху бутона за създаване на нов плейлист, за да създадете нов.\n  Create New Playlist: Създаване на нов\n  Add to Playlist: Добавяне към плейлист за изпълнение\n  Move Video Up: Преместване нагоре\n  Playlist Description: Описание\n  Cancel: Отказ\n  Sort By:\n    LatestCreatedFirst: Дата на създаване (най-нови)\n    EarliestCreatedFirst: Дата на създаване (най-стари)\n    EarliestPlayedFirst: Дата на възпроизвеждане (най-стари)\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestUpdatedFirst: Дата на обновяване (най-нови)\n    EarliestUpdatedFirst: Дата на обновяване (най-стари)\n    LatestPlayedFirst: Дата на възпроизвеждане (най-нови)\n  AddVideoPrompt:\n    Search in Playlists: Търсене в плейлисти\n    Select a playlist to add your N videos to: Изберете плейлист, в който да добавите своето видео | Изберете плейлист, в който да добавите своите {videoCount} видеа\n    N playlists selected: '{playlistCount} избрани'\n    Toast:\n      You haven't selected any playlist yet.: Все още не сте избрали плейлист.\n      \"Video(s) added to {playlistCount} playlists\": \"Видеа, добавени към 1 плейлист | Видеа, добавени към {playlistCount} плейлиста\"\n    Save: Запазване\n    Added {count} Times: Вече е добавено | Добавено {count} пъти\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": Вече са добавени {videoCount}/{totalVideoCount} видеа\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": Ще бъдат добавени {videoCount}/{totalVideoCount} видеа\n    Allow Adding Duplicate Video(s): Разрешаване на добавянето на дублиращи се видеа\n  Remove from Playlist: Премахване от плейлиста за изпълнение\n  Playlist Name: Име на плейлиста\n  Save Changes: Запазване на промените\n  Edit Playlist Info: Редактиране на инфо\n  Copy Playlist: Копиране на плейлиста\n  Remove Watched Videos: Премахване на гледаните видеа\n  Enable Quick Bookmark With This Playlist: Активиране на бърза отметка с този плейлист\n  Delete Playlist: Изтриване на плейлиста\n  Remove from Favorites: Премахване от {playlistName}\n  Move Video Down: Преместване надолу\n  Playlists with Matching Videos: Плейлисти със съвпадащи видеа\n  Quick Bookmark Enabled: Бързите отметки са активирани\n  Cannot delete the quick bookmark target playlist.: Не може да се изтрие целевия списък за плейлисти с бързи отметки.\n  Remove Duplicate Videos: Премахване на дублирани видеа\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Сигурни ли сте, че искате да премахнете 1 дублиращо се видео от този плейлист? Това не може да бъде отменено. | Сигурни ли сте, че искате да премахнете {playlistItemCount} дублиращи се видеа от този плейлист? Това не може да бъде отменено.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Сигурни ли сте, че искате да премахнете 1 гледано видео от този плейлист? Това не може да бъде отменено. | Сигурни ли сте, че искате да премахнете {playlistItemCount} гледани видеа от този плейлист? Това не може да бъде отменено.\n  Export Playlist: Изнасяне на плейлиста\n  The playlist has been successfully exported: Плейлистът е изнесен успешно\n  TotalTimePlaylist: 'Общо време: {duration}'\n  Export list of URLs: Изнасяне на списък с URL адреси\nHistory:\n  # On History Page\n  History: 'История'\n  Watch History: 'История на гледане'\n  Your history list is currently empty.: 'Плейлиста с история на гледанията е празен.'\n  Search bar placeholder: Търсене в историята\n  Empty Search Message: В историята няма видеа, които да отговарят на търсенето ви\n  Case Sensitive Search: Главни / малки букви\n  DateOldestHistory: Дата на гледане (най-стари)\n  DateNewestHistory: Дата на гледане (най-нови)\nSettings:\n  # On Settings Page\n  Settings: 'Настройки'\n  General Settings:\n    General Settings: 'Общи'\n    Check for Updates: 'Проверка за актуализации'\n    Check for Latest Blog Posts: 'Проверка за нови публикации в блога'\n    Fallback to Non-Preferred Backend on Failure: 'При грешка, връщане към непредпочитан интерфейс'\n    Enable Search Suggestions: 'Активиране на препоръките при търсене'\n    Default Landing Page: 'Страница по подразбиране'\n    Locale Preference: 'Език'\n    Preferred API Backend:\n      Preferred API Backend: 'Предпочитан вътрешен интерфейс'\n      Local API: 'Локален'\n      Invidious API: 'Invidious'\n    Video View Type:\n      Video View Type: 'Подредба на видеата'\n      Grid: 'Решетка'\n      List: 'Списък'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Настройки на миниатюри'\n      Default: 'По подразбиране'\n      Beginning: 'Начало на видео'\n      Middle: 'Среда на видео'\n      End: 'Край на видео'\n      Hidden: Скриване\n      Blur: Размазано\n    Region for Trending: 'Регион за набиращи популярност'\n        #! List countries\n    View all Invidious instance information: Преглед на пълна информация за Invidious обекта\n    System Default: Стандартен за системата\n    Clear Default Instance: Изчистване на сървъра по подразбиране\n    Set Current Instance as Default: Задаване на текущият сървър като по подразбиране\n    Current instance will be randomized on startup: Текущият сървър при стартиране ще бъде случаен\n    No default instance has been set: Няма зададен сървър по подразбиране\n    The currently set default instance is {instance}: Текущо зададеният сървър по подразбиране е {instance}\n    Current Invidious Instance: Текущ Invidious сървър\n    External Link Handling:\n      No Action: Без действие\n      Ask Before Opening Link: Питане, преди отворяне на връзка\n      Open Link: Отваряне на връзка\n      External Link Handling: Работа с външни връзки\n    Auto Load Next Page:\n      Label: Автоматично зареждане на следващата страница\n      Tooltip: Автоматично зареждане на допълнителни страници и коментари.\n    Open Deep Links In New Window: Отваряне в нов прозорец на URL адреси, преминаващи през FreeTube\n    Minimize to system tray: Намаляване в системната лента\n  Theme Settings:\n    Theme Settings: 'Тема'\n    Match Top Bar with Main Color: 'Съвпадане на горната лента с основната цветова тема'\n    Base Theme:\n      Base Theme: 'Основна тема'\n      Black: 'Черна'\n      Dark: 'Тъмна'\n      Light: 'Светла'\n      Dracula: Dracula\n      System Default: Стандартна за системата\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Пастелно розово\n      Hot Pink: Горещо розово\n      Nordic: Nordic\n      Solarized Dark: Solarized тъмна\n      Solarized Light: Solarized светла\n      Gruvbox Dark: Gruvbox тъмна\n      Gruvbox Light: Gruvbox светла\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Light Low: Everforest светло ниско\n      Everforest Light Hard: Everforest светло твърдо\n      Everforest Dark Hard: Everforest Тъмно твърдо\n      Everforest Light Medium: Everforest светло средно\n      Everforest Dark Medium: Everforest Тъмно средно\n      Everforest Dark Low: Everforest Тъмно ниско\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Основна цветова тема'\n      Red: 'Червено'\n      Pink: 'Розово'\n      Purple: 'Пурпурно'\n      Deep Purple: 'Наситено пурпурно'\n      Indigo: 'Наситено синьо'\n      Blue: 'Синьо'\n      Light Blue: 'Светло синьо'\n      Cyan: 'Синьозелено'\n      Teal: 'Наситено синьозелено'\n      Green: 'Зелено'\n      Light Green: 'Светло зелено'\n      Lime: 'Жълтозелено'\n      Yellow: 'Жълто'\n      Amber: 'Кехлибарено'\n      Orange: 'Оранжево'\n      Deep Orange: 'Наситено оранжево'\n      Dracula Cyan: 'Dracula Синьозелено'\n      Dracula Green: 'Dracula Зелено'\n      Dracula Orange: 'Dracula Оранжево'\n      Dracula Pink: 'Dracula Розово'\n      Dracula Purple: 'Dracula Пурпурно'\n      Dracula Red: 'Dracula Червено'\n      Dracula Yellow: 'Dracula Жълто'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Розова вода\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Фламинго\n      Catppuccin Mocha Pink: Catppuccin Mocha Розово\n      Catppuccin Mocha Mauve: Catppuccin Mocha Мораво\n      Catppuccin Mocha Red: Catppuccin Mocha Червено\n      Catppuccin Mocha Maroon: Catppuccin Mocha Кестеняво\n      Catppuccin Mocha Peach: Catppuccin Mocha Праскова\n      Catppuccin Mocha Yellow: Catppuccin Mocha Жълто\n      Catppuccin Mocha Sky: Catppuccin Mocha Небесносиньо\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Сапфир\n      Catppuccin Mocha Teal: Catppuccin Mocha Синьозелено\n      Catppuccin Mocha Lavender: Catppuccin Mocha Лавандула\n      Catppuccin Mocha Blue: Catppuccin Mocha Синьо\n      Catppuccin Mocha Green: Catppuccin Mocha Зелено\n      Solarized Yellow: Solarized Жълто\n      Solarized Orange: Solarized Оранжево\n      Solarized Red: Solarized Червено\n      Solarized Magenta: Solarized Пурпурно\n      Solarized Violet: Solarized Виолетово\n      Solarized Blue: Solarized Синьо\n      Solarized Cyan: Solarized Синьозелено\n      Solarized Green: Solarized Зелено\n      Gruvbox Dark Yellow: Gruvbox Тъмножълто\n      Gruvbox Dark Blue: Gruvbox Тъмносиньо\n      Gruvbox Dark Purple: Gruvbox Тъмнопурпурно\n      Gruvbox Dark Aqua: Gruvbox Тъмна вода\n      Gruvbox Light Blue: Gruvbox Светлосиньо\n      Gruvbox Light Purple: Gruvbox Светлопурпурно\n      Gruvbox Light Orange: Gruvbox Светлооранжево\n      Gruvbox Dark Green: Gruvbox Тъмнозелено\n      Gruvbox Dark Orange: Gruvbox Тъмнооранжево\n      Gruvbox Light Red: Gruvbox Светлочервено\n      Catppuccin Frappe Pink: Catppuccin Frappe Розово\n      Catppuccin Frappe Blue: Catppuccin Frappe Синьо\n      Catppuccin Frappe Lavender: Catppuccin Frappe Лавандула\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Фламинго\n      Catppuccin Frappe Red: Catppuccin Frappe Червено\n      Catppuccin Frappe Yellow: Catppuccin Frappe Жълто\n      Catppuccin Frappe Peach: Catppuccin Frappe Праскова\n      Catppuccin Frappe Mauve: Catppuccin Frappe Мораво\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Розова вода\n      Catppuccin Frappe Maroon: Catppuccin Frappe Кестеняво\n      Catppuccin Frappe Green: Catppuccin Frappe Зелено\n      Catppuccin Frappe Sky: Catppuccin Frappe Небесносиньо\n      Catppuccin Frappe Teal: Catppuccin Frappe Синьозелено\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Сапфир\n      Everforest Dark Red: Everforest Тъмночервено\n      Everforest Light Red: Everforest Светлочервено\n      Everforest Dark Blue: Everforest Тъмносиньо\n      Everforest Light Yellow: Everforest Светложълто\n      Everforest Light Green: Everforest Светлозелено\n      Everforest Dark Orange: Everforest Тъмнооранжево\n      Everforest Dark Yellow: Everforest Тъмножълто\n      Everforest Dark Green: Everforest Тъмнозелено\n      Everforest Dark Aqua: Everforest Тъмна вода\n      Everforest Light Orange: Everforest Светлооранжево\n      Everforest Dark Purple: Everforest Тъмнопурпурно\n      Everforest Light Aqua: Everforest Светла вода\n      Everforest Light Blue: Everforest Светлосиньо\n      Everforest Light Purple: Everforest Светлопурпурно\n      Catppuccin Latte Mauve: Catppuccin Latte Лилаво\n      Catppuccin Latte Red: Catppuccin Latte Червено\n    Secondary Color Theme: 'Вторична цветова тема'\n        #* Main Color Theme\n    UI Scale: Мащаб на интерфейса\n    Disable Smooth Scrolling: Изключване на плавното превъртане\n    Expand Side Bar by Default: Разширяване на страничната лента по подразбиране\n    Hide Side Bar Labels: Скриване етикетите на страничната лента\n    Hide FreeTube Header Logo: Скриване логото на FreeTube\n  Player Settings:\n    Player Settings: 'Плейър'\n    Play Next Video: 'Автоматично пускане на препоръчаните видеа'\n    Turn on Subtitles by Default: 'Включване на субтитрите по подразбиране'\n    Autoplay Videos: 'Автоматично пускане на видеата'\n    Proxy Videos Through Invidious: 'Прекарване на видеата през Invidious'\n    Autoplay Playlists: 'Автоматично пускане на видеата в плейлистите'\n    Enable Theatre Mode by Default: 'Активиране на широкоекранен режим по подразбиране'\n    Default Volume: 'Сила на звука'\n    Default Playback Rate: 'Скорост на възпроизвеждане'\n    Default Video Format:\n      Default Video Format: 'Видео формат'\n      Dash Formats: 'DASH формати'\n      Legacy Formats: 'Стари формати'\n      Audio Formats: 'Аудио формати'\n    Default Quality:\n      Default Quality: 'Качество'\n      Auto: 'Автоматично'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Таймер за обратно броене при автоматично възпроизвеждане\n    Display Play Button In Video Player: Показване на бутона за възпроизвеждане във видео плейъра\n    Scroll Volume Over Video Player: Промяна на звука при превъртане над видео плейъра\n    Fast-Forward / Rewind Interval: Интервал за бързо превъртане напред / назад\n    Scroll Playback Rate Over Video Player: Промяна на скоростта на възпроизвеждане над видео плейъра\n    Max Video Playback Rate: Максимална скорост на възпроизвеждане\n    Video Playback Rate Interval: Интервал на скоростта на възпроизвеждане\n    Screenshot:\n      Enable: Включване на снимки на екрана\n      Quality Label: Качество\n      Ask Path: Питане за папка за запазване\n      Folder Label: Папка\n      File Name Label: Модел за име на файл\n      Error:\n        Forbidden Characters: Забранени символи\n        Empty File Name: Празно име на файл\n      File Name Tooltip: Можете да използвате променливите по-долу. %Y - година - 4 цифри. %M - месец - 2 цифри. %D - ден - 2 цифри. %H - час - 2 цифри. %N - минути - 2 цифри. %S - секунди - 2 цифри. %T - милисекунди - 3 цифри. %s - видеосекунди. %t - видео милисекунди - 3 цифри. %i ID на видеото.\n      Format Label: Формат\n      Folder Button: Избор на папка\n    Enter Fullscreen on Display Rotate: Режим на цял екран при завъртане на дисплея\n    Skip by Scrolling Over Video Player: Превъртане над видео плейъра\n    Autoplay Interruption Timer: Таймер за прекъсване на автоматичното възпроизвеждане\n    Default Viewing Mode:\n      Full Screen: Цял екран\n      External Player: Външен плейър ({externalPlayerName})\n      Theater: Широк екран\n      Default Viewing Mode: Режим на гледане по подразбиране\n      Picture in Picture: Картина в картината\n  Privacy Settings:\n    Privacy Settings: 'Поверителност'\n    Remember History: 'Запазване на историята с гледания'\n    Save Watched Progress: 'Запазване напредъка на гледането'\n    Clear Search Cache: 'Изчистване кеша на търсенията'\n    Are you sure you want to clear out your search cache?: 'Сигурни ли сте, че искате да изчистите кеша на търсенията си?'\n    Search cache has been cleared: 'Кешът на търсенията беше изчистен'\n    Remove Watch History: 'Премахване на историята на гледанията'\n    Are you sure you want to remove your entire watch history?: 'Сигурни ли сте, че искате да премахнете цялата история на гледанията?'\n    Watch history has been cleared: 'Историята на гледанията беше изчистена'\n    Remove All Subscriptions / Profiles: 'Премахване на всички абонаменти / профили'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Сигурни ли сте, че искате да премахнете всички абонаменти и профили? Това не може да бъде възстановено.'\n    Save Watched Videos With Last Viewed Playlist: Запазване на гледани видеа с последно гледан плейлист\n    Remove All Playlists: Премахване на всички плейлисти\n    All playlists have been removed: Всички плейлисти са премахнати\n    Are you sure you want to remove all your playlists?: Сигурни ли сте, че искате да премахнете всичките си плейлисти?\n    Remember Search History: Запазване на историята с търсения\n    Clear Search History and Cache: Изчистване на историята с търсения и кеша\n    Are you sure you want to clear out your search history and cache?: Сигурни ли сте, че искате да изчистите историята с търсения и кеша?\n    Search history and cache have been cleared: Историята на търсенията и кеша бяха изчистени\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Автоматично\n        Semi-auto: Полуавтоматично\n        Never: Никога\n      Tooltip: Автоматично = Записване при всяко излизане от страницата с видеото, при приключването му и възникване на грешка (напр. ограничена скорост и изтичане на сесията за гледане). Полуавтоматично = Като Автоматично, с изключение на това, че при излизане от страницата с видеото може да се запазва напредъка ръчно чрез бутона Запазване на напредъка, разположен под видеоплейъра.\n  Subscription Settings:\n    Subscription Settings: 'Абонаменти'\n    Fetch Feeds from RSS: 'Извличане на съдържания през RSS'\n    Fetch Automatically: Автоматично извличане на съдържание\n    Confirm Before Unsubscribing: Избягване на случайно отписване\n    'Limit the number of videos displayed for each channel': Ограничаване на броя на показваните видеа за всеки канал\n    To: на\n  Data Settings:\n    Data Settings: 'Данни'\n    Select Export Type: 'Избор на тип за изнасяне'\n    Import Subscriptions: 'Внасяне на абонаменти'\n    Export Subscriptions: 'Изнасяне на абонаменти'\n    Export FreeTube: 'Изнасяне във FreeTube формат'\n    Export YouTube: 'Изнасяне в YouTube формат'\n    Export NewPipe: 'Изнасяне в NewPipe формат'\n    Import History: 'Внасяне на история'\n    Export History: 'Изнасяне на история'\n    Profile object has insufficient data, skipping item: 'В профила няма достатъчно данни, прескачане на обекта'\n    All subscriptions and profiles have been successfully imported: 'Всички абонаменти и профили бяха внесени успешно'\n    All subscriptions have been successfully imported: 'Всички абонаменти бяха внесени успешно'\n    Invalid subscriptions file: 'Невалиден файл с абонаменти'\n    Invalid history file: 'Невалиден файл с история'\n    Subscriptions have been successfully exported: 'Абонаментите бяха изнесени успешно'\n    History object has insufficient data, skipping item: 'Историята няма достатъчно данни, прескачане на обекта'\n    All watched history has been successfully imported: 'Цялата история на гледанията беше внесена успешно'\n    All watched history has been successfully exported: 'Цялата история на гледанията беше изнесена успешно'\n    Unable to read file: 'Файлът не се прочете'\n    Unable to write file: 'Файлът не се записа'\n    Unknown data key: 'Непознат ключ данни'\n    How do I import my subscriptions?: 'Как да внеса абонаментите си?'\n    Manage Subscriptions: Управление на абонаменти\n    Export Playlists: Изнасяне на плейлисти\n    All playlists has been successfully imported: Всички плейлисти са внесени успешно\n    Import Playlists: Внасяне на плейлисти\n    Playlist insufficient data: Недостатъчно данни за плейлист \"{playlist}\", прескачане на елемент\n    All playlists has been successfully exported: Всички плейлисти са изнесени успешно\n    History File: Файл с история\n    Playlist File: Файл с плейлисти\n    Subscription File: Файл с абонаменти\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Тази опция изнася видеа от всички плейлисти в един плейлист с име \\\"Предпочитани\\\".\\nКак да изнесете и внесете видеа в плейлисти за по-стара версия на FreeTube:\\n1. Изнесете плейлистите си с включена тази опция.\\n2. Изтрийте всичките си съществуващи плейлисти, като използвате опцията \\\"Премахване на всички плейлисти\\\" в Настройки за поверителност.\\n3. Стартирайте по-старата версия на FreeTube и внесете изнесените плейлисти.\\\"\"\n      Label: Изнасяне на плейлисти за по-стари версии на FreeTube\n\n    Search history file: Файл с история на търсенията\n    Search history: История с търсения\n    Import search history: Внасяне на история с търсения\n    Export search history: Изнасяне на история с търсения\n    All search history has been successfully imported: Цялата история на търсенията е внесена успешно\n    All search history has been successfully exported: Цялата история на търсенията е изнесена успешно\n  Distraction Free Settings:\n    Hide Live Chat: Скриване на чата на живо\n    Hide Popular Videos: Скриване на популярните видеа\n    Hide Trending Videos: Скриване на набиращите популярност видеа\n    Hide Recommended Videos: Скриване на препоръчаните видеа\n    Hide Comment Likes: Скриване оценките на коментарите\n    Hide Channel Subscribers: Скриване броя на абонатите на канали\n    Hide Video Likes And Dislikes: Скриване оценките на видеата\n    Hide Video Views: Скриване броя показвания на видеата\n    Distraction Free Settings: Без разсейване\n    Hide Active Subscriptions: Скриване на активните абонаменти\n    Hide Playlists: Скриване на плейлисти\n    Hide Video Description: Скриване описанието на видеото\n    Hide Comments: Скриване на коментари\n    Hide Sharing Actions: Скриване на действията за споделяне\n    Hide Videos on Watch: 'Скриване на видеата при гледане'\n    Hide Live Streams: Скриване на предавания на живо\n    Hide Chapters: Скриване на главите\n    Hide Upcoming Premieres: Скриване на предстоящите премиери\n    Hide Channels: Скриване видеата от каналите\n    Hide Channels Placeholder: Идентификатор на канала\n    Display Titles Without Excessive Capitalisation: Показване на заглавията без излишни главни букви и препинателни знаци\n    Hide Featured Channels: Скриване на препоръчаните канали\n    Hide Channel Playlists: Скриване на раздел \"Плейлисти\"\n    Hide Channel Shorts: Скриване на раздел \"Кратки видеа\"\n    Sections:\n      Channel Page: Страница на канала\n      Side Bar: Странична лента\n      Watch Page: Страница за гледане\n      General: Общи\n      Subscriptions Page: Страница с абонаменти\n    Hide Channel Releases: Скриване на раздел \"Издания\"\n    Hide Subscriptions Videos: Скриване на видеата в абонаментите\n    Hide Subscriptions Shorts: Скриване на кратките видеа в абонаментите\n    Hide Subscriptions Live: Скриване на абонаментите на живо\n    Hide Channel Podcasts: Скриване на раздел \"Подкасти\"\n    Hide Profile Pictures in Comments: Скриване на профилните снимки в коментарите\n    Hide Channels Disabled Message: Някои канали бяха блокирани с чрез идентификатор и не бяха обработени. Функцията е блокирана, докато тези идентификатори се актуализират\n    Hide Channels API Error: Грешка при извличането на потребител с предоставения идентификатор. Моля, проверете отново дали идентификаторът е правилен.\n    Hide Channels Invalid: Предоставеният идентификатор на канала е невалиден\n    Hide Channels Already Exists: Идентификаторът на канала вече съществува\n    Hide Videos, Playlists and Channels Containing Text: Скриване на видеа и плейлисти, съдържащи текст\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Дума, част от дума или фраза\n    Hide Channel Home: Скриване на раздел \"Начало\"\n    Show Added Items: Показване на добавените елементи\n    Hide Channel Courses: Скриване на раздел \"Курсове\"\n    Hide Channel Posts: Скриване на раздел \"Публикации\"\n    Hide Subscriptions Posts: Скриване на публикациите в абонаментите\n  The app needs to restart for changes to take effect. Restart and apply change?: Приложението трябва да се рестартира за да се приложат промените. Рестартиране?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Грешка при получаване на информация за мрежата. Правилно ли е конфигуриран вашият прокси сървър?\n    City: Град\n    Region: Регион\n    Country: Държава\n    Ip: Ip\n    Your Info: Вашата информация\n    Test Proxy: Тестване на прокси\n    Clicking on Test Proxy will send a request to: Щракването върху \"Тестване на прокси\" ще изпрати заявка до\n    Proxy Port Number: Порт\n    Proxy Host: Хост\n    Proxy Protocol: Протокол\n    Enable Tor / Proxy: Активиране на Tor / Proxy\n    Proxy Settings: Прокси\n    Proxy Warning: FreeTube не разполага с вграден прокси сървър, но може да се свърже с външен, например такъв, който работи на вашата машина, като Tor или SOCKS5 прокси сървър, предоставян от някои VPN услуги. Ако е активирано, уверете се, че прокси сървърът/Tor е конфигуриран правилно, тъй като FreeTube няма да може да извлича данни.\n    Proxy Username: Потребителско име\n    Proxy Password: Парола\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Известие при пропускане на спонсориран сегмент\n    Enable SponsorBlock: Активиране на SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API адрес (по подразбиране е https://sponsor.ajay.app)\n    Skip Options:\n      Skip Option: Опция за пропускане\n      Auto Skip: Автоматично пропускане\n      Show In Seek Bar: Показване в лентата за търсене\n      Prompt To Skip: Подкана за пропускане\n      Do Nothing: Не правете нищо\n    Category Color: Категория Цвят\n    UseDeArrowTitles: Използване на DeArrow за заглавия на видео\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow API адрес за генератор на миниатюри (по подразбиране е https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Използване на DeArrow за миниатюри\n  External Player Settings:\n    Custom External Player Arguments: Персонализирани аргументи за външен плейър\n    Custom External Player Executable: Персонализирано изпълнение на външен плейър\n    Ignore Unsupported Action Warnings: Игнориране на предупрежденията за неподдържани действия\n    External Player: Външен плейър\n    External Player Settings: Външен плейър\n    Players:\n      None:\n        Name: Няма\n    Ignore Default Arguments: Игнориране на аргументите по подразбиране\n  Parental Control Settings:\n    Parental Control Settings: Родителски контрол\n    Hide Unsubscribe Button: Скриване на бутона за отписване\n    Show Family Friendly Only: Показване само за семейства\n    Hide Search Bar: Скриване на лентата за търсене\n    Hide Uploader on Watch page: Скриване името на канала от страницата за гледане\n  Experimental Settings:\n    Experimental Settings: Експериментални\n    Replace HTTP Cache: Замяна на HTTP кеша\n    Warning: Тези настройки са експериментални и може да причинят сривове, докато са разрешени. Силно се препоръчва създаването на резервни копия. Използвайте на свой риск!\n  Password Settings:\n    Password Settings: Парола\n    Set Password To Prevent Access: Задаване на парола, за ограничаване на достъпа до настройките\n    Set Password: Задаване на парола\n    Remove Password: Премахване на паролата\n  Password Dialog:\n    Enter Password To Unlock: Въведете парола за отключване на настройките\n    Password: Парола\n  Sort Settings Sections (A-Z): Подреждане на секциите на настройките (А-Я)\n  Return to Settings Menu: Връщане към менюто с настройки\nAbout:\n  #On About page\n  About: 'Относно'\n  #& About\n  Donate: Дарение\n  these people and projects: тези хора и проекти\n  Translate: Превод\n  room rules: Правилата за общуване\n  Chat on Matrix: Чат в Matrix\n  Mastodon: Mastodon\n  Email: Електронна поща\n  Blog: Блог\n  Website: Уебсайт\n  Please check for duplicates before posting: Моля, проверете за дубликати преди публикуване\n  GitHub issues: GitHub проблеми\n  Report a problem: Съобщаване за проблем\n  FAQ: ЧЗВ\n  FreeTube Wiki: FreeTube Wiki\n  Help: Помощ\n  GitHub releases: GitHub издания\n  Downloads / Changelog: Изтегляния / Дневник с промени\n  Source code: Програмен код\n  Beta: Бета\n  Credits: Заслуги\n  Discussions: Дискусии\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Лицензирано под {licenseLink}\n  Please read the {roomRulesLink}: Моля, прочетете {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube е възможен, благодарение на {creditsPageLink}\nProfile:\n  Profile Select: 'Избор на профил'\n  All Channels: 'Всички канали'\n  Profile Manager: 'Управление на профили'\n  Create New Profile: 'Създаване на нов профил'\n  Edit Profile: 'Редактиране на профил'\n  Color Picker: 'Избор на цвят'\n  Custom Color: 'Потребителски цвят'\n  Profile Preview: 'Преглед на профила'\n  Create Profile: 'Създаване на профил'\n  Update Profile: 'Актуализиране на профила'\n  Make Default Profile: 'Задаване профил по подразбиране'\n  Delete Profile: 'Изтриване на профила'\n  Are you sure you want to delete this profile?: 'Сигурни ли сте, че искате да изтриете профила?'\n  All subscriptions will also be deleted.: 'Всички абонаменти също ще бъдат изтрити.'\n  Your profile name cannot be empty: 'Името на профила не може да е празно'\n  Profile has been created: 'Профилът беше създаден'\n  Profile has been updated: 'Профилът беше актуализиран'\n  Your default profile has been set to {profile}: 'Вашият профил по подразбиране беше указан да е {profile}'\n  Removed {profile} from your profiles: '{profile} е премахнат от вашите профили'\n  Your default profile has been changed to your primary profile: 'Профилът по подразбиране е променен на вашия първоначален профил'\n  '{profile} is now the active profile': 'Активният профил сега е {profile}'\n  Subscription List: 'Списък с абонаменти'\n  Other Channels: 'Други канали'\n  '{number} selected': '{number} избран(и)'\n  Select All: 'Избиране на всички'\n  Select None: 'Без избиране'\n  Delete Selected: 'Изтриване на избраните'\n  Add Selected To Profile: 'Добавяне на избраното към профила'\n  No channel(s) have been selected: 'Няма избрани канали'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Това е основният ви профил. Сигурни ли сте, че искате да изтриете избраните канали? Същите канали ще бъдат изтрити във всички профили, в които бъдат намерени.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Сигурни ли сте, че искате да изтриете избраните канали? Така каналът няма да бъде изтрит от другите профили.'\n#On Channel Page\n  Profile Filter: Профилен филтър\n  Profile Settings: Профил\n  Toggle Profile List: Превключване на списъка с профили\n  Profile Name: Име на профила\n  Open Profile Dropdown: Отваряне на падащото меню на профила\n  Close Profile Dropdown: Затваряне на падащото меню на профила\n  Edit Profile Name: Редактиране на името на профила\n  Create Profile Name: Създаване на име на профил\nChannel:\n  Subscribe: 'Абониране'\n  Unsubscribe: 'Отписване'\n  Channel has been removed from your subscriptions: 'Каналът беше премахнат от вашите абонаменти'\n  Removed subscription from {count} other channel(s): 'Премахнат абонамент от {count} друг(и) канал(и)'\n  Added channel to your subscriptions: 'Каналът е добавен към вашите абонаменти'\n  Search Channel: 'Търсене в канала'\n  Your search results have returned 0 results: 'Търсенето върна 0 резултата'\n  Videos:\n    Videos: 'Видеа'\n    This channel does not currently have any videos: 'В този канал по настоящем няма видеа'\n    Sort Types:\n      Newest: 'Най-нови'\n      Oldest: 'Най-стари'\n      Most Popular: 'Най-популярни'\n  Playlists:\n    Playlists: 'Плейлисти'\n    This channel does not currently have any playlists: 'В този канал по настоящем няма плейлисти'\n    Sort Types:\n      Last Video Added: 'Последно добавени'\n      Newest: 'Най-нови'\n      Oldest: 'Най-стари'\n  About:\n    About: 'Относно'\n    Channel Description: 'Описание на канала'\n    Featured Channels: 'Препоръчани канали'\n    Tags:\n      Tags: Етикети\n      Search for: Търсене за „{tag}“\n    Details: Детайли\n    Joined: Присъединен на\n    Location: Местоположение\n  Posts:\n    This channel currently does not have any posts: В момента този канал няма никакви публикации\n    votes: '{votes} гласа'\n    Reveal Answers: Разкриване на отговорите\n    Hide Answers: Скриване на отговорите\n    Video hidden by FreeTube: Видео, скрито от FreeTube\n    Viewing Posts Only Supported By Invidious: Преглеждането на публикации се поддържа само от Invidious. Отидете в раздела на общността на канала, за да видите съдържанието там без Invidious.\n    View Full Post: Преглед на цялата публикация\n  This channel does not exist: Каналът не съществува\n  This channel does not allow searching: Каналът не позволява търсене\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Каналът е възрастово ограничен и в момента не може да бъде гледан във FreeTube.\n  Channel Tabs: Раздели на каналите\n  Live:\n    Live: На живо\n    This channel does not currently have any live streams: В момента този канал няма никакви потоци на живо\n  Shorts:\n    This channel does not currently have any shorts: В момента този канал няма никакви кратки видеа\n  Podcasts:\n    Podcasts: Подкасти\n    This channel does not currently have any podcasts: В момента този канал няма никакви подкасти\n  Releases:\n    Releases: Издания\n    This channel does not currently have any releases: В момента този канал няма никакви издания\n  Home:\n    Home: Начало\n    View Playlist: Преглед на плейлиста\n  Courses:\n    Courses: Курсове\n    This channel does not currently have any courses: В момента този канал няма никакви курсове\nVideo:\n  Mark As Watched: 'Отбелязване като гледано'\n  Remove From History: 'Премахване от историята'\n  Video has been marked as watched: 'Видеото беше отбелязано като гледано'\n  Video has been removed from your history: 'Видеото беше премахнато от историята'\n  Open in YouTube: 'Отваряне в YouTube'\n  Copy YouTube Link: 'Копиране на връзка за YouTube'\n  Open YouTube Embedded Player: 'Отваряне на вградения YouTube плейър'\n  Copy YouTube Embedded Player Link: 'Копиране на връзка за вградения YouTube плейър'\n  Open in Invidious: 'Отваряне в Invidious'\n  Copy Invidious Link: 'Копиране на връзка за Invidious'\n  Views: 'Показвания'\n  Loop Playlist: 'Повтаряне на плейлиста'\n  Shuffle Playlist: 'Разбъркване на плейлиста'\n  Reverse Playlist: 'Обръщане на плейлиста'\n  Previous: 'Пускане пак'\n  Next: 'Следващ'\n  Watched: 'Гледано'\n  Autoplay: 'Автоматично пускане'\n  Starting soon, please refresh the page to check again: 'Започва скоро, моля опреснете страницата за актуализация'\n  # As in a Live Video\n  Live: 'На живо'\n  Live Now: 'На живо сега'\n  Live Chat: 'Чат на живо'\n  Enable Live Chat: 'Активиране чата на живо'\n  Live Chat is currently not supported in this build.: 'Чатът на живо не се поддръжа в тази версия.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Чатът на живо е активиран. Съобщенията ще се появят тук когато бъдат изпратени.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Чатът на живо не се поддържа от интерфейса на Invidious. Изисква се директна връзка с YouTube.'\n  Published:\n    In less than a minute: След по-малко от минута\n  Published on: 'Публикувано на'\n#& Videos\n  Copy Invidious Channel Link: Копиране на връзка за канала в Invidious\n  Open Channel in Invidious: Отваряне на канала в Invidious\n  Copy YouTube Channel Link: Копиране на връзка за канала в YouTube\n  Open Channel in YouTube: Отваряне на канала в YouTube\n  Started streaming on: Начало на предаването\n  Streamed on: На живо на\n  Video has been removed from your saved list: Видеото е премахнато от вашия списък със запазени\n  Video has been saved: Видеото е запазено\n  Save Video: Запазване на видео\n  Sponsor Block category:\n    interaction: Взаимодействие\n    self-promotion: Самореклама\n    outro: Епилог\n    intro: Въведение\n    sponsor: Спонсор\n    music offtopic: Музика извън темата\n    recap: Резюме\n    filler: Запълване\n  External Player:\n    Unsupported Actions:\n      looping playlists: повтаряне на плейлисти\n      shuffling playlists: разбъркване на плейлисти\n      reversing playlists: обръщане на плейлист\n      opening specific video in a playlist (falling back to opening the video): отваряне на определено видео в плейлист (връщане към отваряне на видеото)\n      opening playlists: отваряне на плейлист\n      setting a playback rate: задаване на скорост за възпроизвеждане\n      starting video at offset: стартиране на видео при отместване\n    UnsupportedActionTemplate: '{externalPlayer} не поддържа: {action}'\n    OpeningTemplate: Отваряне на {videoOrPlaylist} във {externalPlayer}...\n    playlist: плейлист\n    video: видео\n    OpenInTemplate: Отваряне във {externalPlayer}\n  Premieres: Премиерa\n  Show Super Chat Comment: Показване на Super Chat коментар\n  Scroll to Bottom: Превъртане в долната част\n  Upcoming: Предстои\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Чатът на живо не е наличен за този поток. Възможно е да е бил деактивиран от качващия.\n  Unhide Channel: Показване на канала\n  Hide Channel: Скриване на канала\n  More Options: Още опции\n  Player:\n    Audio Tracks: Аудио пътеки\n    Exit Full Window: Изход от цял прозорец\n    Take Screenshot: Екранна снимка\n    Show Stats: Показване на статистика\n    Exit Theatre Mode: Изход от широкоекранния режим\n    Stats:\n      Stats: Статистика\n      Video ID: 'Видео ID: {videoId}'\n      Media Formats: 'Медиен формат: {formats}'\n      Volume: 'Сила на звука: {volumePercentage}%'\n      Bandwidth: 'Честотна лента: {bandwidth} kbps'\n      Buffered: 'Буферирани: {bufferedPercentage}%'\n      CodecAudio: 'Кодек: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Кодеци: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Кодеци: {videoCodec} / {audioCodec}'\n      Resolution: 'Разделителна способност: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Размери на плейъра: {width}x{height}'\n      Bitrate: 'Скорост на предаване: {bitrate} kbps'\n      Dropped Frames / Total Frames: 'Изпуснати кадри: {droppedFrames} / Общо кадри: {totalFrames}'\n    You appear to be offline: Изглежда, че сте офлайн.\n    Playback will resume automatically when your connection comes back: Възпроизвеждането ще се възобнови автоматично, когато връзката ви се възстанови.\n    Skipped segment: Пропуснат сегмент {segmentCategory}\n    TranslatedCaptionTemplate: '{language} (преведено от \"{originalLanguage}\")'\n    Theatre Mode: Широкоекранен режим\n    Full Window: Цял прозорец\n    Hide Stats: Скриване на статистиката\n    Autoplay is off: Автоматичното пускане е спряно\n    Autoplay is on: Автоматичното пускане е включено\n  IP block: YouTube е блокирал вашия IP адрес за гледане на видеа. Опитайте да преминете към друга VPN услуга или прокси сървър.\n  AgeRestricted: Видеата с възрастови ограничения не могат да се гледат с FreeTube, тъй като изискват вход в Google и използване на проверен по възраст акаунт в YouTube.\n  Unlisted: Непосочен в списъка\n  MembersOnly: Видеата, предназначени само за членове, не могат да се гледат с FreeTube, тъй като изискват вход в Google и платено членство в канала на качващия.\n  DeArrow:\n    Show Original Details: Показване на оригинални данни\n    Show Modified Details: Показване на променени данни\n  DRMProtected: Видеата, защитени с DRM не могат да се възпроизвеждат във FreeTube, тъй като изискват собствени компоненти със затворен код. Ако искате да гледате това видео, моля, използвайте официалния уебсайт на YouTube в уеб браузър поддържащ DRM.\n#& Playlists\n  Watched Progress Saved: Напредъка на гледането е запазен\n  Save Watched Progress: Запазване на напредъка\n  Popout Live Chat: Изскачащ чат\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Оставащо време за реклама преди видеото: {remindingTimeSeconds} сек'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Оставащо време за отлагане на SABR: {remindingTimeSeconds} сек'\nPlaylist:\n  #& About\n  View Full Playlist: 'Преглед на пълен плейлист'\n  Last Updated On: 'Последна актуализиция на'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Плейлист\n  Sort By:\n    DateAddedNewest: Дата на добавяне (най-нови)\n    DateAddedOldest: Дата на добавяне (най-стари)\n    AuthorAscending: Автор (A-Z)\n    AuthorDescending: Автор (Z-A)\n    VideoTitleAscending: Заглавие (A-Z)\n    Custom: Потребителски\n    VideoTitleDescending: Заглавие (Z-A)\n    VideoDurationAscending: Продължителност (най-кратки)\n    VideoDurationDescending: Продължителност (най-дълги)\n    PublishedNewest: Дата на публикуване (най-нови)\n    PublishedOldest: Дата на публикуване (най-стари)\nChange Format:\n  Change Media Formats: 'Смяна видео формати'\n  Use Dash Formats: 'Използване на DASH формати'\n  Use Legacy Formats: 'Използване на стари формати'\n  Use Audio Formats: 'Използване на аудио формати'\n  Dash formats are not available for this video: 'DASH форматите не са достъпни за това видео'\n  Audio formats are not available for this video: 'Аудио форматите не са достъпни за това видео'\n  Legacy formats are not available for this video: За това видео не са налични наследени формати\nShare:\n  Share Video: 'Споделяне на видео'\n  Share Playlist: 'Споделяне на плейлиста'\n  Include Timestamp: 'Включване на текущото време'\n  Copy Link: 'Копиране на връзка'\n  Open Link: 'Отваряне на връзка'\n  Copy Embed: 'Копиране за вграждане'\n  Open Embed: 'Отваряне на връзка за вграждане'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious адресът е копиран'\n  Invidious Embed URL copied to clipboard: 'Invidious адресът за вграждане е копиран'\n  YouTube URL copied to clipboard: 'YouTube адресът е копиран'\n  YouTube Embed URL copied to clipboard: 'YouTube адресът за вграждане е копиран'\n  YouTube Channel URL copied to clipboard: YouTube адресът на канала е копиран\n  Invidious Channel URL copied to clipboard: Invidious адресът на канала е копиран\n  Share Channel: Споделяне на канал\n  Share Post: Споделяне на публикация\nMini Player: 'Мини плейър'\nComments:\n  Comments: 'Коментари'\n  Click to View Comments: 'Щракнете, за да видите коментарите'\n  Getting comment replies, please wait: 'Получаване на отговори на коментара, моля изчакайте'\n  There are no more comments for this video: 'Към това видео няма повече коментари'\n  Hide Comments: 'Скриване на коментарите'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Към това видео няма коментари'\n  Load More Comments: 'Зареждане на още коментари'\n  Newest first: Първо най-новите\n  Top comments: Последни коментари\n  Show More Replies: Показване на още отговори\n  Pinned by: Прихванато от\n  Member: Член\n  View {replyCount} replies: Преглед на 1 отговор | Преглед на {replyCount} отговора\n  Hearted: Сърдечно\n  Subscribed: Абониран\n  There are no comments available for this post: За тази публикация няма налични коментари\n  Hide {replyCount} replies: Скриване на 1 отговор | Скриване на {replyCount} отговора\n  View 1 reply from {channelName}: Преглед на 1 отговор от {channelName}\n  View {replyCount} replies from {channelName} and others: Преглед на {replyCount} отговора от {channelName} и други\nUp Next: 'Следващ'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Грешка в локалния интерфейс (щракнете за копиране)'\nInvidious API Error (Click to copy): 'Грешка в Invidious интерфейса (щракнете за копиране)'\nFalling back to Invidious API: 'Връщане към Invidious интерфейса'\nFalling back to Local API: 'Връщане към локалния интерфейс'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Видеото не е достъпно поради липсващи формати. Това може да се дължи на ограничен достъп за страната.'\nLoop is now disabled: 'Повтарянето е изключено'\nLoop is now enabled: 'Повтарянето е включено'\nShuffle is now disabled: 'Разбъркването е изключено'\nShuffle is now enabled: 'Разбъркването е включено'\nThe playlist has been reversed: 'Плейлистата е в обърнат ред'\nPlaying Next Video: 'Пускане на следващото видео'\nPlaying Previous Video: 'Пускане на предишното видео'\nCanceled next video autoplay: 'Следващото видео е отказано'\n'The playlist has ended. Enable loop to continue playing': 'Плейлиста приключи. Включете повторението за да продължи'\n\nYes: 'Да'\nNo: 'Не'\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: FreeTube ще използва RSS вместо метода по подразбиране за получаване на абонаментите. RSS е по-бърз метод и преодолява блокиранията на IP адреса, но не получава някои съпътстващи данни, като продължителност на видеото, дали е на живо или публикации\n    Fetch Automatically: FreeTube автоматично ще извлича абонаментите при стартиране и при отваряне на нов прозорец.\n  Player Settings:\n    Default Video Format: Настройка на използваните формати. DASH форматите могат да показват видеа с по-високо качество. Старите формати са ограничени до макс. 360р, но пък генерират по-малък трафик. Аудио форматите предават само звук.\n    Proxy Videos Through Invidious: Ще се свърже с Invidious, за да изтегли видеото, вместо да прави дирекна връзка с YouTube.\n    Scroll Playback Rate Over Video Player: Докато курсорът е върху видеото, натиснете и задръжте клавиша Control (Command Key за Mac) и превъртете колелцето на мишката напред или назад, за да контролирате скоростта на възпроизвеждане. Натиснете и задръжте клавиша Control (Command Key за Mac) и щракнете с левия бутон на мишката, за да се върнете бързо към стандартната скорост на възпроизвеждане (1x, освен ако не е променена в настройките).\n    Skip by Scrolling Over Video Player: Използване колелцето на мишката за превъртане на видео в стил MPV.\n  General Settings:\n    Region for Trending: Регионът на набиращите популярност дава възможност да се избере страната, за която това се отнася.\n    Invidious Instance: Сървър на Invidious, към който FreeTube ще се свързва.\n    Thumbnail Preference: Всички миниатюри във FreeTube ще бъдат подменени с кадър от видеото, замъглени или скрити, вместо тези по подразбиране.\n    Fallback to Non-Preferred Backend on Failure: Когато избраният интерфейс срещне проблем, FreeTube ще опита да премине автоматично към друг метод, ако има избран такъв.\n    Preferred API Backend: Избиране на начина, по който FreeTube получава данните. Локалният интерфейс има вградено извличане. Invidious интерфейсът изисква Invidious сървър, към който да се свърже.\n    External Link Handling: \"Избор на поведението по подразбиране, когато щракнете върху връзка, която не може да бъде отворена във FreeTube.\\nПо подразбиране FreeTube ще отвори връзката в браузъра по подразбиране.\\n\"\n    Open Deep Links In New Window: URL адресите, преминаващи през FreeTube, например чрез разширения на браузъра или аргументи от командния ред, се отварят в нов прозорец.\n  External Player Settings:\n    Custom External Player Arguments: Всички персонализирани аргументи от командния ред, които искате да бъдат предадени на външния плейър.\n    Ignore Warnings: Премахване на предупрежденията, когато текущият външен плейър не поддържа текущото действие (напр. обръщане на плейлисти и др.).\n    Custom External Player Executable: По подразбиране FreeTube предполага, че избраният външен плейър може да бъде намерен чрез променливата на средата 'PATH'. Ако е необходимо, тук може да се зададе потребителски път.\n    External Player: При избора на външен плейър, върху миниатюрата ще се покаже икона за отваряне на видеото (плейлиста, ако се поддържа) във външния плейър. Внимание, настройките на Invidious не влияят на външните плейъри.\n    DefaultCustomArgumentsTemplate: \"(По подразбиране: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Без изпращане на аргументи по подразбиране към външния плейър, освен URL адреса на видеото (напр. скорост на възпроизвеждане, URL адрес на плейлиста за възпроизвеждане и т.н.). Потребителските аргументи все пак ще бъдат изпратени.\n  Experimental Settings:\n    Replace HTTP Cache: Деактивира HTTP кеша на Electron върху носителя и активира персонализиран кеш за изображения в паметта. Ще доведе до увеличаване на използването на RAM паметта.\n  Distraction Free Settings:\n    Hide Channels: Въведете идентификатор на канал, за да скриете всички видеа, плейлисти и самия канал от показване в търсенето, тенденциите, най-популярните и препоръчаните. Въведеният идентификатор трябва да съвпада напълно и е чувствителен към главни и малки букви.\n    Hide Subscriptions Live: Тази настройка се отменя от настройката за цялото приложение \"{appWideSetting}\" в секция \"{subsection}\" на \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Въведете дума, част от дума или фраза (без значение от главни и малки букви), за да скриете всички видеа и плейлисти, чиито оригинални заглавия ги съдържат в целия FreeTube, с изключение само на Историята, Вашите плейлисти и видеата в плейлистите.\n    Hide Videos on Watch: Скрива гледаните видеа от разделите \"Видеа\", \"Кратки видеа\" и \"На живо\" на страниците \"Абонамент\" и \"Канал\". Това не засяга раздел \"Начало\" на страниците на канала\n  SponsorBlock Settings:\n    UseDeArrowTitles: Заменя заглавията на видеата с подадени от потребителите заглавия от DeArrow.\n    UseDeArrowThumbnails: Заменя миниатюрите на видеата с миниатюри от DeArrow.\nMore: Още\nPlaying Next Video Interval: Пускане на следващото видео веднага. Щракнете за отказ. | Пускане на следващото видео след {nextVideoInterval} секунда. Щракнете за отказ. | Пускане на следващото видео след {nextVideoInterval} секунди. Щракнете за отказ.\nUnknown YouTube url type, cannot be opened in app: Неизвестен тип URL адрес за YouTube, не може да се отвори в приложението\nOpen New Window: Отваряне на нов прозорец\nDefault Invidious instance has been cleared: Сървъра по подразбиране за Invidious е изчистен\nDefault Invidious instance has been set to {instance}: Сървъра по подразбиране за Invidious е зададен на {instance}\nExternal link opening has been disabled in the general settings: Отварянето на външни връзки е изключено в общите настройки\nSearch Bar:\n  Clear Input: Изчистване на въведеното\n  Remove: Премахване\nAre you sure you want to open this link?: Сигурни ли сте, че искате да отворите тази връзка?\nScreenshot Error: Снимката на екрана е неуспешна. {error}\nScreenshot Success: Запазена снимка на екрана\nNew Window: Нов прозорец\nChannels:\n  Count: Намерени са {number} канала.\n  Unsubscribe Prompt: Сигурни ли сте, че искате да се отпишете от \"{channelName}\"?\n  Search bar placeholder: Търсене на канали\n  Channels: Канали\n  Title: Списък с канали\n  Empty: Списъкът с канали в момента е празен.\nClipboard:\n  Cannot access clipboard without a secure connection: Не може да се получи достъп до клипборда без защитена връзка\n  Copy failed: Неуспешно копиране в клипборда\nChapters:\n  Chapters: Глави\n  Key Moments: Основни моменти\nPreferences: Предпочитания\nOk: Добре\nHashtag:\n  Hashtag: Хаштаг\n  This hashtag does not currently have any videos: В момента този хаштаг няма видеа\nChannel Hidden: '{channel} е добавен към филтъра за канали'\nChannel Unhidden: '{channel} е премахнат от филтъра за канали'\nGo to page: Отиване на {page}\nTag already exists: Етикетът \"{tagName}\" вече съществува\nTrimmed input must be at least N characters long: Орязаният вход трябва да бъде дълъг поне 1 символ | Орязаният вход трябва да бъде дълъг поне {length} символа\nAge Restricted:\n  This channel is age restricted: Този канал е с възрастово ограничение\n  This video is age restricted: Това видео е с възрастово ограничение\nClose Banner: Затваряне на банер\nSearch character limit: Заявката за търсене е над лимита от {searchCharacterLimit} символа\nFeed:\n  Feed Last Updated: 'Последна актуализация на емисията {feedName}: {date}'\n  Refresh Feed: Обновяване на {subscriptionName}\nYes, Delete: Да, изтрий\nYes, Restart: Да, рестартирай\nYes, Open Link: Да, отваряне на връзката\nCancel: Отказ\nMoments Ago: току що\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Субтитри\n    Closed Captions: Затворени субтитри\n    VR180: VR180\n    3D: 3D\n    8K: 8K\n    360 Video: 360°\n    New: Нов\nDescription:\n  Collapse Description: По-малко\n  Expand Description: '...още'\nKeys:\n  arrowleft: Стрелка наляво\n  arrowright: Стрелка надясно\n  arrowup: Стрелка нагоре\n  alt: Alt\n  arrowdown: Стрелка надолу\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Плюс\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: Щракнете с десния бутон на мишката или задръжте, за да видите историята\nAutoplay Interruption Timer: Автоматичното възпроизвеждане е отменено поради {autoplayInterruptionIntervalHours} час(а) неактивност\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Бързи клавиши\n  Sections:\n    Video:\n      Playback: 'Видео: Възпроизвеждане'\n      General: 'Видео: Общи'\n    App:\n      Situational: 'Приложение: Ситуационно'\n      General: 'Приложение: Общи'\n  Show Keyboard Shortcuts: Показване на бързи клавиши\n  New Window: Създаване на нов прозорец\n  History Forward: Отиване с една страница напред\n  Navigate to Settings: Отиване на страницата с настройки\n  Navigate to History: Отиване на страницата с история\n  Refresh: Обновяване на емисията с най-новото съдържание\n  Focus Secondary Search: Фокусиране върху допълнителната лента за търсене (ако има такава)\n  Captions: Вкл/Изкл на надписите\n  Stats: Показване на статистика за видеото\n  Fullscreen: Превключване на цял екран\n  Picture in Picture: Превключване на режим \"Картина в картината\"\n  Large Rewind: Превъртане с 10 секунди назад / Превъртане на видеото въз основа на текущата скорост на възпроизвеждане\n  Play: Възпроизвеждане/Пауза\n  Decrease Video Speed: Намаляване скоростта на видеото въз основа на интервала за скорост на възпроизвеждане\n  Mute: Вкл/Изкл на звука\n  Increase Video Speed: Увеличаване скоростта на видеото въз основа на интервала за скорост на възпроизвеждане\n  Full Window: Превключване на цял прозорец\n  Theatre Mode: Превключване на широкоекранен режим\n  Take Screenshot: Снимка на екрана\n  Minimize Window: Минимизиране на прозореца\n  Close Window: Затваряне на прозореца\n  Toggle Developer Tools: Превключване на инструментите за разработчици\n  Reset Zoom: Нулиране на мащабирането\n  Zoom In: Увеличаване на мащаба\n  Zoom Out: Намаляване на мащаба\n  Focus Search: Фокусиране върху лентата за търсене\n  Last Frame: Предишен кадър (докато е на пауза)\n  Next Frame: Следващ кадър (докато е на пауза)\n  Volume Up: Увеличаване на звука\n  Volume Down: Намаляване на звука\n  Small Rewind: Превъртане назад с X секунди въз основа на интервала и текущата скорост на възпроизвеждане на видео\n  Last Chapter: Последна глава\n  Next Chapter: Следваща глава\n  Skip by Tenths: Прескачане на видео по проценти (3 прескачания до 30% от продължителността)\n  History Backward: Връщане с една страница назад\n  Large Fast Forward: Превъртане с 10 секунди напред / Бързо превъртане на видеото въз основа на текущата скорост на възпроизвеждане\n  Search in New Window: Търсене в нов прозорец\n  Small Fast Forward: Превъртане напред с X секунди въз основа на интервала и текущата скорост на възпроизвеждане на видео\n  Home: Преминаване към началото на видеото\n  End: Преминаване към края на видеото\n  Skip to Next Video: Преминаване към следващото видео в плейлиста или към следващото препоръчано\n  Skip to Previous Video: Преминаване към предходното видео в плейлиста\nshortcutLabelSeparator: '{''|''}'\nCompact side navigation: Компактна странична навигация\nExpand side navigation: Разширена странична навигация\n"
  },
  {
    "path": "static/locales/bn.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'বাংলা'\n\n# Webkit Menu Bar\nFile: 'ফাইল'\nQuit: 'প্রস্থান'\nEdit: 'সম্পাদনা'\nUndo: 'পূর্বাবস্থায় ফিরো'\nRedo: 'আবার করো'\nCut: 'কাটো'\nCopy: 'অনুলিপি'\nPaste: 'লেপন'\nDelete: 'মুছো'\nSelect all: 'সব নির্বাচন করো'\nToggle Developer Tools: 'ডেভেলপার যন্ত্র টগল করো'\nActual size: 'প্রকৃত আকার'\nZoom in: 'সম্প্রসারিত করো (জুম)'\nZoom out: 'সংকুচিত করো(জুম)'\nToggle fullscreen: 'পূর্ণ-স্ক্রিন'\nWindow: 'উইন্ডো'\nMinimize: 'ক্ষুদ্রকরণ'\nClose: 'বন্ধ'\nBack: 'পিছনে'\nForward: 'সামনে'\n\nVersion {versionNumber} is now available!  Click for more details: 'সংস্করণ {versionNumber} এসে গেছে!  আরো জানতে টিপ দাও'\nDownload From Site: 'সাইট থেকে ডাউনলোড করো'\nA new blog is now available, {blogTitle}. Click to view more: 'নতুন ব্লগ আছে, {blogTitle}. আরো দেখতে টিপ দাও'\n\n# Search Bar\nSearch / Go to URL: 'অনুসন্ধান / ইউআরএলে যাও'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'অনুসন্ধান ছাঁকনি'\n  Sort By:\n    Most Relevant: 'সবচেয়ে প্রাসঙ্গিক'\n    Rating: 'তারকা'\n    Upload Date: 'ছাপানোর তারিখ'\n    View Count: 'দৃশ্য সংখ্যা'\n  Time:\n    Time: 'সময়'\n    Any Time: 'যেকোনো সময়'\n    Last Hour: 'শেষ ঘণ্টা'\n    Today: 'আজকে'\n    This Week: 'এই সপ্তাহে'\n    This Month: 'এই মাসে'\n    This Year: 'এই বছর'\n  Type:\n    Type: 'ধরণ'\n    All Types: 'সব ধরণ'\n    Videos: 'ভিডিও'\n    Channels: 'চ্যানেল'\n    #& Playlists\n    Movies: চলচিত্র\n  Duration:\n    Duration: 'সময়কাল'\n    All Durations: 'সকল দৈর্ঘ্যের'\n    Short (< 4 minutes): 'ছোট (<৪ মিনিট)'\n    Long (> 20 minutes): 'লম্বা (> ২০ মিনিট)'\n  # On Search Page\n    Medium (4 - 20 minutes): মধ্যম (৪ - ২০ মিনিট)\n  Search Results: 'অনুসন্ধান ফলাফল'\n  Fetching results. Please wait: 'ফলাফল আনা হচ্ছে, একটু অপেক্ষা করো'\n  Fetch more results: 'আরো ফলাফল আনো'\n# Sidebar\n  There are no more results for this search: এই অনুসন্ধানের আর কোনো ফলাফল নেই\n  Features:\n    Live: সরাসরি\n    Location: স্থান\n    360 Video: ৩৬০ ভিডিও\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'সদস্যতা'\n  Error Channels: ত্রুটিপূর্ণ চ্যানেল\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': আপনার সাবস্ক্রিপশন লিস্ট খালি, দেখতে সাবস্ক্রিপশন করুন\n  Load More Posts: অতিরিক্ত পোস্ট লোড করুন\n  Empty Channels: আপনি যেসকল চ্যানেল সাবস্ক্রাইব করেছেন তাদের কোন ভিডিও নেই ।\n  Subscriptions Tabs: সাবস্ক্রিপশন ট্যাব\n  Empty Posts: আপনার সাবস্ক্রাইব কৃত চ্যানেলে কোন পোস্ট নেই ।\n  All Subscription Tabs Hidden: সকল সাবস্ক্রিপশন ট্যা গোপন করা হয়েছে ।এখানে কনটেন্ট দেখতে কিছু ট্যাব আনহাইড করুন\"{subsection}\"এর \"{settingsSection}\"।\n  Load More Videos: অতিরিক্ত ভিডিও লোড করুন\n  Disabled Automatic Fetching: আপনি সাবস্ক্রিপশন পেচ বন্ধ করে রেখেছেন। সাবস্ক্রিপশন রিফ্রেশ করুন দেখার জন্য।\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: এই প্রোফাইলের অনেক সাবস্ক্রাইবার রয়েছে। জোরপূর্বক লিমিট এড়ানোর চেষ্টা করা হচ্ছে\nTrending:\n  Trending: 'চলছে'\n  Gaming: গেমিং\n  Trending Tabs: চলমান ভিডিও ট্যাব\nHistory:\n  # On History Page\n  History: 'ইতিহাস'\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\n  Player Settings: {}\nAbout:\n  #On About page\n  Email: 'ই-মেইল'\nChannel:\n  Videos:\n    Videos: ভিডিও\n  Playlists: {}\nVideo: {}\nTooltips: {}\nOpen New Window: নতুন জানালা খুলো\nNew Window: নতুন জানালা\nSearch Bar:\n  Clear Input: ইনপুট পরিষ্কার করো\n  Remove: মুছুন\nGlobal:\n  Videos: ভিডিও\n  Shorts: খাটো\n  Live: লাইভ\n  Sort By: 'সাজানোর পদ্ধতি'\n  Counts:\n    Video Count: ১ ভিডিও |{count}ভিডিও\n    Subscriber Count: ১ সাবস্ক্রাইবার |{count}সাবস্ক্রাইবার\n    View Count: ১ দেখা হয়েছে |{count}দর্শন সংখ্যা\n    Watching Count: ১ দেখছি |{count}দেখছেন\n    Channel Count: ১ চ্যানেল |{count}চ্যানেল সমূহ\n    Like Count: ১টি পছন্দ | {count} পছন্দ করা হয়েছে\n    Comment Count: ১টি মন্তব্য | {count} মন্তব্য করা হয়েছে\n  Posts: পোস্ট\nExternal link opening has been disabled in the general settings: সাধারণ পছন্দসমূহে বহিঃসংযোগ খোলা নিষ্ক্রিয় রাখা হয়েছে\nAre you sure you want to open this link?: তুমি কি এই সংযোগটি খোলার ব্যাপারে নিশ্চিত?\nPreferences: পছন্দসমূহ\nMost Popular: অতিপরিচিত\nChannels:\n  Search bar placeholder: চ্যানেল খুঁজুন\n  Unsubscribe Prompt: আপনি নিশ্চিত আপনি \"{channelName}\"আনসাবস্ক্রাইব করতে চান ?\n  Channels: চ্যানেলসমূহ\n  Title: চ্যানেল সুচি\n  Empty: আপনার চ্যানেল সুচি এখন খালি ।\n  Count: '{number}চ্যানেল পাওয়া গিয়েছে ।'\nPlaylists: প্লে লিস্ট\nUser Playlists:\n  Your Playlists: আপনার প্লেলিস্ট\n  Search bar placeholder: নির্বাচিত তালিকাতে খুঁজুন\n  This playlist currently has no videos.: এই নির্বাচিত তালিকাতে কোন ভিডিও নেই।\n  Create New Playlist: নতুন একটি নির্বাচিত তালিকা তৈরি করুন\n  Add to Playlist: নির্বাচিত তালিকাতে যুক্ত করুন\n  Move Video Up: ভিডিও উপরে নিন\n  Move Video Down: ভিডিও নিচে নিন\n  Remove from Playlist: তালিকা থেকে মুছুন\n  Playlist Name: তালিকার নাম\n  Playlist Description: তালিকার বিবরন\n  Save Changes: পরিবর্তন সংরক্ষণ করুন\n  Cancel: বাতিল\n  Edit Playlist Info: নির্বাচিত তালিকার তথ্য পরিবর্তন\n  Empty Search Message: এই চালুতালিকাতে আপনার কাংখিত ভিডিও নেই যেটি আপনি অনুসন্ধান করছেন\n  You have no playlists. Click on the create new playlist button to create a new one.: নির্বাচিত তালিকা নেই। নতুন তালিকা তৈরির জন্য নিউ প্লে-লিস্ট বাটন এ চাপ দিয়ে অগ্রসর হতে পারেন।\n  Delete Playlist: চালুতালিকা মুছুন\n  Sort By:\n    EarliestUpdatedFirst: সবচেয়ে পুরনো হালনাগাদকৃত\n    LatestUpdatedFirst: সম্প্রতি হালনাগদকৃত\n    LatestPlayedFirst: সম্প্রতি চালানো\n    LatestCreatedFirst: সম্প্রতি তৈরি\n    EarliestCreatedFirst: সবচেয়ে পুরনো তৈরি\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: ভিডিওটি উপরে সরানো যাবে না।\n      This video cannot be moved down.: ভিডিওটি নিচে সরানো যাবেনা।\n      Video has been removed: ভিডিওটি মুছে ফেলা হয়েছে\n    Search for Videos: ভিডিও খুঁজুন\n  Add to Favorites: '{playlistName}তে যুক্ত করুন'\n  Remove Duplicate Videos: অভিন্ন ভিডিওগুলি মুছুন\n  Remove Watched Videos: দেখা ভিডিওগুলি মুছুন\n  Remove from Favorites: '{playlistName} থেকে বাদ দিন'\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: আপনি কি নিশ্চিত যে আপনি ১টি অভিন্ন ভিডিও চালুতালিকা হতে মুছতে চান? এটি পূর্বাবস্থায় ফেরানো সম্ভব নয়। | আপনি কি নিশ্চিত যে আপনি {playlistItemCount}টি অভিন্ন ভিডিও চালুতালিকা হতে মুছতে চান? এটি পূর্বাবস্থায় ফেরানো সম্ভব নয়।\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: আপনি কি নিশ্চিত যে আপনি ১টি দেখা ভিডিও চালুতালিকা হতে মুছতে চান? এটি পূর্বাবস্থায় ফেরানো সম্ভব নয়। | আপনি কি নিশ্চিত যে আপনি {playlistItemCount}টি দেখা ভিডিও চালুতালিকা হতে মুছতে চান? এটি পূর্বাবস্থায় ফেরানো সম্ভব নয়।\n  Are you sure you want to delete this playlist? This cannot be undone: আপনি কি নিশ্চিত যে আপনি চালুতালিকাটি মুছতে চান? এটি পূর্বাবস্থায় ফেরানো সম্ভব নয়।\nMore: অতিরিক্ত\nGo to page: পরবর্তী {page}\nSearch character limit: সার্চ কোয়েরি {searchCharacterLimit} অক্ষরের সীমা অতিক্রম করেছে\nClose Banner: ব্যানারটি বন্ধ করুন\nSearch Listing:\n  Label:\n    360 Video: ৩৬০°\n    New: নতুন\n    8K: 8K\n    4K: 4K\nRight-click or hold to see history: ইতিহাস দেখতে রাইট-ক্লিক করুন অথবা ধরে রাখুন\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: ডেভেলপার যন্ত্র টগল করো\n  Zoom In: সম্প্রসারিত করো (জুম)\n  Zoom Out: সংকুচিত করো(জুম)\n  Fullscreen: পূর্ণ-স্ক্রিন\nProfile:\n  Select All: সব নির্বাচন করো\n"
  },
  {
    "path": "static/locales/br.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Brezhoneg'\n\n# Webkit Menu Bar\nFile: 'Restr'\nNew Window: 'Prenestr nevez'\nPreferences: 'Gwellvezioù'\nQuit: 'Kuitaat'\nEdit: 'Kemmañ'\nUndo: 'Dizober'\nRedo: 'Adober'\nCut: 'Troc''hañ'\nCopy: 'Eilañ'\nPaste: 'Pegañ'\nDelete: 'Dilemel'\nSelect all: 'Diuzañ pep tra'\nToggle Developer Tools: 'Enaouiñ/Lazhañ Ostilhoù diorren'\nActual size: 'Ment a-vremañ'\nZoom in: 'Zoum brassat'\nZoom out: 'Zoum bihanaat'\nToggle fullscreen: 'Tremen e skramm leun'\nWindow: 'Prenestr'\nMinimize: 'Izekaat'\nClose: 'Seriñ'\nBack: 'Distreiñ'\nForward: 'War-raok'\nOpen New Window: 'Digeriñ ur prenestr nevez'\nGo to page: 'Mont d''ar bajenn {page}'\nClose Banner: 'Serriñ ar Giton'\n\nVersion {versionNumber} is now available!  Click for more details: 'Stumm {versionNumber} a zo hegerz !  Klikit amañ evit gouzout hiroc''h'\nDownload From Site: 'Pellgargañ diwar al lec''hienn'\nA new blog is now available, {blogTitle}. Click to view more: 'Embannet ez eus bet ur pennad nevez, {blogTitle}. Klikit amañ evit gouzout hiroc''h'\nAre you sure you want to open this link?: 'Ha sur oc''h e faot deoc''h digeriñ al liamm-mañ ?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videoioù'\n  Shorts: 'Videoioù berr (Shorts)'\n  Live: 'War-eeun'\n  Sort By: 'Rummañ dre'\n  Counts:\n    Video Count: '1 video | {count} video'\n    Channel Count: '1 chadenn | {count} chadenn'\n    Subscriber Count: '1 den koumanantet | {count} den koumanantet'\n    View Count: '1 sell | {count} sell'\n    Like Count: '1 like | {count} like'\n    Comment Count: '1 evezhiadenn | {count} evezhiadenn'\n    Watching Count: '1 den o sellet | {count} den o sellet'\n\n# Search Bar\n  Posts: Pennadoù\nSearch / Go to URL: 'Klask / Mont betek un URL'\nSearch Bar:\n  Clear Input: 'Skarzhañ an enankad'\n  Remove: Dilemel\nSearch character limit: 'Ar c''hlask a ya dreist an hirder brasañ aotreet : {searchCharacterLimit} arouezenn'\nSearch Listing:\n  Label:\n    4K: '4K'\n    8K: '8K'\n    VR180: 'VR180'\n    360 Video: '360°'\n    Subtitles: 'Istitloù'\n    New: 'Nevez'\n    3D: '3D'\n    # Aria labels\n    Closed Captions: 'Teleteks'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Siloù evit Klask'\n  Sort By:\n    Most Relevant: 'Ar re wellañ'\n    Rating: 'Notenn'\n    Upload Date: 'Deiziad kargañ'\n    View Count: 'Niver a selloù'\n  Time:\n    Time: 'Padelezh'\n    Any Time: 'A-holl-viskoaz'\n    Last Hour: 'Eur diwezhañ'\n    Today: 'Hiziv'\n    This Week: 'Ar sizhun-mañ'\n    This Month: 'Ar miz-mañ'\n    This Year: 'Ar bloaz-mañ'\n  Type:\n    Type: 'Doare'\n    All Types: 'Holl zoareoù'\n    Videos: 'Videoioù'\n    Channels: 'Chadennoù'\n    Movies: 'Filmoù'\n    #& Playlists\n  Duration:\n    Duration: 'Padelezh'\n    All Durations: 'An holl badelezhioù'\n    Short (< 4 minutes): 'Berr (< 4 munud)'\n    Medium (4 - 20 minutes): 'Etre (4 - 20 munud)'\n    Long (> 20 minutes): 'Hir (> 20 munud)'\n  Features:\n    Features: 'Perzhioù'\n    HD: 'HD'\n    Subtitles: 'Istitloù'\n    Creative Commons: 'Creative Commons'\n    3D: '3D'\n    Live: 'War-eeun'\n    4K: '4K'\n    360 Video: 'Video 360'\n    Location: 'Lec’h'\n    HDR: 'HDR'\n    VR180: 'VR180'\n  # On Search Page\n  Search Results: 'Disoc''hoù ar c''hlask'\n  Fetching results. Please wait: 'O klask emañ. Gortozit mar-plij'\n  Fetch more results: 'Diskouez muioc''h a zisoc''hoù'\n  There are no more results for this search: 'N''eus ket mui netra da ziskouez evit ar c''hlask-mañ'\n# Sidebar\n  Clear Filters: Skarzhañ ar siloù\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Koumanantoù'\n  # channels that were likely deleted\n  Error Channels: 'Chadennoù gant fazioù'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Ur bochad koumanantoù en deus ar profil-mañ. Ar wazh RSS a yelo en tu all d''ar vevenn lakaet'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Goullo eo ho roll koumanantoù. Ma faot deoc''h enporzhiañ ho koumanantoù, e c''hellit mont da Arventennoù ar Roadennoù ha choaz Enporzhiañ ho koumanantoù, mod all e c''hellit klask chadennoù da goumanantiñ dezho.'\n  Disabled Automatic Fetching: 'Diweredekaet ho peus an adtapout koumanantoù ent emgefreek. Hizivaat ar c''houmanantoù evit gwelet anezho.'\n  Empty Channels: 'N''eus video ebet gant ar chadennoù heuliet ganeoc''h evit poent.'\n  Empty Posts: 'N''eus kemennadenn ebet gant ar chadennoù heuliet ganeoc''h evit poent.'\n  Load More Videos: 'Kargañ muioc''h a videoioù'\n  Load More Posts: 'Kargañ muioc''h a bennadoù'\n  Subscriptions Tabs: 'Ivinelloù ar c''houmanantoù'\n  All Subscription Tabs Hidden: 'Kuzhet eo holl ivinelloù ar c''houmanantoù. Evit gwelet traoù amañ, diguzhit un nebeud ivinelloù e lodenn \"{subsection}\" e-barzh \"{settingsSection}\".'\nMore: 'Muioc''h'\nChannels:\n  Channels: 'Chadennoù'\n  Title: 'Roll ar chadennoù'\n  Search bar placeholder: 'Klask chadennoù'\n  Count: '{number} chadenn kavet.'\n  Empty: 'Goullo eo ho roll chadennoù.'\n  Unsubscribe: ''\n  Unsubscribed: ''\n  Unsubscribe Prompt: 'Ha sur oc''h e faot deoc''h digoumanantiñ deus \"{channelName}\" ?'\nTrending:\n  Trending: 'Diouzh ar cʼhiz'\n  Gaming: 'C''hoarioù video'\n  Trending Tabs: 'Ivinelloù ar re diouzh ar c''hiz'\n  Sports: Sport\nMost Popular: 'Ar muiañ a verzh ganto'\nFeed:\n  Feed Last Updated: '{feedName} hizivadenn diwezhañ ar wazh : {date}'\n  Refresh Feed: 'Adkargañ {subscriptionName}'\nPlaylists: 'Rolloù videoioù'\nUser Playlists:\n  Your Playlists: 'Ho rolloù videoioù'\n  Playlist Message: ''\n  Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: 'N''ho peus ket a roll videoioù. Klikit war ar bouton krouiñ ur roll-videoioù nevez evit krouiñ unan.'\n  Empty Search Message: 'N''eus video ebet e-barzh ar roll-vidoeioù-mañ a glotfe gant ho klask'\n  Search bar placeholder: 'Klask rolloù-videoioù'\n  Playlists with Matching Videos: 'Rolloù-videoioù gant videoioù a glot'\n\n  This playlist currently has no videos.: 'Ar roll-videoioù-mañ n''en deus video ebet evit poent.'\n\n  Create New Playlist: 'Krouiñ ur roll-videoioù nevez'\n\n  Add to Playlist: 'Ouzhpennañ d''ar roll-videoioù'\n  Add to Favorites: 'Ouzhpennañ da {playlistName}'\n  Remove from Favorites: 'Dilemel diwar {playlistName}'\n\n  Move Video Up: 'Kas ar video uheloc''h'\n  Move Video Down: 'Kas ar video izeloc’h'\n  Remove from Playlist: 'Tennañ kuit eus ar roll-videoioù'\n\n  Playlist Name: 'Anv ar roll-videoioù'\n  Playlist Description: 'Deskrivadur ar roll-videoioù'\n\n  Save Changes: 'Enrollañ ar c''hemmoù'\n  Cancel: 'Nullañ'\n  Edit Playlist Info: 'Kemmañ titouroù ar roll-videoioù'\n  Copy Playlist: 'Eilañ ar roll-videoioù'\n  Remove Duplicate Videos: 'Dilemel doublennoù ar videoioù'\n  Remove Watched Videos: 'Dilemel ar videoioù bet lennet'\n  Enable Quick Bookmark With This Playlist: 'Gweredekaat ar sined prim evit ar roll-videoioù-mañ'\n  Quick Bookmark Enabled: 'Sined prim gweredekaet'\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: 'Ha sur oc''h e faot deoc''h dilemel 1 doublenn video diouzh ar roll-videoioù-mañ ? Ne c''hall ket bezañ nullet. | Ha sur oc''h e faot deoc''h dilemel {playlistItemCount} doublenn video diouzh ar roll-videoioù-mañ ? Ne c''hall ket bezañ nullet.'\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 'Ha sur oc''h e faot deoc''h dilemel 1 video bet lennet diouzh ar roll-videoioù-mañ ? Ne c''hall ket bezañ nullet. | Ha sur oc''h e faot deoc''h dilemel {playlistItemCount} video bet lennet diouzh ar roll-videoioù-mañ ? Ne c''hall ket bezañ nullet.'\n  Delete Playlist: 'Dilemel roll-videoioù'\n  Cannot delete the quick bookmark target playlist.: 'N''eo ket posupl dilemel ar roll-videoioù e-lec''h ma vez enrollet ar sinedoù prim.'\n  Are you sure you want to delete this playlist? This cannot be undone: 'Ha sur oc''h e faot deoc''h dilemel ar roll-videoioù-mañ ? Ne vo ket moaien da nullañ war-lerc''h.'\n\n  Sort By:\n    NameAscending: 'A-Z'\n    NameDescending: 'Z-A'\n\n    LatestCreatedFirst: 'Deiziad Krouet (Nevez ''zo)'\n    EarliestCreatedFirst: 'Deiziad Krouet (Pell ''zo)'\n\n    LatestUpdatedFirst: 'Deiziad Hizivaat (Nevez ''zo)'\n    EarliestUpdatedFirst: 'Deiziad Hizivaat (Pell ''zo)'\n\n    LatestPlayedFirst: 'Deiziad Lennet (Nevez ''zo)'\n    EarliestPlayedFirst: 'Deiziad Lennet (Pell ''zo)'\n  SinglePlaylistView:\n    Search for Videos: 'Klask Videoioù'\n\n    Toast:\n      This video cannot be moved up.: 'Ar video-mañ n''hall ket pignat er roll.'\n      This video cannot be moved down.: 'Ar video-mañ n''hall ket diskenn er roll.'\n      Video has been removed: 'Dilamet eo bet ar video'\n      There was a problem with removing this video: 'Ur gudenn a oa en ur glask dilemel ar video-mañ'\n\n      This playlist is already being used for quick bookmark.: 'Implijet e vez dija ar roll-videoioù-mañ evit enrollañ ar sinedoù prim.'\n      This playlist is now used for quick bookmark: 'Implijet e vo ar roll-videoioù-mañ evit enrollañ ar sinedoù prim'\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: 'Implijet e vo ar roll-videoioù-mañ evit enrollañ ar sinedoù prim e-lec''h {oldPlaylistName}. Klikit amañ evit nullañ'\n      Reverted to use {oldPlaylistName} for quick bookmark: 'Adlakaat ar roll-videoioù {oldPlaylistName} evit enrollañ ar sinedoù prim'\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 'Videoioù ''zo e-barzh ar roll-videoioù n''int ket karget c''hoazh. Klikit amañ evit eilañ anezho memestra.'\n      Playlist name cannot be empty. Please input a name.: 'N''hall ket anv ar roll-videoioù bezañ goullo. Lakait unan mar-plij.'\n      Playlist has been updated.: 'Kemmet eo bet ar roll-videoioù.'\n      There was an issue with updating this playlist.: 'C''hoarvezet ez eus ur gudenn en ur cheñch ar roll-videoioù-mañ.'\n      \"{videoCount} video(s) have been removed\": \"Dilamet ez eus bet 1 video | Dilamet ez eus bet {videoCount} video\"\n      There were no videos to remove.: 'Ne oa video ebet da zilemel.'\n      This playlist is protected and cannot be removed.: 'Gwarezet eo ar roll-videoioù-mañ ha ne c''hall ket bezañ dilamet.'\n      Playlist {playlistName} has been deleted.: 'Dilamet eo bet ar roll-videoioù {playlistName}.'\n\n      This playlist does not exist: 'N''eus ket eus ar roll-videoioù-mañ'\n\n      This playlist has a video with a duration error: 'Bez ez eus ur video d''an nebeutañ hep padelezh e-barzh ar roll-videoioù, rummet e vo evel ma vije goullo ar padelezh.'\n      Video has been removed. Click here to undo.: Lamet eo bet ar video. Klikit amañ evit nullañ.\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: 'Choazit ur roll-videoioù evit ouzhpennañ ho video e-barzh | Choazit ur roll-videoioù evit ouzhpennañ ho {videoCount} video e-barzh'\n    N playlists selected: '{playlistCount} Diuzet'\n    Search in Playlists: 'Klask e-barzh ar rolloù-videoioù'\n    Allow Adding Duplicate Video(s): 'Aotren ouzhpennañ doublennoù videoioù'\n    Save: 'Enrollañ'\n\n    Added {count} Times: 'Ouzhpennet dija | Ouzhpennet {count} gwech'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} video a vo ouzhpennet'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} video bet ouzhpennet dija'\n\n    Toast:\n      You haven't selected any playlist yet.: 'N''ho peus diuzet ur roll-videoioù c''hoazh.'\n      \"Video(s) added to {playlistCount} playlists\": \"Video ouzhpennet d'ur roll-videoioù | Video ouzhpennet da {playlistCount} roll-videoioù\"\n  CreatePlaylistPrompt:\n    New Playlist Name: 'Anv nevez ar roll-videoioù'\n    Create: 'Krouiñ'\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: 'Bez ez eus dija ur roll-videoioù gant an anv-mañ. Choazit un anv disheñvel mar-plij.'\n      Playlist {playlistName} has been successfully created.: 'Krouet eo bet ar roll-videoioù {playlistName} gant berzh.'\n      There was an issue with creating the playlist.: 'C''hoarvezet ez eus ur gudenn en ur grouiñ ar roll-videoioù.'\n  Export Playlist: Ezporzhiañ ar Roll-videoioù\n  The playlist has been successfully exported: Ezporzhiet eo bet ar roll-videoioù gant berzh\n  TotalTimePlaylist: 'Amzer hollek : {duration}'\n  Export list of URLs: Ezporzhiañ roll an URLoù\nHistory:\n  # On History Page\n  History: 'Roll istor'\n  Watch History: 'Roll istor ar videoioù lennet'\n  Your history list is currently empty.: 'Goullo eo ho roll istor.'\n  Empty Search Message: 'N''eus video ebet e-barzh ho roll istor o klotañ gant ho klask'\n  Search bar placeholder: \"Klask e-barzh ar roll istor\"\n  Case Sensitive Search: 'Klask o toujañ d''ar pennlizherennoù'\n  DateNewestHistory: Deiziad Sellet (Nevez 'zo)\n  DateOldestHistory: Deiziad Sellet (Pell 'zo)\nSettings:\n  # On Settings Page\n  Settings: 'Arventennoù'\n  Expand All Settings Sections: ''\n  Sort Settings Sections (A-Z): 'Rummañ lodennoù an arventennoù (A-Z)'\n  Return to Settings Menu: 'Distreiñ d''al lañser arventennoù'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Ezhomm en deus an arload da vezañ adloc''het bremañ evit arloañ ar c''hemmoù. Adloc''hañ hag arloañ ar c''hemmoù ?'\n  General Settings:\n    General Settings: 'Hollek'\n    Check for Updates: 'Klask Hizivadurioù'\n    Check for Latest Blog Posts: 'Diskouez pennadoù diwezhañ ar Blog'\n    Fallback to Non-Preferred Backend on Failure: 'Distreiñ d''ar Backend ha n''eo ket hoc''h hini karetañ ma c''hoarvez ur gudenn'\n    Enable Search Suggestions: 'Gweredekaat Kinnigoù klask'\n    Auto Load Next Page:\n      Label: 'Kargañ ar bajenn da heul ent emgefreek'\n      Tooltip: 'Kargañ ar pajennoù hag an evezhiadennoù all ent emgefreek.'\n    Default Landing Page: 'Pajenn degemer dre ziouer'\n    Locale Preference: 'Yezh'\n    System Default: 'Reizhiad dre ziouer'\n    Preferred API Backend:\n      Preferred API Backend: 'API Backend muiañ karet'\n      Local API: 'API lec''hel'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Doare da ziskouez ar videoioù'\n      Grid: 'Kael'\n      List: 'Roll'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Gwellvezioù ar skeudennoùigoù'\n      Default: 'Dre ziouer'\n      Beginning: 'Derou'\n      Middle: 'Kreiz'\n      End: 'Fin'\n      Hidden: 'Kuzhet'\n      Blur: 'Ruzed'\n    Current Invidious Instance: 'Istañs Invidious bremanel'\n    The currently set default instance is {instance}: 'An istañs dre ziouer a zo {instance}'\n    No default instance has been set: 'N''eus istañs dre ziouer ebet choazet'\n    Current instance will be randomized on startup: 'Dargouezheket e vo un istañs dre ziouer pa vo adloc''het'\n    Set Current Instance as Default: 'Lakaat an istañs implijet bremañ evel an hini dre ziouer'\n    Clear Default Instance: 'Diverkañ an istañs dre ziouer'\n    View all Invidious instance information: 'Gwelet titouroù an holl istañsoù Invidious'\n    Region for Trending: 'Bro evit ar videoioù diouzh ar c''hiz'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Merañ al liammoù diavaez'\n      Open Link: 'Digeriñ an ere'\n      Ask Before Opening Link: 'Goulenn a-raok digeriñ ul liamm'\n      No Action: 'Netra'\n    Open Deep Links In New Window: Digeriñ an URLoù kaset da FreeTube e-barzh ur prenestr nevez\n    Minimize to system tray: Bihanaat er varenn kemennadennoù\n  Theme Settings:\n    Theme Settings: 'Tem'\n    Match Top Bar with Main Color: 'Lakaat da glotañ liv ar varenn e-krec''h gant al liv pennañ'\n    Expand Side Bar by Default: 'Astenn ar varenn gostez dre ziouer'\n    Disable Smooth Scrolling: 'Diweredekaat an dibunañ flour'\n    UI Scale: 'Skeul an UI'\n    Hide Side Bar Labels: 'Kuzhat tikedennoù ar varrenn gostez'\n    Hide FreeTube Header Logo: 'Kuzhat logo FreeTube an talbenn'\n    Base Theme:\n      Base Theme: 'Tem diazez'\n      Black: 'Du'\n      Dark: 'Teñval'\n      System Default: 'Yezh ar reizhiad'\n      Light: 'Sklaer'\n      Dracula: 'Drakula'\n      Catppuccin Mocha: 'Catppuccin Mocha'\n      Pastel Pink: 'Roz pastel'\n      Hot Pink: 'Roz flamm'\n      Nordic: 'Nordik'\n      Solarized Dark: 'Du luc''hahelet'\n      Solarized Light: 'Sklaer luc''hahelet'\n      Catppuccin Frappe: Catppuccin Frappe\n      Gruvbox Dark: Gruvboks Teñval\n      Gruvbox Light: Gruvboks Sklaer\n      Everforest Dark Hard: Everforest Du Teñval\n      Everforest Dark Medium: Everforest Du Krenn\n      Everforest Dark Low: Everforest Du Sklaer\n      Everforest Light Hard: Everforest Kalet Sklaer\n      Everforest Light Medium: Everforest Sklaer Krenn\n      Everforest Light Low: Everforest Sklaer Bihan\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Liv pennañ an tem'\n      Red: 'Ruz'\n      Pink: 'Roz'\n      Purple: 'Mouk'\n      Deep Purple: 'Mouk teñval'\n      Indigo: 'Indigo'\n      Blue: 'Glas'\n      Light Blue: 'Glas sklaer'\n      Cyan: 'Siañ'\n      Teal: 'Glas-gwer'\n      Green: 'Gwer'\n      Light Green: 'Gwer sklaer'\n      Lime: 'Liv sitroñs'\n      Yellow: 'Melen'\n      Amber: 'Goularz'\n      Orange: 'Orañjez'\n      Deep Orange: 'Orañjez teñval'\n      Dracula Cyan: 'Drakula Siañ'\n      Dracula Green: 'Drakula Gwer'\n      Dracula Orange: 'Drakula Orañjez'\n      Dracula Pink: 'Drakula Roz'\n      Dracula Purple: 'Drakula Mouk'\n      Dracula Red: 'Drakula Ruz'\n      Dracula Yellow: 'Drakula Melen'\n      Catppuccin Mocha Rosewater: 'Catppuccin Moka Roz sklaer'\n      Catppuccin Mocha Flamingo: 'Catppuccin Moka Flammeg boutin'\n      Catppuccin Mocha Pink: 'Catppuccin Moka Roz'\n      Catppuccin Mocha Mauve: 'Catppuccin Moka Mouk'\n      Catppuccin Mocha Red: 'Catppuccin Moka Ruz'\n      Catppuccin Mocha Maroon: 'Catppuccin Moka Gell'\n      Catppuccin Mocha Peach: 'Catppuccin Moka Pechez'\n      Catppuccin Mocha Yellow: 'Catppuccin Moka Melen'\n      Catppuccin Mocha Green: 'Catppuccin Moka Gwer'\n      Catppuccin Mocha Teal: 'Catppuccin Moka Glas-gwer'\n      Catppuccin Mocha Sky: 'Catppuccin Moka Glas oabl'\n      Catppuccin Mocha Sapphire: 'Catppuccin Moka Safir'\n      Catppuccin Mocha Blue: 'Catppuccin Moka Glas'\n      Catppuccin Mocha Lavender: 'Catppuccin Moka Lavand'\n      Solarized Yellow: 'Melen luc''hahelet'\n      Solarized Orange: 'Orañjez luc''hahelet'\n      Solarized Red: 'Ruz luc''hahelet'\n      Solarized Magenta: 'Majenta luc''hahelet'\n      Solarized Violet: 'Mouk luc''hahelet'\n      Solarized Blue: 'Glas luc''hahelet'\n      Solarized Cyan: 'Siañ luc''hahelet'\n      Solarized Green: 'Gwer luc''hahelet'\n      Gruvbox Dark Green: Gruvboks Gwer Teñval\n      Gruvbox Dark Yellow: Gruvboks Melen Teñval\n      Gruvbox Dark Blue: Gruvboks Glas Teñval\n      Gruvbox Dark Purple: Gruvboks Mouk Teñval\n      Gruvbox Dark Aqua: Gruvboks Dour Teñval\n      Gruvbox Dark Orange: Gruvboks Orañjez Teñval\n      Gruvbox Light Red: Gruvboks Ruz Sklaer\n      Gruvbox Light Blue: Gruvboks Glas Sklaer\n      Gruvbox Light Purple: Gruvboks Mouk Sklaer\n      Gruvbox Light Orange: Gruvboks Orañjez Sklaer\n      Everforest Dark Red: Everforest Ruz Teñval\n      Everforest Dark Orange: Everforest Orañjez Teñval\n      Everforest Dark Yellow: Everforest Melen Teñval\n      Everforest Dark Green: Everforest Gwer Teñval\n      Everforest Dark Aqua: Everforest Dour Teñval\n      Everforest Dark Blue: Everforest Glas Teñval\n      Everforest Dark Purple: Everforest Mouk Teñval\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Roz\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mouk\n      Catppuccin Frappe Red: Catppuccin Frappe Ruz\n      Catppuccin Frappe Maroon: Catppuccin Frappe Gell\n      Catppuccin Frappe Peach: Catppuccin Frappe Pechez\n      Catppuccin Frappe Yellow: Catppuccin Frappe Melen\n      Catppuccin Frappe Green: Catppuccin Frappe Gwer\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Sky: Catppuccin Frappe Oabl\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Safir\n      Catppuccin Frappe Blue: Catppuccin Frappe Glas\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavand\n      Everforest Light Red: Everforest Ruz Sklaer\n      Everforest Light Orange: Everforest Orañjez Sklaer\n      Everforest Light Yellow: Everforest Melen Sklaer\n      Everforest Light Green: Everforest Gwer Sklaer\n      Everforest Light Aqua: Everforest Dour Sklaer\n      Everforest Light Blue: Everforest Glas Sklaer\n      Everforest Light Purple: Everforest Mouk Sklaer\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Dour Rozenn\n      Catppuccin Latte Mauve: Catppuccin Latte Mouk\n      Catppuccin Latte Red: Catppuccin Latte Ruz\n    Secondary Color Theme: 'Liv eilvedel an tem'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'Lenner'\n    Play Next Video: 'Lenn emgefreek ar videoioù aliet'\n    Turn on Subtitles by Default: 'Enaouiñ an istitloù dre ziouer'\n    Autoplay Videos: 'Lenn emgefreek ar videoioù'\n    Proxy Videos Through Invidious: 'Proksi video dre Invidious'\n    Autoplay Playlists: 'Lenn emgefreek ar rolloù-videoioù'\n    Enable Theatre Mode by Default: 'Gweredekaat ar mod sinema dre ziouer'\n    Scroll Volume Over Video Player: 'Kontrol al live-son en ur zibunañ rodellig al logodenn war al lenner video'\n    Scroll Playback Rate Over Video Player: 'Kontrol ar feur lenn en ur zibunañ rodellig al logodenn war al lenner video'\n    Skip by Scrolling Over Video Player: 'Tremen en ur zibunañ rodellig al logodenn war al lenner video'\n    Display Play Button In Video Player: 'Diskouez ar bouton Lenn e-barzh al lenner video'\n    Enter Fullscreen on Display Rotate: 'Tremen e skramm leun pa vez troet ar skramm'\n    Next Video Interval: 'Munuter evit al lenn emgefreek'\n    Fast-Forward / Rewind Interval: 'Esaouenn evit mont War-raok / War-gil'\n    Default Volume: 'Ment ar son dre ziouer'\n    Default Playback Rate: 'Feur lenn dre ziouer'\n    Max Video Playback Rate: 'Feur lenn uhelañ ar videoioù'\n    Video Playback Rate Interval: 'Esaouenn feur lenn ar videoioù'\n    Default Video Format:\n      Default Video Format: 'Furmad video dre ziouer'\n      Dash Formats: 'Furmad DASH'\n      Legacy Formats: 'Furmad Legacy'\n      Audio Formats: 'Furmadoù son'\n    Default Quality:\n      Default Quality: 'Kalite dre ziouer'\n      Auto: 'Emgefreek'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: 'Gweredekaat Tapadennoù-skramm'\n      Format Label: 'Furmad an tapadennoù-skramm'\n      Quality Label: 'Kalite an tapadennoù-skramm'\n      Ask Path: 'Goulenn war-lerc''h an teuliad enrollañ'\n      Folder Label: 'Teuliad an tapadennoù-skramm'\n      Folder Button: 'Diuzañ un teuliad'\n      File Name Label: 'Patrom anv restr'\n      File Name Tooltip: 'Gallout a rit implijout an argemmennoù da-heul. %Y Bloavezh 4 sifr. %M Miz 2 sifr. %D Devezh 2 sifr. %H Eur 2 sifr. %N Munutennoù 2 sifr. %S Eilennoù 2 sifr. %T Mili-eilennoù 3 sifr. %s Eilennoù ar video. %t Mili-eilennoù ar video 3 sifr. %i ID ar video.'\n      Error:\n        Forbidden Characters: 'Arouezennoù difennet'\n        Empty File Name: 'Goullo eo anv ar restr'\n    Autoplay Interruption Timer: Munuter evit paouez al lenn emgefreek\n    Default Viewing Mode:\n      Theater: C'hoariva\n      Default Viewing Mode: Mod da welet dre ziouer\n      Full Screen: Skramm Leun\n      Picture in Picture: Mod skeudenn-ouzh-skeudenn\n      External Player: Lenner Diavaez ({externalPlayerName})\n  External Player Settings:\n    External Player Settings: 'Lenner diavaez'\n    External Player: 'Lenner diavaez'\n    Ignore Unsupported Action Warnings: 'Lezel a-gostez ar c''hemennadennoù evit an obererezhioù nann skoret'\n    Ignore Default Arguments: 'Leuskel arguzennoù dre ziouer a-gostez'\n    Custom External Player Executable: 'Lenner diavaez personelaet'\n    Custom External Player Arguments: 'Arguzennoù al lenner diavaez personelaet'\n    Players:\n      None:\n        Name: 'Hini ebet'\n  Privacy Settings:\n    Privacy Settings: 'Prevezded'\n    Remember History: 'Derc''hel soñj ar roll istor'\n    Save Watched Progress: 'Enrollañ araokadur al lenn'\n    Save Watched Videos With Last Viewed Playlist: 'Enrollañ ar videoioù lennet e-barzh roll-videoioù diwezhañ sellet'\n    Clear Search Cache: 'Skarzhañ roll-istor an enklaskoù'\n    Are you sure you want to clear out your search cache?: 'Ha sur oc''h e faot deoc''h skarzhañ roll-istor an enklaskoù ?'\n    Search cache has been cleared: 'Skarzhet eo bet roll-istor an enklaskoù'\n    Remove Watch History: 'Dilemel ar roll istor'\n    Are you sure you want to remove your entire watch history?: 'Ha sur oc''h e faot deoc''h dilemel ho roll istor a-bezh ?'\n    Watch history has been cleared: 'Dilamet eo bet roll istor ar videoioù lennet'\n    Remove All Subscriptions / Profiles: 'Dilemel an holl goumanantoù / profiloù'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Ha sur oc''h e faot deoc''h dilemel an holl goumanantoù ha profiloù ? Ne c''hall ket bezañ nullet.'\n    Remove All Playlists: 'Dilemel an holl rolloù-videoioù'\n    All playlists have been removed: 'Lamet eo bet an holl rolloù-videoioù'\n    Are you sure you want to remove all your playlists?: 'Ha sur oc''h e faot deoc''h dilemel hoc''h holl rolloù-videoioù ?'\n    Remember Search History: Derc'hel soñj roll istor ar c'hlask\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Emgefreek\n        Semi-auto: Hanter-emgefreek\n        Never: Biskoazh\n      Tooltip: Emgefreek = Enrollañ a ra pa vez kuitaet pep pajenn video, pa vez achu ar video, pe pa c'hoarvez ur fazi (da sk., feur bevennet pe ho talc'h zo aet da dermen). Hanter emgefreek = Heñvel ouzh emgefreek nemet pa vez kuitaet ur bajenn video, ha gallout a rit enrollañ pa faot deoc'h gant ar bouton \"Enrollañ araokadur al lenn\" dindan al lenner video.\n    Clear Search History and Cache: Skarzhañ ar roll istor hag ar grubuilh\n    Are you sure you want to clear out your search history and cache?: Ha sur oc'h e faot deoc'h skarzhañ ar roll istor hag ar grubuilh ?\n    Search history and cache have been cleared: Diverket eo bet ar roll istor hag ar grubuilh\n  Subscription Settings:\n    Subscription Settings: 'Koumanant'\n    Fetch Feeds from RSS: 'Adtapout ar gwazhioù RSS'\n    Manage Subscriptions: ''\n    Fetch Automatically: 'Adtapout ar wazh ent emgefreek'\n    Only Show Latest Video for Each Channel: 'Diskouez ar video-diwezhañ hepken evit pep chadenn'\n    Confirm Before Unsubscribing: 'Kadarnaat a-raok Digoumanantiñ'\n    To: Evit\n    'Limit the number of videos displayed for each channel': Termeniñ an niver a videoioù da ziskouez evit pep chadenn\n  Distraction Free Settings:\n    Distraction Free Settings: 'Disoursi'\n    Sections:\n      Side Bar: 'Barrenn gostez'\n      Subscriptions Page: 'Pajenn ar c''houmanantoù'\n      Channel Page: 'Pajenn ar chadenn'\n      Watch Page: 'Pajenn evit lenn'\n      General: 'Hollek'\n    Hide Video Views: 'Kuzhat an niver a selloù'\n    Hide Video Likes And Dislikes: 'Kuzhat bizied-meud ar videoioù'\n    Hide Channel Subscribers: 'Kuzhat an niver a dud koumanantet d''ar chadennoù'\n    Hide Comment Likes: 'Kuzhat an niver a vizied-meud evit an evezhiadennoù'\n    Hide Recommended Videos: 'Kuzhat ar videoioù aliet'\n    Hide Trending Videos: 'Kuzhat ar videoioù diouzh ar c''hiz'\n    Hide Popular Videos: 'Kuzhat ar videoioù muian karet'\n    Hide Playlists: 'Kuzhat ar rolloù-videoioù'\n    Hide Live Chat: 'Kuzhat ar flapiñ war-eeun'\n    Hide Active Subscriptions: 'Kuzhat ar c''houmanantoù oberiant'\n    Hide Video Description: 'Kuzhat deskrivadur ar video'\n    Hide Comments: 'Kuzhat an evezhiadennoù'\n    Hide Profile Pictures in Comments: 'Kuzhat ar skeudennoù profil e-barzh an evezhiadennoù'\n    Display Titles Without Excessive Capitalisation: 'Diskouez an titloù hep lizherennoù bras hag hep re a boentadurioù'\n    Hide Live Streams: 'Kuzhat ar skignañ war-eeun'\n    Hide Upcoming Premieres: 'Kuzhat rakskignañ da zont'\n    Hide Sharing Actions: 'Kuzhat an doareoù da rannañ'\n    Hide Videos on Watch: 'Kuzhat ar videoioù lennet'\n    Hide Chapters: 'Kuzhat ar chabistroù'\n    Hide Channels: 'Kuzhat videoioù ar chadennoù'\n    Hide Channels Disabled Message: 'Stanket eo bet chadennadoù zo gant an ID ha n''int ket evit bezañ diskouezet. Stanket eo an obererezh-mañ keit ma vez hizivaet an IDoù-se'\n    Hide Channels Placeholder: 'ID ar chadenn'\n    Hide Channels Invalid: 'Direizh eo ID ar chadenn roet'\n    Hide Channels API Error: 'Fazi en ur adtapout an implijer gant an ID bet roet. Gwiriit en-dro hag-eñ eo reizh an ID mar plij.'\n    Hide Channels Already Exists: 'ID ar chadenn a zo anezhañ dija'\n    Hide Featured Channels: 'Kuzhat ar chadennoù lakaet war-wel'\n    Hide Channel Playlists: 'Kuzhat ivinell \"rolloù-videoioù\" ar chadenn'\n    Hide Channel Shorts: 'Kuzhat ivinell \"Shortoù\" ar chadenn'\n    Hide Channel Podcasts: 'Kuzhat ivinell \"Podskignañ\" ar chadenn'\n    Hide Channel Releases: 'Kuzhat ivinell \"ermaeziadennoù\" ar chadenn'\n    Hide Videos, Playlists and Channels Containing Text: 'Kuzhat ar videoioù hag ar rolloù-videoioù gant testennoù'\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 'Ger, lodenn deus ur ger, pe frazenn'\n    Hide Subscriptions Videos: 'Kuzhat videoioù ar c''houmanantoù'\n    Hide Subscriptions Shorts: 'Kuzhat Shortoù ar c''houmanantoù'\n    Hide Subscriptions Live: 'Kuzhat ar skignañ war-eeun deus ar c''houmanantoù'\n    Hide Subscriptions Posts: Kuzhat ar pennadoù deus ar c'houmanantoù\n    Hide Channel Posts: Kuzhat ivinell \"Pennadoù\" ar chadenn\n    Hide Channel Home: Kuzhat ivinell \"Degemer\" ar chadenn\n    Hide Channel Courses: Kuzhat ivinell \"Kentelioù\" ar chadenn\n    Show Added Items: Diskouez an elfennoù ouzhpennet\n  Data Settings:\n    Data Settings: 'Roadennoù'\n    Select Export Type: 'Choaz doare ezporzhiañ'\n    Import Subscriptions: 'Enporzhiañ ho koumanantoù'\n    Subscription File: 'Restr ar c''houmanant'\n    History File: 'Rest ar roll istor'\n    Playlist File: 'Restr ar roll-videoioù'\n    Check for Legacy Subscriptions: ''\n    Export Subscriptions: 'Ezporzhiañ ar c''houmanantoù'\n    Export FreeTube: 'Ezporzhiañ FreeTube'\n    Export YouTube: 'Ezporzhiañ YouTube'\n    Export NewPipe: 'Ezporzhiañ NewPipe'\n    Import History: 'Enporzhiañ ar roll istor'\n    Export History: 'Ezporzhiañ ar roll istor'\n    Import Playlists: 'Enporzhiañ rolloù-videoioù'\n    Export Playlists: 'Ezporzhiañ rolloù-videoioù'\n    Export Playlists For Older FreeTube Versions:\n      Label: 'Ezporzhiañ rolloù-videoioù evit stummoù kozh FreeTube'\n      # |- = Keep newlines, No newline at end\n      Tooltip: |-\n        An dibarzh-mañ a ezporzh videoioù an holl rolloù-videoioù e-barzh ur roll-videoioù anvet « Favorites ».\n        Penaos ezporzhiañ & enporzhiañ videoioù e-barzh rolloù-videoioù gant stummoù kozh FreeTube :\n        1. Ezporzhiañ ho rolloù-videoioù gant an dibarzh-mañ gweredekaet.\n        2. Dilemel an holl rolloù-videoioù en ur implijout an dibarzh Dilemel an holl rolloù-videoioù dindan Prevezded.\n        3. Loc'hañ stumm kozh FreeTube hag enporzhiañ ar rolloù-videoioù ezporzhiet.\"\n    Profile object has insufficient data, skipping item: 'Diouer a roadennoù evit profil an elfenn-mañ, o leuskel an elfenn a-gostez'\n    All subscriptions and profiles have been successfully imported: 'Enporzhiet eo bet an holl goumanantoù ha profiloù gant berzh'\n    All subscriptions have been successfully imported: 'Enporzhiet eo bet an holl goumanantoù gant berzh'\n    Invalid subscriptions file: 'Direizh eo restr ar c''houmanantoù'\n    Invalid history file: 'Restr ar roll istor direizh'\n    Subscriptions have been successfully exported: 'Ezporzhiet eo bet ar c''houmanantoù gant berzh'\n    History object has insufficient data, skipping item: 'Lezel a-gostez an elfenn-mañ peogwir e vank titouroù e-barzh ar roll istor'\n    All watched history has been successfully imported: 'Enporzhiet eo bet roll istor ar videoioù lennet gant berzh'\n    All watched history has been successfully exported: 'Ezporzhiet eo bet roll istor ar videoioù lennet gant berzh'\n    Playlist insufficient data: 'Diouer a roadennoù evit ar roll-videoioù \"{playlist}\", o leuskel an elfenn a-gostez'\n    All playlists has been successfully imported: 'Enporzhiet eo bet an holl rolloù-videoioù gant berzh'\n    All playlists has been successfully exported: 'Ezporzhiet eo bet an holl rolloù-videoioù gant berzh'\n    Unable to read file: 'Ne c''haller ket lenn ar restr'\n    Unable to write file: 'N''haller ket skrivañ ar restr'\n    Unknown data key: 'Alc''hwez ar roadennoù dianav'\n    How do I import my subscriptions?: 'Penaos enporzhiañ ma c''houmanantoù ?'\n    Manage Subscriptions: 'Merañ ar c''houmanantoù'\n    Search history: Roll istor ar c'hlask\n    Import search history: Enporzhiañ roll istor ar c'hlask\n    Export search history: Ezporzhiañ roll istor ar c'hlask\n    Search history file: Restr roll istor ar c'hlask\n    All search history has been successfully imported: Enporzhiet eo bet roll istor ar c'hlask gant berzh\n    All search history has been successfully exported: Ezporzhiet eo bet roll istor ar c'hlask gant berzh\n  Proxy Settings:\n    Proxy Settings: 'Proksi'\n    Enable Tor / Proxy: 'Gweredekaat Tor / Proksi'\n    Proxy Protocol: 'Komenad ar Proksi'\n    Proxy Host: 'Komenad Servijer'\n    Proxy Port Number: 'Niverenn borzh ar Proksi'\n    Clicking on Test Proxy will send a request to: 'En ur glikañ war Taol-esae Proksi e vo kaset ur goulenn da'\n    Test Proxy: 'Taol-esae Proksi'\n    Your Info: 'Ho titouroù'\n    Ip: 'IP'\n    Country: 'Bro'\n    Region: 'Rannvro'\n    City: 'Kêr'\n    Error getting network information. Is your proxy configured properly?: 'C''hoarvezet ez eus bet ur gudenn en ur glask war-lerc''h titouroù ar rouedad. Ha kefluniet mat eo ho proksi ?'\n    Proxy Warning: N'eus ket ur proksi enframmet gant FreeTube met gallout a ra kennaskañ gant ur proksi diavaez, evel unan o vont en-dro war hoc'h urzhiataer evel Tor pe ur proksi diavaez SOCKS5 pourvezet gant VPNoù zo. Ma vez enaouet, deoc'h da wiriekaat e vez kefluniet mat ho proksi/Tor, mod-all ne vo ket FreeTube evit mont da gerc'hat an traoù.\n    Proxy Password: Ger-tremen ar Proksi\n    Proxy Username: Anv-Implijer ar Proksi\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'SponsorBlock'\n    Enable SponsorBlock: 'Gweredekaat SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'URL API SponsorBlock (Dre ziouer https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'Kelaouiñ pa vez tremenet ul lodenn paeroniet'\n    UseDeArrowTitles: 'Implijout titloù video DeArrow'\n    UseDeArrowThumbnails: 'Implijout DeArrow evit ar skeudennoùigoù'\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL API DeArrow evit krouiñ skeudennoùigoù (Dre ziouer https://dearrow-thumb.ajay.app)'\n    Skip Options:\n      Skip Option: 'Laoskel a-gostez an dibarzh'\n      Auto Skip: 'Lamm emgefreek'\n      Show In Seek Bar: 'Diskouez er varenn glask'\n      Prompt To Skip: 'Kinnig da laoskel a-gostez'\n      Do Nothing: 'Ober netra'\n    Category Color: 'Liv ar rummad'\n  Parental Control Settings:\n    Parental Control Settings: 'Kontroll ar gerent'\n    Hide Unsubscribe Button: 'Kuzhat ar bouton digoumanantiñ'\n    Show Family Friendly Only: 'Diskouez videoioù evit ar familh hepken'\n    Hide Search Bar: 'Kuzhat ar varenn glask'\n    Hide Uploader on Watch page: Kuzhat ar chadenn war ar bajenn lenn\n  Experimental Settings:\n    Experimental Settings: 'Arnodel'\n    Warning: 'Arventennoù arnodel eo, gallout a ra ar sistem chom bout pa vezont gweredekaet. Aliet-tre eo ober enrolladennoù. Kendalc’hit en ho riskl hoc’h-unan !'\n    Replace HTTP Cache: 'Erlec''hiañ ar grubuilh HTTP'\n  Password Dialog:\n    Password: 'Ger-tremen'\n    Enter Password To Unlock: 'Enankit ar ger-tremen evit dibrennañ an arventennoù'\n  Password Settings:\n    Password Settings: 'Ger-tremen'\n    Set Password To Prevent Access: 'Lakaat ur ger-tremen evit gwareziñ an arventennoù'\n    Set Password: 'Termeniñ ur ger-termen'\n    Remove Password: 'Dilemel ar ger-tremen'\nAbout:\n  #On About page\n  About: 'A-zivout'\n  Beta: 'Beta'\n  Source code: 'Kod mammenn'\n  AGPLv3: 'AGPLv3'\n  Downloads / Changelog: 'Pellgargañ / Deizlevr ar cheñchamantoù'\n  GitHub releases: 'Ermaeziadennoù GitHub'\n  Help: 'Skoazell'\n  FreeTube Wiki: 'Wiki FreeTube'\n  FAQ: 'FAG'\n  Discussions: 'Kaozeadennoù'\n  Report a problem: 'Menegiñ ur gudenn'\n  GitHub issues: 'Kudennoù renablet war GitHub'\n  Please check for duplicates before posting: 'Gwiriekait an doublennoù a-raok embann, mar-plij'\n  Website: 'Lec''hienn web'\n  Blog: 'Blog'\n  Email: 'Chomlec’h postel'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Flapañ war Matrix'\n  room rules: 'reolennoù ar sal'\n  Translate: 'Treiñ'\n  Credits: 'Kreditoù'\n  these people and projects: 'an dud-se hag ar raktresoù-se'\n  Donate: 'Ober un donezon'\n\nProfile:\n  Profile Settings: 'Profil'\n  Toggle Profile List: 'Diskouez roll ar profiloù'\n  Profile Select: 'Dibab ar profil'\n  Profile Filter: 'Silañ ar profil'\n  All Channels: 'An holl chadennoù'\n  Profile Manager: 'Merañ ar profil'\n  Create New Profile: 'Krouiñ ur profil nevez'\n  Edit Profile: 'Kemmañ ar profil'\n  Edit Profile Name: 'Kemmañ anv ar profil'\n  Create Profile Name: 'Krouiñ anv ar profil'\n  Profile Name: 'Anv ar profil'\n  Color Picker: 'Garrennig livioù'\n  Custom Color: 'Liv personelaet'\n  Profile Preview: 'Rakwelet ar profil'\n  Create Profile: 'Krouiñ ur profil'\n  Update Profile: 'Hizivaat ar profil'\n  Make Default Profile: 'Lakaat evel Profil dre ziouer'\n  Delete Profile: 'Dilemel ar profil'\n  Are you sure you want to delete this profile?: 'Ha sur oc''h e faot deoc''h dilemel ar profil-mañ ?'\n  All subscriptions will also be deleted.: 'An holl goumanantoù a vo ivez dilamet.'\n  Your profile name cannot be empty: 'Ne c''hall ket anv ar profil bezañ goullo'\n  Profile has been created: 'Krouet eo bet ar profil'\n  Profile has been updated: 'Hizivaet eo bet ar profil'\n  Your default profile has been set to {profile}: 'Ho profil dre ziouer ''zo bet lakaet da {profile}'\n  Removed {profile} from your profiles: 'Dilamet eo bet {profile} deus ho profiloù'\n  Your default profile has been changed to your primary profile: 'Kemmet eo bet ho profil dre ziouer d''ho profil pennañ'\n  '{profile} is now the active profile': '{profile} a zo bremañ ar profil oberiant'\n  Subscription List: 'Roll ar c''houmanantoù'\n  Other Channels: 'Chadennoù all'\n  '{number} selected': '{number} diuzet'\n  Select All: 'Diuzañ an holl'\n  Select None: 'Diuzañ hini ebet'\n  Delete Selected: 'Dilemel ar re ziuzet'\n  Add Selected To Profile: 'Ouzhpennañ ar re ziuzet d’ar profil'\n  No channel(s) have been selected: 'Chadenn ebet diuzet'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Ho profil pennañ eo. Ha sur oc''h e faot deoc''h dilemel ar chadennoù diuzet ? Ar memes chadennoù a vo dilamet deus ho profiloù all.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ha sur oc''h hoc''h e faot deoc''h dilemel ar chadennoù diuzet ?  Gant-se ne vo ket dilamet ar chadenn diouzh profil ebet all.'\n  Close Profile Dropdown: 'Serriñ roll ar profil'\n  Open Profile Dropdown: 'Digeriñ roll ar profil'\n#On Channel Page\nChannel:\n  Subscribe: 'Koumanantiñ'\n  Unsubscribe: 'Digoumanantiñ'\n  Channel has been removed from your subscriptions: 'Dilamet eo bet ar chadenn diouzh ho koumanantoù'\n  Removed subscription from {count} other channel(s): 'Dilamet eo bet ar c''houmanant diouzh {count} chadenn all'\n  Added channel to your subscriptions: 'Chadenn ouzhpennet d''ho koumanantoù'\n  Search Channel: 'Klask e-barzh ar chadenn'\n  Your search results have returned 0 results: 'N''eus disoc''h ebet gant ho klask'\n  This channel does not exist: 'N''eus ket deus ar chadenn-mañ'\n  This channel does not allow searching: 'Ne vez ket aotreet klask gant ar chadenn-mañ'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'Ur vevenn oad a zo d''ar chadenn-mañ ha ne c''hall ket bezañ gwelet war FreeTube evit poent.'\n  Channel Tabs: 'Ivinelloù ar chadenn'\n  Videos:\n    Videos: 'Videoioù'\n    This channel does not currently have any videos: 'N''eus ket a video evit poent gant ar chadenn-mañ'\n    Sort Types:\n      Newest: 'Nevesañ'\n      Oldest: 'Koshañ'\n      Most Popular: 'Ar muiañ a verzh ganto'\n  Shorts:\n    This channel does not currently have any shorts: 'N''eus ket a video short evit poent gant ar chadenn-mañ'\n  Live:\n    Live: 'End-eeun'\n    This channel does not currently have any live streams: 'Ne vez ket skignet war-eeun gant ar chadenn-mañ evit poent'\n  Playlists:\n    Playlists: 'Rolloù-videoioù'\n    This channel does not currently have any playlists: 'N''eus ket a roll-videoioù evit poent gant ar chadenn-mañ'\n    Sort Types:\n      Last Video Added: 'Video diwezhañ ouzhpennet'\n      Newest: 'Nevesañ'\n      Oldest: 'Koshañ'\n  Podcasts:\n    Podcasts: 'Podskignañ'\n    This channel does not currently have any podcasts: 'N''eus ket a bodskignañ evit poent gant ar chadenn-mañ'\n  Releases:\n    Releases: 'Ermaeziadennoù'\n    This channel does not currently have any releases: 'N''eus ket a ermaeziadenn evit poent gant ar chadenn-mañ'\n  About:\n    About: 'A-zivout'\n    Channel Description: 'Deskrivadur ar chadenn'\n    Tags:\n      Tags: 'Tikedennoù'\n      Search for: 'Klask evit \"{tag}\"'\n    Details: 'Munudoù'\n    Joined: 'Enskrivet'\n    Location: 'Lec''hiadur'\n    Featured Channels: 'Chadennoù lakaet war-wel'\n  Posts:\n    This channel currently does not have any posts: 'N''eus ket a gaozeadenn evit poent gant ar chadenn-mañ'\n    votes: '{votes} a vouezhioù'\n    View Full Post: 'Gwelet ar pennad a-bezh'\n    Reveal Answers: 'Diskouez ar respontoù'\n    Hide Answers: 'Kuzhat ar respontoù'\n    Video hidden by FreeTube: 'Video kuzhet gant FreeTube'\n    Viewing Posts Only Supported By Invidious: 'Posupl eo gwelet ar pennadoù gant Invidious hepken. Kit war ivinell kumuniezh ur chadenn evit gwelet he fennadoù hep Invidious.'\n  Home:\n    Home: Degemer\n    View Playlist: Diskouez ar roll-videoioù\n  Courses:\n    Courses: Kentelioù\n    This channel does not currently have any courses: Ar chadenn-mañ n'eus kentel ebet evit poent\nVideo:\n  IP block: 'Stanket eo bet ho chomlec''h IP gant YouTube. Klaskit cheñch VPN pe proksi evit lenn ar videoioù.'\n  More Options: 'Muioc''h a zibarzhioù'\n  Mark As Watched: 'Lakaat evel lennet'\n  Remove From History: 'Skarzhañ deus ar roll istor'\n  Video has been marked as watched: 'Lakaet eo bet ar video evel lennet'\n  Video has been removed from your history: 'Skarzhet eo bet ar video deus ho roll istor'\n  Save Video: 'Enrollañ ar video'\n  Video has been saved: 'Enrollet eo bet ar video'\n  Video has been removed from your saved list: 'Dilamet eo bet ar video diouzh ho roll-videoioù enrollet'\n  Open in YouTube: 'Digeriñ gant YouTube'\n  Copy YouTube Link: 'Eilañ liamm YouTube'\n  Open YouTube Embedded Player: 'Digeriñ lenner enkorfet YouTube'\n  Copy YouTube Embedded Player Link: 'Eilañ liamm lenner enkorfet YouTube'\n  Open in Invidious: 'Digeriñ gant Invidious'\n  Copy Invidious Link: 'Eilañ liamm Invidious'\n  Open Channel in YouTube: 'Digeriñ ar chadenn war YouTube'\n  Copy YouTube Channel Link: 'Eilañ liamm YouTube ar chadenn'\n  Open Channel in Invidious: 'Digeriñ ar chadenn war Invidious'\n  Copy Invidious Channel Link: 'Eilañ liamm Invidious ar chadenn'\n  Hide Channel: 'Kuzhat ar chadenn'\n  Unhide Channel: 'Diskouez ar chadenn'\n  Views: 'Sell'\n  Loop Playlist: 'Rodell roll-videoioù'\n  Shuffle Playlist: 'Meskañ ar roll-videoioù'\n  Reverse Playlist: 'Cheñch tu ar roll-videoioù'\n  Previous: 'A-raok'\n  Next: 'Goude'\n  Watched: 'Lennet'\n  Autoplay: 'Lenn emgefreek'\n  Starting soon, please refresh the page to check again: 'Kregiñ a raio a-benn nebeut, freskait ar bajenn evit gwiriañ en-dro'\n  # As in a Live Video\n  Premieres: 'Rakskignañ'\n  Upcoming: 'A-benn nebeut'\n  Live: 'End-eeun'\n  Live Now: 'War-eeun bremañ'\n  Live Chat: 'Flapañ war-eeun'\n  Enable Live Chat: 'Gweredekaat ar flapañ war-eeun'\n  Live Chat is currently not supported in this build.: 'N''eo ket skoret ar flapañ war-eeun gant ar stumm-añ evit poent.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Gweredekaet eo ar flapañ war-eeun.  Diskouezet e vo ar c''hemennadennoù amañ ur wech kaset.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'N''eo ket skoret ar flapañ war-eeun gant API Invidious evit poent.  Ret eo bezañ kennasket war-eeun ouzh YouTube.'\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'Dihegerz eo ar flapañ war-eeun evit ar skignañ-mañ. Marteze eo bet diweredekaet gant perc''henn ar chadenn.'\n  Show Super Chat Comment: 'Diskouez evezhiadennoù ar flapañ-meur'\n  Scroll to Bottom: 'Dibunañ d''an traoñ'\n  Published:\n    In less than a minute: 'Nebeutoc''h eget ur vunutenn zo'\n  Published on: 'Embannet war'\n  Streamed on: 'Skignet d''ar'\n  Started streaming on: 'Kroget da skignañ'\n  Sponsor Block category:\n    sponsor: 'Sponsor'\n    intro: 'Rakskrid'\n    outro: 'Klozañ'\n    self-promotion: 'Emvrudañ'\n    interaction: 'Etregwered'\n    music offtopic: 'Sonerezh na glot ket gant an tem'\n    recap: 'Berrzastum'\n    filler: 'Serrdoull'\n  External Player:\n    OpenInTemplate: 'Digeriñ gant {externalPlayer}'\n    video: 'video'\n    playlist: 'roll-videoioù'\n    OpeningTemplate: 'Digeriñ {videoOrPlaylist} gant {externalPlayer}…'\n    UnsupportedActionTemplate: '{externalPlayer} ne skor ket : {action}'\n    Unsupported Actions:\n      starting video at offset: 'kregiñ gant ar video gant dale'\n      setting a playback rate: 'termenañ ur feur lenn'\n      opening playlists: 'digeriñ rolloù-videoioù'\n      opening specific video in a playlist (falling back to opening the video): 'digeriñ ur video resis en ur roll-videoioù (distreiñ da zigeriñ ar video)'\n      reversing playlists: 'cheñch tu ar rolloù-videoioù'\n      shuffling playlists: 'meskañ ar rolloù-videoioù'\n      looping playlists: 'rodell rolloù-videoioù'\n  Player:\n    TranslatedCaptionTemplate: '{language} (troet diwar ar \"{originalLanguage}\")'\n    Audio Tracks: 'Tonioù aodio'\n    Theatre Mode: 'Mod c''hoariva'\n    Exit Theatre Mode: 'Kuitaat ar mod c''hoariva'\n    Full Window: 'Skramm a-bezh'\n    Exit Full Window: 'Kuitaat ar skramm a-bezh'\n    Take Screenshot: 'Kemer un dapadenn-skramm'\n    Show Stats: 'Diskouez Stadegoù'\n    Hide Stats: 'Kuzhat stadegoù'\n    Stats:\n      Stats: 'Stadegoù'\n      Video ID: 'ID ar Video : {videoId}'\n      Media Formats: 'Furmadoù ar media : {formats}'\n      Resolution: 'Spisder : {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Ment al lenner : {width}x{height}'\n      Bitrate: 'Fonnder bit : {bitrate} kbps'\n      Volume: 'Live-son : {volumePercentage}%'\n      Bandwidth: 'Bann drafet : {bandwidth} kbps'\n      Buffered: 'Karget e memor : {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Frammadoù dilamet : {droppedFrames} / Frammadoù hollek : {totalFrames}'\n      CodecAudio: 'Enboneger-ezvoneger : {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Enboneger-ezvoneger : {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Enboneger-ezvoneger : {videoCodec} / {audioCodec}'\n    You appear to be offline: 'Emaoc''h ezlinenn war a seblant.'\n    Playback will resume automatically when your connection comes back: 'Kendalc''het e vo da lenn ent emgefreek pa viot kennasket endro.'\n    Skipped segment: 'Lodenn {segmentCategory} tremenet'\n#& Videos\n    Autoplay is off: Lazhet eo al lenn emgefreek\n    Autoplay is on: Enaouet eo al lenn emgefreek\n  Unlisted: Anlistennet\n  MembersOnly: N'haller ket sellet ouzh ar videoioù miret d'an izili hepken gant FreeTube, peogwir eo ret bezañ luget gant ur gont Google ha paeañ ur c'houmanant d'ar chadenn.\n  AgeRestricted: N'haller ket sellet ouzh ar videoioù gant ur vevenn oad war FreeTube, peogwir eo ret bezañ luget gant ur gont Google kadarnaet gant hoc'h oad.\n#& Playlists\n  DRMProtected: Ne c'heller ket lenn ar videoioù gwarezet gant DRM war FreeTube, peogwir e vije ezhomm implijout elfennoù perc'hennet gant gwirioù ha n'int ket digor. Ma faot deoc'h sellet ouzh ar video-mañ e rankit mont war lec'hienn ofisiel YouTube gant ur merdeer web gouest da lenn an DRM.\n  Save Watched Progress: Enrollañ araokadur al lenn\n  Watched Progress Saved: Enrollet eo bet araokadur al lenn\n  DeArrow:\n    Show Original Details: Diskouez ar munudoù orin\n    Show Modified Details: Diskouez ar munudoù kemmet\nPlaylist:\n  #& About\n  Playlist: 'Roll-videoioù'\n  View Full Playlist: 'Gwelet ar roll-videoioù a-bezh'\n  Videos: ''\n  View: ''\n  Views: ''\n  Last Updated On: 'Hizivadenn ziwezhañ'\n  Sort By:\n    DateAddedNewest: 'Deiziad Ouzhpennet (Nevez ''zo)'\n    DateAddedOldest: 'Deiziad Ouzhpennet (Pell ''zo)'\n    AuthorAscending: 'Aozer (A-Z)'\n    AuthorDescending: 'Aozer (Z-A)'\n    VideoTitleAscending: 'Titl (A-Z)'\n    VideoTitleDescending: 'Titl (Z-A)'\n    VideoDurationAscending: 'Padelezh (Berrañ)'\n    VideoDurationDescending: 'Padelezh (Hirañ)'\n    Custom: 'Personelaat'\n\n# On Video Watch Page\n#* Published\n#& Views\n    PublishedNewest: Deiziad Embannet (Nevez 'zo)\n    PublishedOldest: Deiziad embannet (Pell 'zo)\nToggle Theatre Mode: ''\nChange Format:\n  Change Media Formats: 'Cheñch furmad ar video'\n  Use Dash Formats: 'Implijout ar furmad DASH'\n  Use Legacy Formats: 'Implijout ar furmad Legacy'\n  Use Audio Formats: 'Implijout ar furmad aodio'\n  Dash formats are not available for this video: 'N''haller ket implijout ar furmad DASH evit ar video-mañ'\n  Audio formats are not available for this video: 'N''haller ket implijout ar furmad aodio evit ar video-mañ'\n  Legacy formats are not available for this video: 'N''haller ket implijout ar furmad Legacy evit ar video-mañ'\nShare:\n  Share Video: 'Rannañ ar video'\n  Share Channel: 'Rannañ ar chadenn'\n  Share Playlist: 'Rannañ ar roll-videoioù'\n  Include Timestamp: 'Adalek ar mare resis'\n  Copy Link: 'Eilañ al liamm'\n  Open Link: 'Digeriñ an ere'\n  Copy Embed: 'Eilañ kod al lenner video enkorfet'\n  Open Embed: 'Digeriñ kod al lenner video enkorfet'\n  # On Click\n  Invidious URL copied to clipboard: 'Liamm Invidious eilet er golver'\n  Invidious Embed URL copied to clipboard: 'Liamm lenner enkorfet Invidious eilet er golver'\n  Invidious Channel URL copied to clipboard: 'Liamm Invidious ar chadenn eilet er golver'\n  YouTube URL copied to clipboard: 'Liamm YouTube eilet er golver'\n  YouTube Embed URL copied to clipboard: 'Liamm lenner enkorfet YouTube eilet er golver'\n  YouTube Channel URL copied to clipboard: 'Liamm YouTube ar chadenn eilet er golver'\n  Share Post: Rannañ an embann\nClipboard:\n  Copy failed: 'Eilañ er golver c''hwitet'\n  Cannot access clipboard without a secure connection: 'Ne c''haller ket adtapout ar golver hep ur c''hennask suraet'\n\nChapters:\n  Chapters: 'Chabistroù'\n  Key Moments: Mareoù a-bouez\nMini Player: 'Lenner bihan'\nComments:\n  Comments: 'Evezhiadennoù'\n  Click to View Comments: 'Klikit amañ evit gwelet an evezhiadennoù'\n  Getting comment replies, please wait: 'O kerc''hat respontoù an evezhiadennoù, gortozit mar plij'\n  There are no more comments for this video: 'Evezhiadenn ouzhpenn ebet evit ar video-mañ'\n  Hide Comments: 'Kuzhat an evezhiadennoù'\n  Top comments: 'Evezhiadennoù gwellañ'\n  Newest first: 'Nevesañ da gentañ'\n  View {replyCount} replies: 'Diskouez 1 respont | Diskouez {replyCount} respont'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'Diskouez respontoù all'\n  There are no comments available for this video: 'N''eus evezhiadenn ebet evit ar video-mañ'\n  There are no comments available for this post: 'N''eus evezhiadenn ebet evit ar gemennadenn-mañ'\n  Load More Comments: 'Kargañ muioc''h a evezhiadennoù'\n  Pinned by: 'Spilhennet gant'\n  Member: 'Ezel'\n  Subscribed: 'Koumanantet'\n  Hearted: 'Karet'\n\n  Hide {replyCount} replies: Kuzhat 1 respont | Kuzhat {replyCount} respont\n  View 1 reply from {channelName}: Diskouez 1 respont gant {channelName}\n  View {replyCount} replies from {channelName} and others: Diskouez {replyCount} respont gant {channelName} ha reoù all\nUp Next: 'Da-heul'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Choazit ar backend implijet gant FreeTube evit tapout ar roadennoù. Un eztenner enkorfet eo an API lec''hel. Ezhomm en deus an API Invidious da gaout ur servijer Invidious evit kevreañ outañ.'\n    Fallback to Non-Preferred Backend on Failure: 'Pa c''hoarvezo ur gudenn gant hoc''h API karetañ, e klasko FreeTube implijout an API ha n''eo ket hoc''h hini karetañ evel doare sikour ma vez gweredekaet.'\n    Thumbnail Preference: 'Erlec''hiet e vo an holl skeudennoùigoù war FreeTube gant ur skeudenn tennet eus ar video, kuzhet pe displannet, e-lec''h ar skeudennig dre ziouer.'\n    Invidious Instance: 'Istañs Invidious implijet gant FreeTube evit galvoù API.'\n    Region for Trending: 'Gant an dra-se e c''hallit dibab ar vro evit ar videoioù diouzh ar c''hiz a faot deoc''h gwelet.'\n    External Link Handling: |\n      Choazit an emzalc'h dre ziouer pa vo kliket war ul liamm ha n'hall ket bezañ digoret gant FreeTube.\n      Dre ziouer, e vo digoret al liamm e-barzh ho merdeer web.\n    Open Deep Links In New Window: An URLoù kaset da FreeTube gant askouezhioù ur merdeer web pe roet war arroudenn an arc'had, a vo digoret e-barzh ur prenestr nevez.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Kevreañ a raio ouzh Invidious evit mont da gerc''hat ar videoioù e-lec''h kevreañ war-eeun ouzh YouTube.'\n    Default Video Format: 'Arventennañ ar furmadoù implijet pa vez lennet ur video. Ar furmadoù DASH a c''hell bezañ lennet gant ur c''halite uheloc''h. Bevennet eo ar furmadoù Legacy da 360p d''ar muiañ met nebeutoc''h a vann- drafet a vez implijet. Ar furmadoù aodio zo lanvioù aodio hepken.'\n    Scroll Playback Rate Over Video Player: 'Pa vez ar biz-red war ar video, dalc''hit pouezet war an douchenn Ctrl (Command war Mac) ha dibunit rodellig al logodenn war-raok pe war-gil evit cheñch ar feur lenn. Dalc''hit pouezet war an douchenn Ctrl (Command war Mac) ha klikit war bouton kleiz al logodenn a-benn distreiñ buan d''ar feur lenn dre ziouer (1x, nemet ma ''z eo bet kemmet en arventennoù).'\n    Skip by Scrolling Over Video Player: 'Tremen d''ur video d''egile en ur zibunañ rodellig al logodenn war al lenner video, doare MPV.'\n  External Player Settings:\n    External Player: 'Dibab ul lenner diavaez a ziskouezo un ikon war ar skeudennig, evit digeriñ ar video (pe ar roll-videoioù ma vez skoret) el lenner diavaez. Diwallit, arventennoù Invidious n''o deus ket efed ebet war al lenner diavaez.'\n    Custom External Player Executable: 'Dre ziouer e soñjo FreeTube e c''hall mont da glask al lenner diavaez choazet dre an argemmenn endro PATH. Mar bez ezhomm e c''haller lakaat un hent personelaet amañ.'\n    Ignore Warnings: 'Diweredekaat ar c''hemennadennoù pa ne vez ket skoret un obererezh bennak gant al lenner diavaez (da sk. cheñch tu ar rolloù-videoioù, etc.).'\n    Ignore Default Arguments: 'Arabat kas arguzennoù dre ziouer d''al lenner diavaez nemet URL ar video (d.s. feur lenn, URL ar roll-videoioù, etc.). Treuzkaset e vo an arguzennoù personelaet.'\n    Custom External Player Arguments: 'An holl arguzennoù personelaet el linennoù urzhiañ, a faot deoc''h e vefe treuzkaset d''al lenner diavaez.'\n    DefaultCustomArgumentsTemplate: \"(Dre ziouer : '{defaultCustomArguments}')\"\n  Distraction Free Settings:\n    Hide Channels: 'Lakait ID ur chadenn evit mirout ouzh an holl videoioù, rolloù-videoioù hag ar chadenn hec''h-unan da vezañ gwelet en enklaskoù, e roll ar videoioù brudetañ, ar re vuiañ karet, hag ar re aliet. Ret eo d''an ID bezañ klot ha ret eo doujañ d''ar pennlizherennoù.'\n    Hide Subscriptions Live: 'Erlec''hiet eo an arventenn-mañ gant an arventenn \"{appWideSetting}\" evit an arload a-bezh, e lodenn \"{subsection}\" e-barzh \"{settingsSection}\"'\n    Hide Videos, Playlists and Channels Containing Text: 'Ebarzhit ur ger, lodenn ur ger pe ur frazenn (o toujañ d''ar pennlizherennoù) evit kuzhat an holl videoioù & rolloù-videoioù gant ar ger pe ar frazenn-mañ en titl orin war FreeTube, nemet er roll-istor, e-barzh ho rolloù-videoioù hag ar videoioù e-barzh ar rolloù-videoioù.'\n    Hide Videos on Watch: Kuzhat ar videoioù bet lennet diouzh ar Videoioù, Shortoù hag ivinell ar skignañ war-eeun war bajenn ar c'houmanantoù ha pajenn ar chadennoù. Ne vo ket kemmet pajenn degemer ar chadennoù\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Pa vez gweredekaet e vez implijet RSS gant FreeTube e-lec''h e zoare dre ziouer evit adtapout ho kwazh koumanantiñ. Buanoc''h ez an traoù gant an RSS ha ne vo ket stanket ar chomlec''h IP, met ne ginnig ket titouroù ''zo evel padelezh ar video, statud ar video war-eeun, pe c''hoazh an evezhiadennoù'\n    Fetch Automatically: 'Pa vo gweredekaet e vo adtapet ho kwazh koumanantiñ gant FreeTube ent emgefre pa vo lañset pe pa vo digoret ur prenestr nevez.'\n  Experimental Settings:\n    Replace HTTP Cache: 'Diweredekaat ar grubuilh HTTP diazezet war ar bladenn Electron ha gweredekaat krubuilh personelaet ar skeudennoù e-barzh ar memor. Implijet e vo muioc''h a vemor RAM.'\n  SponsorBlock Settings:\n    UseDeArrowTitles: 'Erlec''hiañ titloù ar videoioù gant titloù kinniget gant implijerien DeArrow.'\n    UseDeArrowThumbnails: 'Erlec''hiañ skeudennoùigoù ar videoioù gant skeudennoùigoù DeArrow.'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Fazi un API lec''hel (Klikit evit eilañ)'\nInvidious API Error (Click to copy): 'Fazi gant API Invidious (Klikit evit eilañ)'\nFalling back to Invidious API: 'Distreiñ da API Invidious'\nFalling back to Local API: 'Distreiñ d''an API lec''hel'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Dihegerz eo ar video-mañ abalamour da furmadoù a vank. Gallout a ra c''hoarvezout e-barzh broioù ''zo.'\nSubscriptions have not yet been implemented: ''\nUnknown YouTube url type, cannot be opened in app: 'Seurt url YouTube dianav, n''hall ket bezañ digoret en arload'\nHashtags have not yet been implemented, try again later: ''\nLoop is now disabled: 'Diweredekaet eo ar rodell bremañ'\nLoop is now enabled: 'Gweredekaet eo ar rodell bremañ'\nShuffle is now disabled: 'Diweredekaet eo ar Mesk-ha-mesk bremañ'\nShuffle is now enabled: 'Gweredekaet eo ar Mesk-ha-mesk bremañ'\nThe playlist has been reversed: 'Eilpennet eo bet ar roll-videoioù'\nPlaying Next Video: 'Lenn ar video da-heul'\nPlaying Previous Video: 'Lenn ar video a-raok'\nPlaying Next Video Interval: 'Lenn ar video da-heul a-benn nebeud-tre. Klikit evit nullañ. | Lenn ar video da-heul a-benn {nextVideoInterval} eilenn. Klikit evit nullañ. | Lenn ar video da-heul a-benn {nextVideoInterval} eilenn. Klikit evit nullañ.'\nCanceled next video autoplay: 'Nullañ al lenn emgefreek da-heul'\n\nDefault Invidious instance has been set to {instance}: 'Istañs Invidious dre ziouer a zo bet lakaet da {instance}'\nDefault Invidious instance has been cleared: 'Diverket eo bet Istañs Invidious dre ziouer'\n'The playlist has ended. Enable loop to continue playing': 'Echu eo ar roll-videoioù.  Gweredekaat ar rodell evit kenderc''hel da lenn'\nAge Restricted:\n  This channel is age restricted: 'Ur vevenn oad a zo d''ar chadenn-mañ'\n  This video is age restricted: 'Ur vevenn oad a zo d''ar video-mañ'\nExternal link opening has been disabled in the general settings: 'Diweredekaet eo al liammoù diavaez en arventennoù hollek'\nScreenshot Success: 'Enrollet eo bet an dapadenn-skramm'\nScreenshot Error: 'Tapadenn skramm c''hwitet. {error}'\nChannel Hidden: '{channel} ouzhpennet da sil ar chadennoù'\nChannel Unhidden: '{channel} dilamet deus sil ar chadennoù'\nTrimmed input must be at least N characters long: 'An destenn bevennet a rank bezañ 1 arouezenn enni da nebeutañ | An destenn bevennet a rank bezañ {length} arouezenn enni da nebeutañ'\nTag already exists: 'Bez ez eus dija deus an dikedenn \"{tagName}\"'\n\nHashtag:\n  Hashtag: 'Ger-klik'\n  This hashtag does not currently have any videos: 'N''eus ket a video evit poent gant ar ger-klik-mañ'\nMoments Ago: 'nevez ''zo'\nYes: 'Ya'\nNo: 'Ket'\nOk: 'Mat eo'\nYes, Delete: 'Ya, Dilemel'\nYes, Restart: 'Ya, Adloc''hañ'\nYes, Open Link: 'Ya, digeriñ al liamm'\nCancel: 'Nullañ'\n# symbol used to indicate that an item is correct\ncheckmark: '✓'\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: '{label} : {value}'\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Enaouiñ/Lazhañ Ostilhoù diorren\n  Zoom Out: Zoum bihanaat\n  Zoom In: Zoum brassat\n  Fullscreen: Tremen e skramm leun\n  Theatre Mode: Enaouiñ/Lazhañ ar mod c'hoariva\n  Keyboard Shortcuts: Berradennoù an douchennaoueg\n  Sections:\n    Video:\n      Playback: 'Video : Lenn'\n      General: 'Video : Hollek'\n    App:\n      Situational: 'Arload : Situational'\n      General: 'App : Hollek'\n  Show Keyboard Shortcuts: Diskouez Berradennoù an douchennaoueg\n  History Backward: Mont d’ar bajenn kent\n  History Forward: Mont d’ar bajenn war-lerc’h\n  New Window: Krouiñ ur prenestr nevez\n  Navigate to Settings: Mont da bajenn an arventennoù\n  Navigate to History: Mont da bajenn ar roll istor\n  Refresh: Freskaat ar wazh gant traoù embannet nevez 'zo\n  Captions: Enaouiñ/lazhañ an istitloù\n  Stats: Diskouez stadegoù ar video\n  Picture in Picture: Enaouiñ/lazhañ ar mod skeudenn-ouzh-skeudenn\n  Play: Enaouiñ/lazhañ lenn/ehan\n  Mute: Enaouiñ/lazhañ tennañ ar son\n  Full Window: Enaouiñ/lazhañ skramm a-bezh\n  Take Screenshot: Kemer un dapadenn skramm\n  Minimize Window: Bihanaat ar prenestr\n  Close Window: Serriñ ar prenestr\n  Search in New Window: Klask e-barzh ur prenestr nevez\n  Volume Up: Uhelaat al live-son\n  Volume Down: Izelaat al live-son\n  Last Chapter: Chabistr diwezhañ\n  Next Chapter: Chabistr da heul\n  Focus Secondary Search: Lakaat war-wel an eil varenn glask (ma ve deus outi)\n  Large Rewind: Lamm war-gil 10 eilenn / Lamm war-gil hervez feur lenn ar video\n  Large Fast Forward: Lamm war-raok 10 eilenn / Lamm war-raok hervez feur lenn ar video\n  Decrease Video Speed: Gorrekaat ar video hervez esaouenn feur lenn ar video\n  Increase Video Speed: Kreskiñ tizh ar video hervez esaouenn feur lenn ar video\n  Reset Zoom: Adderaouekaat live ar zoum / Skeul an UI\n  Focus Search: Lakaat war-wel ar varenn glask\n  Last Frame: Skeudenn gent (pa vez ehanet ar video)\n  Next Frame: Skeudenn da-heul (pa vez ehanet ar video)\n  Small Rewind: Lamm war-gil K eilenn hervez esaouenn war-gil feur lenn ar video\n  Small Fast Forward: Lamm war-raok K eilenn hervez esaouenn war-raok feur lenn ar video\n  Skip by Tenths: Lammat e-barzh ar video dre zregantad (3 lamm evit tizhout 30% ar badelezh)\n  Home: Mont e penn-kentañ ar video\n  End: Mont e fin ar video\n  Skip to Next Video: Mont d'ar video da heul e-barzh ur roll-videoioù pe d'ar video aliet da heul\n  Skip to Previous Video: Mont d'ar video a-raok e-barzh ur roll-videoioù\nAutoplay Interruption Timer: Nullet al lenn emgefreek goude {autoplayInterruptionIntervalHours} eurvezh dioberiant\nRight-click or hold to see history: Klik dehou pe dalc'hit pouezet evit gwelet ar roll istor\nDescription:\n  Expand Description: \"...muioc'h\"\n  Collapse Description: Diskouez nebeutoc'h\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nshortcutLabelSeparator: ｜\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enankañ\n  plus: Mui\n  arrowdown: Bir diskenn\n  arrowleft: Bir kleiz\n  arrowright: Bir dehou\n  arrowup: Bir sevel\nExpand side navigation: Astenn ar merdeiñ kostez\nCompact side navigation: Fetisaat ar merdeiñ kostez\n"
  },
  {
    "path": "static/locales/bs.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Bosanski'\n\n# Webkit Menu Bar\nFile: 'Fajl'\nQuit: 'Napusti'\nEdit: 'Uredi'\nUndo: 'Ukini'\nRedo: 'Ponovi'\nCut: 'Izreži'\nCopy: 'Kopiraj'\nPaste: 'Umetni'\nDelete: 'Izbriši'\nSelect all: 'Odabri sve'\nToggle Developer Tools: 'Uključi alate za programere'\nActual size: 'Prirodna veličina'\nZoom in: 'Približi'\nZoom out: 'Umanji'\nToggle fullscreen: 'Prebaci preko cijelog ekrana'\nWindow: 'Prozor'\nMinimize: 'Smanji'\nClose: 'Zatvori'\nBack: 'Nazad'\nForward: 'Unapred'\n\nVersion {versionNumber} is now available!  Click for more details: 'Verzija {versionNumber} je sada dostupna! Kliknite za više detalja'\nDownload From Site: 'Instaliraj preko stranice'\nA new blog is now available, {blogTitle}. Click to view more: 'Sada je dostupan novi blog, {blogTitle}. Kliknite da vidite više'\n\nGlobal:\n  Sort By: 'Poredaj po'\n\n# Search Bar\n  Live: Uživo\n  Videos: Videozapisi\nSearch / Go to URL: 'Pretražite / idite na URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Pretraži filtere'\n  Sort By:\n    Most Relevant: 'Naj relevantnije'\n    Rating: 'Ocjena'\n    Upload Date: 'Datum uploada'\n    View Count: 'Broj pregleda'\n  Time:\n    Time: 'Vrjeme'\n    Any Time: 'Bilo kada'\n    Last Hour: 'Zadnji sat'\n    Today: 'Danas'\n    This Week: 'Ove sedmice'\n    This Month: 'Ovog Mjeseca'\n    This Year: 'Ove godine'\n  Type:\n    Type: 'Vrsta'\n    All Types: 'Sve vrste'\n    Videos: 'Videozapisi'\n    Channels: 'Kanali'\n    #& Playlists\n  Duration:\n    Duration: 'Trajanje'\n    All Durations: 'Sva trajanja'\n    Short (< 4 minutes): 'Kratko (<4 minute)'\n    Long (> 20 minutes): 'Dugo (>20 minuta)'\n  # On Search Page\n  Search Results: 'Rezultati pretrage'\n  Fetching results. Please wait: 'Dohvaćanje rezultata. Molimo sačekajte'\n  Fetch more results: 'Dohvati više rezultata'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Pretplate'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Ovaj profil ima veliki broj pretplata. Prisiljavanje RSS-a da izbjegne ograničenje brzine'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Vaša lista pretplata je trenutno prazna. Počnite dodavati pretplate da biste ih vidjeli ovdje.'\n  Load More Videos: 'Očitaj više videozapisa'\nTrending:\n  Trending: 'U trendu'\n  Sports: Sport\nMost Popular: 'Naj popularnije'\nPlaylists: 'playliste'\nUser Playlists:\n  Your Playlists: 'Tvoje playliste'\nHistory:\n  # On History Page\n  History: 'Istorija'\n  Watch History: 'Istorija gledanja'\n  Your history list is currently empty.: 'Vaša lista istorije je trenutno prazna.'\nSettings:\n  # On Settings Page\n  Settings: 'Postavke'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Aplikacija se treba restartovati da bi promjene stupile na snagu. Restartuj i primijeniti promjenu?'\n  General Settings:\n    General Settings: 'Generalne postavke'\n    Check for Updates: 'Provjeri ima li update'\n    Check for Latest Blog Posts: 'Potraži najnovije objave na blogu'\n    Fallback to Non-Preferred Backend on Failure: 'Vraćanje na neželjeni backend u slučaju neuspjeha'\n    Enable Search Suggestions: 'Omogući prijedloge pretraživanja'\n    Default Landing Page: 'Zadana odredišna stranica'\n    Locale Preference: 'Jezik'\n    Preferred API Backend:\n      Preferred API Backend: 'Poželjni API Backend'\n      Local API: 'Lokalni API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Način prikazanja videa'\n      Grid: 'Popločan'\n      List: 'Popis'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencija minijature'\n      Default: 'Standard'\n      Beginning: 'Početak'\n      Middle: 'Sredina'\n      End: 'Kraj'\n    Region for Trending: 'Regiona za trend'\n        #! List countries\n  Theme Settings:\n    Theme Settings: 'Postavke teme'\n    Match Top Bar with Main Color: 'Koristi glavnu boju u gornjoj traci'\nChannel:\n  Videos:\n    Videos: Videozapisi\nTooltips: {}\nNo: 'Ne'\nNew Window: Novi Prozor\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Uključi alate za programere\n  Zoom In: Približi\n  Zoom Out: Umanji\n  Fullscreen: Prebaci preko cijelog ekrana\nPreferences: Postavke\nProfile:\n  Select All: Odabri sve\n"
  },
  {
    "path": "static/locales/ca.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Català'\n\n# Webkit Menu Bar\nFile: 'Fitxer'\nQuit: 'Surt'\nEdit: 'Edita'\nUndo: 'Desfés'\nRedo: 'Refés'\nCut: 'Retalla'\nCopy: 'Copia'\nPaste: 'Enganxa'\nDelete: 'Borra'\nSelect all: 'Seleccionar-ho tot'\nToggle Developer Tools: 'Activa les eines per a desenvolupadors'\nActual size: 'Mida real'\nZoom in: 'Amplia'\nZoom out: 'Allunya'\nToggle fullscreen: 'Commuta la pantalla completa'\nWindow: 'Finestra'\nMinimize: 'Minimitzar'\nClose: 'Tancar'\nBack: 'Enrere'\nForward: 'Endavant'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vídeos'\n\n  Live: En directe\n  Posts: Publicacions\n  Sort By: 'Ordena Per'\n  Shorts: Curts\n  Counts:\n    Video Count: 1 vídeo | {count} vídeos\n    Channel Count: 1 canal | {count} canals\n    Subscriber Count: 1 subscriptor | {count} subscriptors\n    View Count: 1 visualització | {count} visualitzacions\nVersion {versionNumber} is now available!  Click for more details: 'La versió {versionNumber} està disponible! Fes clic per a més detalls'\nDownload From Site: 'Descarrega des del web'\nA new blog is now available, {blogTitle}. Click to view more: 'Nova publicació al blog disponible, {blogTitle}. Fes clic per saber-ne més'\n\n# Search Bar\nSearch / Go to URL: 'Cerca / Ves a l''URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtres de cerca'\n  Sort By:\n    Most Relevant: 'Més rellevant'\n    Rating: 'Valoració'\n    Upload Date: 'Data de pujada'\n    View Count: 'Visualitza el comptador'\n  Time:\n    Time: 'Data'\n    Any Time: 'Qualsevol moment'\n    Last Hour: 'Última hora'\n    Today: 'Avui'\n    This Week: 'Aquesta setmana'\n    This Month: 'Aquest mes'\n    This Year: 'Aquest any'\n  Type:\n    Type: 'Tipus'\n    All Types: 'Qualsevol tipus'\n    Videos: 'Vídeos'\n    Channels: 'Canals'\n    #& Playlists\n    Movies: Pel·lícules\n  Duration:\n    Duration: 'Duració'\n    All Durations: 'Qualsevol duració'\n    Short (< 4 minutes): 'Curts (< 4 minuts)'\n    Long (> 20 minutes): 'Llargs (> 20 minuts)'\n  # On Search Page\n    Medium (4 - 20 minutes): Mitjans (4 - 20 minuts)\n  Search Results: 'Resultats de la cerca'\n  Fetching results. Please wait: 'Obtenint resultats. Espera si us plau'\n  Fetch more results: 'Obtenir més resultats'\n# Sidebar\n  There are no more results for this search: No hi ha més resultats per a aquesta cerca\n  Features:\n    Subtitles: Subtítols\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subscripcions'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'La teva llista de subscripcions està buida. Afegeix subscripcions per veure-les aquí.'\n  Load More Videos: Carregar més vídeos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Aquest perfil té un gran nombre de subscripcions. Forçant RSS per evitar la limitació fixada\n  Error Channels: Canals amb errors\nTrending:\n  Trending: 'Tendències'\n  Gaming: Jocs\n  Trending Tabs: Pestanyes de tendència\nMost Popular: 'Més populars'\nPlaylists: 'Llistes de reproducció'\nUser Playlists:\n  Your Playlists: 'Les teves llistes de reproducció'\n  Search bar placeholder: Cerca a la llista de reproducció\n  Empty Search Message: No hi ha cap vídeo en aquesta llista de reproducció que coincideixi amb la teva cerca\nHistory:\n  # On History Page\n  History: 'Historial'\n  Watch History: 'Veure l''historial'\n  Your history list is currently empty.: 'El teu historial està actualment buit.'\n  Search bar placeholder: Cerca a l'historial\n  Empty Search Message: No hi ha cap vídeo a l'historial que coincideixi amb la cerca\nSettings:\n  # On Settings Page\n  Settings: 'Configuració'\n  General Settings:\n    General Settings: 'Paràmetres generals'\n    Check for Updates: 'Comprovar si hi ha actualitzacions'\n    Check for Latest Blog Posts: 'Consultar les darreres entrades al blog'\n    Fallback to Non-Preferred Backend on Failure: 'Torna al motor per defecte en cas d''error'\n    Enable Search Suggestions: 'Habilitar els suggeriments de cerca'\n    Default Landing Page: 'Pàgina d''aterratge per defecte'\n    Locale Preference: 'Preferència de configuració regional'\n    Preferred API Backend:\n      Preferred API Backend: 'Motor de l''API preferit'\n      Local API: 'API local'\n      Invidious API: 'API d''Invidious'\n    Video View Type:\n      Video View Type: 'Tipus de vista de vídeo'\n      Grid: 'Quadrícula'\n      List: 'Llista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferència de miniatura'\n      Default: 'Per defecte'\n      Beginning: 'Inici'\n      Middle: 'Mig'\n      End: 'Final'\n    Region for Trending: 'Regió per a les tendències'\n        #! List countries\n    View all Invidious instance information: Mostra tota la informació de la instància Invidious\n    System Default: Per defecte del sistema\n    Clear Default Instance: Esborra la instància per defecte\n    Current Invidious Instance: Instància actual d'Invidious\n    The currently set default instance is {instance}: La instància per defecte establerta actualment és {instance}\n    No default instance has been set: No s'ha definit cap instància per defecte\n    External Link Handling:\n      Open Link: Obre l'enllaç\n      External Link Handling: Gestió d'enllaços externs\n      Ask Before Opening Link: Pregunta abans d'obrir l'enllaç\n      No Action: Sense acció\n    Current instance will be randomized on startup: La instància actual es farà aleatòriament a l'inici\n    Set Current Instance as Default: Defineix l'actual com a instància per defecte\n  Theme Settings:\n    Theme Settings: 'Paràmetres del tema'\n    Match Top Bar with Main Color: 'Fer coincidir la barra superior amb el color principal'\n    Base Theme:\n      Base Theme: 'Tema de base'\n      Black: 'Negre'\n      Dark: 'Fosc'\n      Light: 'Clar'\n      Dracula: 'Dràcula'\n      System Default: Valor per defecte del sistema\n    Main Color Theme:\n      Main Color Theme: 'Tema principal del color'\n      Red: 'Vermell'\n      Pink: 'Rosa'\n      Purple: 'Porpra'\n      Deep Purple: 'Porpra profunda'\n      Indigo: 'Indi'\n      Blue: 'Blau'\n      Light Blue: 'Blau clar'\n      Cyan: 'Cian'\n      Teal: 'Blau xarxet'\n      Green: 'Verd'\n      Light Green: 'Verd clar'\n      Lime: 'Llima'\n      Yellow: 'Groc'\n      Amber: 'Ambre'\n      Orange: 'Taronja'\n      Deep Orange: 'Taronja fosc'\n      Dracula Cyan: 'Dràcula Cian'\n      Dracula Green: 'Dràcula Verd'\n      Dracula Orange: 'Dràcula Taronja'\n      Dracula Pink: 'Dràcula Rosa'\n      Dracula Purple: 'Dràcula Porpra'\n      Dracula Red: 'Dràcula Vermell'\n      Dracula Yellow: 'Dràcula Groc'\n    Secondary Color Theme: 'Tema de color secundari'\n        #* Main Color Theme\n    Expand Side Bar by Default: Expandeix la barra lateral per defecte\n    UI Scale: Escala de la interfície gràfica\n    Disable Smooth Scrolling: Desactiva el desplaçament suau\n    Hide Side Bar Labels: Oculta les etiquetes de la barra lateral\n  Player Settings:\n    Player Settings: 'Configuració del reproductor'\n    Play Next Video: 'Reprodueix el vídeo següent'\n    Turn on Subtitles by Default: 'Activa els subtítols per defecte'\n    Autoplay Videos: 'Reprodueix automàticament els vídeos'\n    Proxy Videos Through Invidious: 'Fes servir Invidious com a intermediari per baixar els vídeos'\n    Autoplay Playlists: 'Reprodueix automàticament les llistes de reproducció'\n    Enable Theatre Mode by Default: 'Activa el mode teatre per defecte'\n    Default Volume: 'Volum per defecte'\n    Default Playback Rate: 'Velocitat de reproducció predeterminada'\n    Default Video Format:\n      Default Video Format: 'Format de vídeo predeterminat'\n      Dash Formats: 'Formats DASH'\n      Legacy Formats: 'Formats antics'\n      Audio Formats: 'Formats d''àudio'\n    Default Quality:\n      Default Quality: 'Qualitat per defecte'\n      Auto: 'Automàtic'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Scroll Volume Over Video Player: Canvia el volum amb la roda del ratolí sobre el vídeo\n    Display Play Button In Video Player: Mostra el botó de reproducció al reproductor de vídeo\n    Next Video Interval: Interval de vídeo següent\n    Scroll Playback Rate Over Video Player: Canvia la velocitat de reproducció amb la roda del ratolí sobre el vídeo\n    Fast-Forward / Rewind Interval: Interval d'Avançament / Retrocés Ràpid\n    Max Video Playback Rate: Velocitat màxima de reproducció de vídeo\n    Video Playback Rate Interval: Interval de velocitat de reproducció de vídeo\n  Privacy Settings:\n    Privacy Settings: 'Configuració de la Privacitat'\n    Remember History: 'Recorda l''historial'\n    Save Watched Progress: 'Desa progrés reproduït'\n    Clear Search Cache: 'Elimina la memòria cau de cerca'\n    Are you sure you want to clear out your search cache?: 'Estàs segur que vols eliminar la memòria cau de la cerca?'\n    Search cache has been cleared: 'La memòria cau de la cerca s''ha eliminat'\n    Remove Watch History: 'Elimina l''historial de reproduccions'\n    Are you sure you want to remove your entire watch history?: 'Estàs segur que vols eliminar tot l''historial de reproduccions?'\n    Watch history has been cleared: 'L''historial de reproduccions s''ha eliminat'\n    Remove All Subscriptions / Profiles: 'Elimina totes les subscripcions / perfils'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Esteu segur que voleu esborrar totes les subscripcions i perfils?  Aquesta acció no es pot desfer.'\n  Subscription Settings:\n    Subscription Settings: 'Configuració de les subscripcions'\n    Fetch Feeds from RSS: 'Recupera els canals de continguts des de l''RSS'\n  Data Settings:\n    Data Settings: 'Configuració de les dades'\n    Select Export Type: 'Selecciona tipus d''exportació'\n    Import Subscriptions: 'Importa les subscripcions'\n    Export Subscriptions: 'Exporta subscripcions'\n    Export FreeTube: 'Exporta FreeTube'\n    Export YouTube: 'Exporta YouTube'\n    Export NewPipe: 'Exporta NewPipe'\n    Import History: 'Importa l''historial'\n    Export History: 'Exporta l''historial'\n    Profile object has insufficient data, skipping item: 'Aquest perfil no té dades suficients, ometent l''objecte'\n    All subscriptions and profiles have been successfully imported: 'Totes les subscripcions i perfils s''han importat amb èxit'\n    All subscriptions have been successfully imported: 'Totes les subscripcions s''han importat amb èxit'\n    Invalid subscriptions file: 'Fitxer de subscripcions invàlid'\n    Invalid history file: 'Fitxer d''historial invàlid'\n    Subscriptions have been successfully exported: 'Les subscripcions s''han exportat amb èxit'\n    History object has insufficient data, skipping item: 'L''objecte de l''historial no té suficient informació, saltant l''objecte'\n    All watched history has been successfully imported: 'Tot l''historial visualitzat s''ha importat amb èxit'\n    All watched history has been successfully exported: 'Tot l''historial visualitzat s''ha exportat amb èxit'\n    Unable to read file: 'Impossible llegir el fitxer'\n    Unable to write file: 'Impossible escriure el fitxer'\n    Unknown data key: 'Clau de dades desconegut'\n    How do I import my subscriptions?: 'Com puc importar les meves subscripcions?'\n    Playlist insufficient data: Dades insuficients per a la llista de reproducció \"{playlist}\", saltant l'objecte\n    Manage Subscriptions: Gestiona les subscripcions\n    Import Playlists: Importa llistes de reproducció\n    All playlists has been successfully exported: Totes les llistes de reproducció s'han exportat amb èxit\n    Export Playlists: Exporta llistes de reproducció\n    All playlists has been successfully imported: Totes les llistes de reproducció s'han importat amb èxit\n  The app needs to restart for changes to take effect. Restart and apply change?: Cal reiniciar l'aplicació perquè els canvis tinguin efecte. Vols reiniciar i aplicar els canvis?\n  External Player Settings:\n    External Player Settings: Configuració del reproductor extern\n    External Player: Reproductor extern\n    Ignore Unsupported Action Warnings: Ignora els advertiments d'acció no compatible\n    Custom External Player Executable: Executable de reproductor extern personalitzat\n    Custom External Player Arguments: Arguments personalitzats del reproductor extern\n  Proxy Settings:\n    Proxy Settings: Configuració del servidor intermediari\n    Clicking on Test Proxy will send a request to: En fer clic a \"Prova el servidor intermediari\" s'enviarà una sol·licitud a\n    Ip: IP\n    Country: País\n    Error getting network information. Is your proxy configured properly?: Error en obtenir informació de la xarxa. El servidor intermediari està ben configurat?\n    Region: Regió\n    City: Ciutat\n    Proxy Port Number: Port del servidor intermediari\n    Test Proxy: Prova el servidor intermediari\n    Enable Tor / Proxy: Activa Tor / Servidor intermediari\n    Proxy Host: Amfitrió del servidor intermediari\n    Your Info: La teva informació\n    Proxy Protocol: Protocol del servidor intermediari\n  SponsorBlock Settings:\n    Enable SponsorBlock: Activa l'SponsorBlock\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL de l'API de SponsorBlock (per defecte és https://sponsor.ajay.app)\n    SponsorBlock Settings: Configuració de l'SponsorBlock\n    Notify when sponsor segment is skipped: Notificar quan se salta un segment esponsoritzat\n  Distraction Free Settings:\n    Hide Recommended Videos: Amaga els vídeos recomanats\n    Hide Trending Videos: Amaga els vídeos en tendència\n    Hide Playlists: Amaga les llistes de reproducció\n    Hide Live Chat: Amaga el xat en viu\n    Hide Active Subscriptions: Amaga les subscripcions actives\n    Hide Video Views: Amaga les visualitzacions del vídeo\n    Hide Video Likes And Dislikes: Amaga els \"M'agrada\" i els \"No m'agrada\" del vídeo\n    Hide Channel Subscribers: Amaga les subscripcions del canal\n    Hide Comment Likes: Amaga els \"M'agrada\" dels comentaris\n    Distraction Free Settings: Configuració del mode sense distraccions\n    Hide Popular Videos: Amaga els vídeos populars\n    Hide Videos on Watch: 'Oculta els vídeos visualitzats'\n\nAbout:\n  #On About page\n  About: 'Quant a'\n  #& About\n  Blog: Blog\n  Website: Lloc web\n  Email: Correu-e\n  Help: Ajuda\n  Downloads / Changelog: Descàrregues / Registre de canvis\n  Chat on Matrix: Xat a Matrix\n  room rules: normes de la sala\n  these people and projects: aquesta gent i projectes\n  Source code: Codi font\n  GitHub issues: Incidències del GitHub\n  Beta: Beta\n  Please check for duplicates before posting: Si us plau, abans de publicar comprova no duplicar temes\n  Credits: Crèdits\n  FAQ: PMF\n  Report a problem: Informa d'un problema\n  Mastodon: Mastodon\n  Donate: Dona\n  Translate: Tradueix\n  GitHub releases: Llançaments del GitHub\n  FreeTube Wiki: FreeTube Wiki\nProfile:\n  Profile Select: 'Selecciona perfil'\n  All Channels: 'Tots els canals'\n  Profile Manager: 'Gestor de perfils'\n  Create New Profile: 'Crea un Nou Perfil'\n  Edit Profile: 'Editar el perfil'\n  Color Picker: 'Selector de colors'\n  Custom Color: 'Color personalitzat'\n  Profile Preview: 'Vista prèvia del perfil'\n  Create Profile: 'Crear un perfil'\n  Update Profile: 'Actualitzar el perfil'\n  Make Default Profile: 'Establir un perfil per defecte'\n  Delete Profile: 'Suprimir el perfil'\n  Are you sure you want to delete this profile?: 'Estàs segur que vols suprimir aquest perfil?'\n  All subscriptions will also be deleted.: 'També se suprimiran totes les subscripcions.'\n  Your profile name cannot be empty: 'El nom del perfil no pot estar buit'\n  Profile has been created: 'S''ha creat el perfil'\n  Profile has been updated: 'S''ha actualitzat el perfil'\n  Your default profile has been set to {profile}: 'El vostre perfil predeterminat s''ha establert a {profile}'\n  Removed {profile} from your profiles: 'S''ha eliminat {profile} dels teus perfils'\n  Your default profile has been changed to your primary profile: 'El perfil per defecte s''ha canviat al perfil principal'\n  '{profile} is now the active profile': '{profile} és ara el perfil actiu'\n  Subscription List: 'Llista de subscripcions'\n  Other Channels: 'Altres Canals'\n  '{number} selected': '{number} seleccionat'\n  Select All: 'Selecciona Tot'\n  Select None: 'Selecciona Ningú'\n  Delete Selected: 'Suprimeix els seleccionats'\n  Add Selected To Profile: 'Afegeix Seleccionats al Perfil'\n  No channel(s) have been selected: 'Cap canal s''ha seleccionat'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Aquest és el perfil principal.  Esteu segur que voleu suprimir els canals seleccionats?   Se suprimiran de tots els perfils.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Esteu segur que voleu suprimir els canals seleccionats?  No se suprimiran de cap altre perfil.'\n#On Channel Page\n  Profile Settings: Configuració del perfil\n  Profile Filter: Filtre de perfil\nChannel:\n  Subscribe: 'Subscriu-te'\n  Unsubscribe: 'Cancel·la la subscripció'\n  Channel has been removed from your subscriptions: 'El canal s''ha eliminat de les teves subscripcions'\n  Removed subscription from {count} other channel(s): 'S''ha suprimit la subscripció dels altres {count} canals'\n  Added channel to your subscriptions: 'Afegeix canal a les teves subscripcions'\n  Search Channel: 'Cerca Canal'\n  Your search results have returned 0 results: 'Els resultats de la teva cerca han retornat 0 resultats'\n  Videos:\n    Videos: 'Vídeos'\n    This channel does not currently have any videos: 'Aquest canal no té actualment cap vídeo'\n    Sort Types:\n      Newest: 'Més Nou'\n      Oldest: 'Més Vell'\n      Most Popular: 'Més Popular'\n  Playlists:\n    Playlists: 'Llistes De Reproducció'\n    This channel does not currently have any playlists: 'Aquest canal no té actualment cap llista de reproducció'\n    Sort Types:\n      Last Video Added: 'Últim Vídeo Afegit'\n      Newest: 'Més Nou'\n      Oldest: 'Més Vell'\n  About:\n    About: 'Quant a'\n    Channel Description: 'Descripció del Canal'\n    Featured Channels: 'Canals Destacats'\nVideo:\n  Mark As Watched: 'Marca Com A Vist'\n  Remove From History: 'Suprimeix de l''historial'\n  Video has been marked as watched: 'El vídeo ha sigut marcat com a vist'\n  Video has been removed from your history: 'El vídeo ha sigut eliminat del teu historial'\n  Open in YouTube: 'Obri a YouTube'\n  Copy YouTube Link: 'Copia Enllaç de YouTube'\n  Open YouTube Embedded Player: 'Obri Reproductor de YouTube Incrustat'\n  Copy YouTube Embedded Player Link: 'Copia l''enllaç del reproductor de YouTube incrustat'\n  Open in Invidious: 'Obra a Invidious'\n  Copy Invidious Link: 'Copia l''enllaç d''Invidious'\n  Views: 'Visualitzacions'\n  Loop Playlist: 'Llista de reproducció en bucle'\n  Shuffle Playlist: 'Llista de reproducció en aleatori'\n  Reverse Playlist: 'Llista de reproducció invertida'\n  Previous: Anterior\n  Next: Següent\n  Watched: 'Visualitzat'\n  Autoplay: 'Reproducció Automàtica'\n  # As in a Live Video\n  Live: 'Directe'\n  Live Now: 'Ara en directe'\n  Live Chat: 'Xat en directe'\n  Enable Live Chat: 'Activa el xat en directe'\n  Live Chat is currently not supported in this build.: 'No s’admet el xat en directe en aquesta construcció.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'El Xat En Directe està activat. Els missatges del Xat apareixeran ací una vegada s''envien.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'El xat en directe no està actualment suportat per l''API d''Invidious.  Es requereix una connexió directa a YouTube.'\n  Published on: 'Publicat el'\n#& Videos\n  Started streaming on: Retransmissió iniciada el\n  Sponsor Block category:\n    interaction: interacció\n    sponsor: patrocinador\n    music offtopic: música fora de tema\n    intro: introducció\n    outro: conclusió\n    self-promotion: autopromoció\n  External Player:\n    Unsupported Actions:\n      starting video at offset: començant el vídeo al punt donat\n      setting a playback rate: establint una velocitat de reproducció\n    OpenInTemplate: Obri a {externalPlayer}\n    OpeningTemplate: Obrint {videoOrPlaylist} a {externalPlayer}…\n    video: vídeo\n    playlist: llista de reproducció\n    UnsupportedActionTemplate: '{externalPlayer} no suporta: {action}'\n  Save Video: Desa el Vídeo\n  Video has been saved: El vídeo s'ha desat\n  Video has been removed from your saved list: S'ha suprimit el vídeo de la llista desada\n  Open Channel in YouTube: Obri Canal a YouTube\n  Copy YouTube Channel Link: Copia l'enllaç del canal de YouTube\n  Open Channel in Invidious: Obra el canal a Invidious\n  Copy Invidious Channel Link: Copia l'enllaç del canal d'Invidious\n  Starting soon, please refresh the page to check again: Començant prompte, si us plau recàrrega la pàgina per comprovar-ho de nou\n  Streamed on: Retransmès en directe el\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Visualitza la llista de reproducció sencera'\n  Last Updated On: 'Última Actualització'\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: 'Canvia Els Formats De Vídeo'\n  Use Dash Formats: 'Utilitza Formats DASH'\n  Use Legacy Formats: 'Utilitza els formats llegats'\n  Use Audio Formats: 'Utilitza els formats d’àudio'\n  Dash formats are not available for this video: 'Els formats DASH no són disponibles per aquest vídeo'\n  Audio formats are not available for this video: 'Els formats d''audio no són disponibles per aquest vídeo'\nShare:\n  Share Video: 'Comparteix Vídeo'\n  Share Playlist: 'Comparteix la llista de reproducció'\n  Include Timestamp: 'Afegeix Marca De Temps'\n  Copy Link: 'Copia l''Enllaç'\n  Open Link: 'Obri l''Enllaç'\n  Copy Embed: 'Copia Incrustat'\n  Open Embed: 'Obri Incrustat'\n  # On Click\n  Invidious URL copied to clipboard: 'S''ha copiat l''URL d''Invidious al porta-retalls'\n  Invidious Embed URL copied to clipboard: 'S''ha copiat l''URL d''incrustació d''Invidious al porta-retalls'\n  YouTube URL copied to clipboard: 'URL de YouTube copiada al porta-retalls'\n  YouTube Embed URL copied to clipboard: 'URL d''Incrustació de YouTube copiada al porta-retalls'\n  Invidious Channel URL copied to clipboard: S'ha copiat l'URL del canal d'Invidious al porta-retalls\nYes: 'Sí'\nNo: 'No'\nMore: Més\nOpen New Window: Obre una finestra nova\nSearch Bar:\n  Clear Input: Netejar\nAre you sure you want to open this link?: Estàs segur/a que vols obrir aquest enllaç?\nNew Window: Finestra nova\nPreferences: Preferències\nChannels:\n  Search bar placeholder: Cerca canals\n  Channels: Canals\n  Title: Llista de canals\nFalling back to Invidious API: Recorrent a l'API d'Invidious\nInvidious API Error (Click to copy): S'ha produït un error en l'API d'Invidious (feu clic per copiar-lo)\nMoments Ago: fa un moment\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\n    Subtitles: Subtítols\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Activa les eines per a desenvolupadors\n  Zoom In: Amplia\n  Zoom Out: Allunya\n  Fullscreen: Commuta la pantalla completa\nCompact side navigation: Navegació lateral compacta\nExpand side navigation: Expandir navegació lateral\nRight-click or hold to see history: Clic dret o manté pressionat per veure l'historial\nGo to page: Ves a {page}\nClose Banner: Tanca el bàner\n"
  },
  {
    "path": "static/locales/ckb.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ئینگلیزی (وڵاتە یەکگرتووەکانی ئەمریکا)'\n\n# Webkit Menu Bar\nFile: 'پەڕگە'\nNew Window: 'پەنجەرەی نوێ'\nPreferences: 'هەڵبژاردەکان'\nQuit: 'دەرچوون'\nEdit: 'دەستکاری'\nUndo: 'پووچکردنەوە'\nRedo: 'کردنەوە'\nCut: 'بڕین'\nCopy: 'لەبەرگرتنەوە'\nPaste: 'لکاندن'\nDelete: 'سڕینەوە'\nSelect all: 'دیاریکردنی گشتیان'\nToggle Developer Tools: 'زامنی ئامرازەکانی گەشەپێدەر'\nActual size: 'قەبارەی ڕاستەقینە'\nZoom in: ''\nZoom out: ''\nToggle fullscreen: ''\nWindow: 'پەنجەرە'\nMinimize: ''\nClose: 'داخستن'\nBack: 'دواوە'\nForward: 'پێشەوە'\nOpen New Window: 'کردنەوەی پەنجەرەیەکی نوێ'\n\nVersion {versionNumber} is now available!  Click for more details: 'ئێستا وەشانی {versionNumber} بەردەستە..بۆ زانیاری زۆرتر کرتە بکە'\nDownload From Site: 'لە وێبگەوە دایگرە'\nA new blog is now available, {blogTitle}. Click to view more: 'بلۆگێکی نوێ بەردەستە، {blogTitle}. کرتە بکە بۆ بینینی'\nAre you sure you want to open this link?: 'دڵنیایت دەتەوێت ئەم بەستەرە بکەیتەوە؟'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'ڤیدیۆکان'\n  Shorts: 'کورتەڤیدیۆکان'\n  Live: 'ڕاستەوخۆ'\n  Sort By: 'ڕیزکردن بە'\n  Counts:\n    Video Count: '١ ڤیدیۆ | {count} ڤیدیۆ'\n    Channel Count: '١ کەناڵ | {count} کەناڵ'\n    Subscriber Count: '١ بەشداربوو | {count} بەشداربوو'\n    View Count: 'بینینەک | {count} بینین'\n    Watching Count: '١ تەمەشاکردن | {count} تەمەشاکردن'\n\n# Search Bar\n    Comment Count: ١ توانج | {count} توانج\n    Like Count: ١ بەدڵبوون | {count} بەدڵبوون\n  Posts: بڵاوکراوەکان\nSearch / Go to URL: 'گەڕان/ بڕۆ بۆ ئرڵ'\nSearch Bar:\n  Clear Input: 'سڕینەوەی نووسراو'\n  # In Filter Button\n  Remove: لابردن\nSearch Filters:\n  Search Filters: 'پاڵفتەکردنی گەڕان'\n  Sort By:\n    Most Relevant: 'پەیوەندیدار'\n    Rating: 'هەڵسەنگاندن'\n    Upload Date: 'ڕێکەوتی بارکردن'\n    View Count: 'ژمارەی بینین'\n  Time:\n    Time: 'کات'\n    Any Time: 'هەر کاتێک'\n    Last Hour: 'پێش کاتژمێرێک'\n    Today: 'ئەمڕۆ'\n    This Week: 'ئەم هەفتەیە'\n    This Month: 'ئەم مانگە'\n    This Year: 'ئەمساڵ'\n  Type:\n    Type: 'جۆر'\n    All Types: 'گشت جۆرەکان'\n    Videos: 'ڤیدیۆ'\n    Channels: 'کەناڵ'\n    Movies: 'فیلم'\n    #& Playlists\n  Duration:\n    Duration: 'ماوە'\n    All Durations: 'گشت ماوەکان'\n    Short (< 4 minutes): 'کورت (< ٤ خولەک)'\n    Medium (4 - 20 minutes): 'ناوەند (٤ - ٢٠ خولەک)'\n    Long (> 20 minutes): 'درێژ (> ٢٠ خولەک)'\n  # On Search Page\n  Search Results: 'ئەنجامەکانی گەڕان'\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: 'ئەنجامەکی تر نییە بۆ ئەم گەڕانە'\n# Sidebar\n  Features:\n    Location: شوێن\n    3D: ٣ ڕەهەندی\n    Subtitles: ژێرنووس\n    Live: ڕاستەوخۆ\n    4K: ٤ک\n    360 Video: ڤیدیۆی ٣٦٠°\n    VR180: VR١٨٠\n    Features: تایبەتمەندییەکان\n    HD: HD\n    HDR: HDR\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: 'کەناڵە بەشداربووەکانت هێشتا هیچ ڤیدیۆیەکیان نییە.'\n  Empty Posts: 'کەناڵە بەشداربووەکانت هێشتا هیچ بڵاوکراوەیەکیان نییە.'\n  Load More Videos: 'ڤیدیۆی زۆرتر بار بکە'\n  Load More Posts: 'بڵاوکراوەی زۆرتر بار بکە'\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: 'زۆرتر'\nChannels:\n  Channels: 'کەناڵەکان'\n  Title: 'پێڕستی کەناڵەکان'\n  Search bar placeholder: 'گەڕان لە کەناڵەکان'\n  Count: '{number} کەناڵ دۆزرانەوە.'\n  Empty: 'ئێستا پێڕستی کەناڵەکانت بەتاڵە.'\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: 'باو'\n  Gaming: 'یاری'\n  Trending Tabs: ''\n  Sports: وەرزش\nMost Popular: 'باوترین'\nPlaylists: 'پێڕستی لێدانەکان'\nUser Playlists:\n  Your Playlists: 'پێڕستی لێدانەکانت'\n  Empty Search Message: 'لەم پێڕستی لێدانەدا هیچ ڤیدیۆیەک هاوتای گەڕانەکەت نییە'\n  Search bar placeholder: 'بۆ پێڕستی لێدان بگەڕێ'\n  Move Video Up: ڤیدیۆکە ببە سەرتر\n  Move Video Down: ڤیدیۆکە ببە خوارتر\n  Add to Favorites: بۆ {playlistName}، زیاد بکە\n  Remove from Favorites: لە {playlistName}، لایببە\n  Cancel: هەڵوەشاندنەوە\n  Save Changes: دەستکارییەکان پاشەکەوت بکە\n  Remove Watched Videos: ڤیدیۆ بینراوەکان دەرکە\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved down.: ئەم ڤیدیۆیە نابرێتە خوارتر.\n      There was a problem with removing this video: گرفتێک لە لابردنی ڤیدیۆکە هەیە\n      This video cannot be moved up.: ئەم ڤیدیۆیە نابرێتە سەرتر.\n      Video has been removed: ڤیدیۆکە لابرا\n      This playlist does not exist: ئەم پێڕستی لێدانە بوونی نییە\n      Playlist {playlistName} has been deleted.: پێڕستی لێدانی {playlistName} سڕایەوە.\n      There were no videos to remove.: هیچ ڤیدیۆیەک نییە هەتا لاببرێت.\n      This playlist is protected and cannot be removed.: ئەم پێڕستی لێدانە پارێزراوە و لانابرێت.\n      Playlist name cannot be empty. Please input a name.: پێڕستی لێدان نابێت بێ ناو بێت. تکایە ناوێک بنووسە.\n      There was an issue with updating this playlist.: هەڵەیەک ڕوویدا لە نوێکردنەوەی ئەم پێڕستی لێدانە.\n      Playlist has been updated.: پێڕستی لێدان نوێ کرایەوە.\n      \"{videoCount} video(s) have been removed\": ١ ڤیدیۆ لابرا | {videoCount} ڤیدیۆ لابرا\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: هەندێک لە ڤیدیۆکانی ناو پێڕستی لێدانەکە هێشتا بار نەکراون. بۆ لەبەرگرتنەوەی کرتە لێرە بکە.\n      Video has been removed. Click here to undo.: ڤیدیۆکە لابرا. کرتە لێرە بکە بۆ گەڕاندنەوەی.\n    Search for Videos: لە ڤیدیۆ بگەڕێ\n  Sort By:\n    NameAscending: ئ-ێ\n    NameDescending: ێ-ئ\n    EarliestCreatedFirst: زوو درووستکراو\n    LatestUpdatedFirst: دوایین نوێ کراوە\n    LatestPlayedFirst: دوایین لێدراو\n    EarliestPlayedFirst: زوو لێدراو\n    LatestCreatedFirst: دوایین درووستکراو\n    EarliestUpdatedFirst: زوو نوێ کراوە\n  Remove Duplicate Videos: ڤیدیۆی پاتە دەرکە\n  Add to Playlist: زیادکردن بۆ پێڕستی لێدان\n  Edit Playlist Info: دەستکاری کردنی زانیارییەکانی پێڕستی لێدان\n  Delete Playlist: سڕینەوەی پێڕستی لێدان\n  This playlist currently has no videos.: ئەم پێڕستی لێدانە هیچ ڤیدیۆیەکی تێدا نییە.\n  You have no playlists. Click on the create new playlist button to create a new one.: هیچ پێڕستەکی لێدانت نییە. کرتە لەسەر دوگمەی درووستکردنی پێڕستی نوێ بکە بۆ دانەیەکی نوێ.\n  Export Playlist: هەناردنی ئەم پێڕستی لێدانە\n  The playlist has been successfully exported: پێڕستی لێدانەکە بە سەرکەوتووی هەناردرا\n  Create New Playlist: درووستکردنی پێڕستێکی لێدانی نوێ\n  Remove from Playlist: لە پێڕستی لێدانی لاببە\n  Playlist Name: ناوی پێڕستی لێدان\n  Copy Playlist: لەبەرگرتنەوەی پێڕستی لێدان\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: پێڕستێکی لێدان هەڵبژێرە بۆ زیاد کردنی ڤیدیۆ بۆی | پێڕستێکی لێدان هەڵبژێرە بۆ زیاد کردنی {videoCount} ڤیدیۆ بۆی\n    Save: پاشەکەوتکردن\n    Added {count} Times: زیادکراوە | {count} جار زیادکراوە\n    Search in Playlists: گەڕان لەناو پێڕستی لێدانەکان\n    Toast:\n      You haven't selected any playlist yet.: هێشتا هیچ پێڕستێکی لێدانت دیاری نەکردووە.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Allow Adding Duplicate Video(s): ڕێ بە زیادکردنی ڤیدیۆی دووبارە بدە\n    N playlists selected: '{playlistCount} دیاریکراوە'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} ڤیدیۆ زیاد دەکرێتن'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} ڤیدیۆ زیاد کراینە'\n  CreatePlaylistPrompt:\n    New Playlist Name: ناوی پێڕستی لێدانی نوێ\n    Create: درووستکردن\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: پێڕستی تر بەم ناوە هەیە، تکایە ناوێکی جوایەز بنووسە.\n      Playlist {playlistName} has been successfully created.: پێڕستی لێدانی {playlistName} بە سەرکەوتوویی درووست کرا.\n      There was an issue with creating the playlist.: هەڵەیەک ڕوویدا لە درووستکردنی پێڕستی لێدانەکە.\n  Are you sure you want to delete this playlist? This cannot be undone: دڵنیایت لە سڕینەوەی ئەم پێڕستی لێدانە؟ چونکە ناگەڕێندرێتەوە.\n  Playlist Description: پێناسەی پێڕستی لێدان\n  Playlists with Matching Videos: پێڕستەکانی لێدان لەگەڵ ڤیدیۆ هاوتاکان\n  TotalTimePlaylist: 'سەرجەمی کات: {duration}'\nHistory:\n  # On History Page\n  History: 'مێژوو'\n  Watch History: 'مێژووی تەمەشاکردن'\n  Your history list is currently empty.: 'ئێستا لیستەی مێژووت بەتاڵە.'\n  Empty Search Message: 'هیچ ڤیدیۆیەک لە مێژووت نەدۆزرایەوە کە بەرانبەری گەڕانەکەت بێت'\n  Search bar placeholder: \"لەناو مێژوو بگەڕێ\"\nSettings:\n  # On Settings Page\n  Settings: 'ڕێکخستنەکان'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'دەبێت کاربەرنامەکە دابخرێت و بکرێتەوە بۆ ئەوەی گۆڕانەکان جێی خۆیان بگرن. دەتەوێت دابخەیت و بیکەیتەوە بۆ ئەوەی گۆڕانەکان بکرێن؟'\n  General Settings:\n    General Settings: 'گشتیی'\n    Check for Updates: 'بۆ وەشانی نوێ بپشکنە'\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: 'کاراکردنی پێشنیارەکانی گەڕان'\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: 'بنەڕەتی سیستەم'\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: 'خانەخانە'\n      List: 'لیستە'\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: 'بنەڕەت'\n      Beginning: 'سەرەتا'\n      Middle: 'ناوەڕاست'\n      End: 'کۆتایی'\n      Hidden: 'شاراوە'\n      Blur: 'لێڵ'\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: 'کردنەوەی بەستەر'\n      Ask Before Opening Link: 'پێش کردنەوەی بەستەر بپرسە'\n      No Action: 'هیچ مەکە'\n    Auto Load Next Page:\n      Tooltip: خۆکارانە پەڕە و لێدوانی زۆرتر بار بکە.\n      Label: خۆکارانە پەڕەی دواتر بار بکە\n  Theme Settings:\n    Theme Settings: 'ڕووکار'\n    Match Top Bar with Main Color: 'شریتی سەرەوە هاوتای ڕەنگی سەرەکی بکە'\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: 'ڕووکاری بنچینە'\n      Black: 'ڕەش'\n      Dark: 'تاریک'\n      System Default: 'بنەڕەتی سیستەم'\n      Light: 'ڕووناک'\n      Dracula: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n    Main Color Theme:\n      Main Color Theme: 'ڕەنگی سەرەکی ڕووکار'\n      Red: 'سوور'\n      Pink: 'پەمبە'\n      Purple: 'وەنەوشەیی'\n      Deep Purple: 'وەنەوشەیی تۆخ'\n      Indigo: 'نیلی'\n      Blue: 'شین'\n      Light Blue: 'شینی ئاڵ'\n      Cyan: 'شینی تۆخ'\n      Teal: 'شەدری'\n      Green: 'کەسک'\n      Light Green: 'کەسکی ئاڵ'\n      Lime: ''\n      Yellow: 'زەرد'\n      Amber: ''\n      Orange: 'نارنجی'\n      Deep Orange: 'نارنجی تۆخ'\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n    Secondary Color Theme: 'ڕەنگی لاوەکی ڕووکار'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'لێدەر'\n    Play Next Video: 'خۆلێدانی ڤیدیۆی پێشنیارکراو'\n    Turn on Subtitles by Default: 'هەڵکردنی ژێرنووس بە بنەڕەت'\n    Autoplay Videos: 'دەستپێکردنی خۆکارانەی ڤیدیۆ'\n    Proxy Videos Through Invidious: ''\n    Autoplay Playlists: 'خۆلێدانی پێڕستی لێدان'\n    Enable Theatre Mode by Default: 'کاراکردنی بنەڕەتیی شێوازی شانۆیی'\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: 'پیشاندانی دوگمەی لێدان لەناو لێدەری ڤیدیۆ'\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: 'جۆرایەتی بنەڕەت'\n      Auto: 'خۆکار'\n      144p: '١٤٤پ'\n      240p: '٢٤٠پ'\n      360p: '٣٦٠پ'\n      480p: '٤٨٠پ'\n      720p: '٧٢٠پ'\n      1080p: '١٠٨٠پ'\n      1440p: '١٤٤٠پ'\n      4k: '٤k'\n      8k: '٨k'\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: 'بۆ بوخچەی پاشەکەوت بپرسە'\n      Folder Label: ''\n      Folder Button: 'دیاریکردنی بوخچە'\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: 'خانەی ناوی پەڕگە بەتاڵە'\n    Default Viewing Mode:\n      Theater: شانۆ\n      Default Viewing Mode: شێوازی بینینی بنەڕەت\n      External Player: لێدەری دەرەکی ({externalPlayerName})\n  External Player Settings:\n    External Player Settings: 'لێدەری دەرەکی'\n    External Player: 'لێدەری دەرەکی'\n    Ignore Unsupported Action Warnings: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: 'هیچیان'\n  Privacy Settings:\n    Privacy Settings: 'تایبەتمەندێتی'\n    Remember History: 'مێژووی تەمەشاکردن هەڵگرە'\n    Save Watched Progress: 'ڕەوتی تەمەشا کراو پاشەکەوت بکە'\n    Save Watched Videos With Last Viewed Playlist: 'ڤیدیۆ تەمەشاکراوەکان لەگەڵ دوایین پێڕستی لێدانی بینراو پاشەکەوت بکە'\n    Clear Search Cache: ''\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: ''\n    Remove Watch History: 'سڕینەوەی مێژووی تەمەشاکردن'\n    Are you sure you want to remove your entire watch history?: 'دڵنیایت دەتەوێت تەواوی مێژووی تەمەشاکردنت بسڕیەوە؟'\n    Watch history has been cleared: 'مێژووی تەمەشاکردن سڕایەوە'\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Clear Search History and Cache: حەشارگە و مێژووی گەڕان بسڕەوە\n    Remember Search History: مێژووی گەڕان هەڵگرە\n    Remove All Playlists: سڕینەوەی گشت پێڕستەکانی لێدان\n    All playlists have been removed: هەموو پێڕستەکانی لێدان سڕایەوە\n    Are you sure you want to clear out your search history and cache?: دڵنیایت لە سڕینەوەی حەشارگە و مێژووی گەڕان؟\n    Search history and cache have been cleared: حەشارگە و مێژووی گەڕان سڕایەوە\n    Are you sure you want to remove all your playlists?: دڵنیایت لە سڕینەوەی هەموو پێڕستەکانی لێدان؟\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: خۆکار\n        Semi-auto: نیمچە خۆکار\n        Never: هەرگیز\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    To: بۆ\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: 'لامیل'\n      Subscriptions Page: ''\n      Channel Page: 'پەڕەی کەناڵ'\n      Watch Page: 'پەڕەی تەمەشاکردن'\n      General: 'گشتی'\n    Hide Video Views: 'شاردنەوەی ژمارەی بینینەکانی ڤیدیۆ'\n    Hide Video Likes And Dislikes: 'شاردنەوەی بەدڵبوون و نەبوونی ڤیدیۆ'\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: 'شاردنەوەی بەدڵبوونەکانی سەرنج'\n    Hide Recommended Videos: 'شاردنەوەی ڤیدیۆ پێشنیازکراوەکان'\n    Hide Trending Videos: 'شاردنەوەی ڤیدیۆ باوەکان'\n    Hide Popular Videos: 'شاردنەوەی ڤیدیۆ جەماوەرییەکان'\n    Hide Playlists: 'شاردنەوەی پێڕستی لێدان'\n    Hide Live Chat: 'شاردنەوەی دەمەتەقێی ڕاستەوخۆ'\n    Hide Active Subscriptions: ''\n    Hide Video Description: 'شاردنەوەی پێناسەی ڤیدیۆ'\n    Hide Comments: 'شاردنەوەی لێدوانەکان'\n    Hide Profile Pictures in Comments: 'شاردنەوەی وێنەی لادیمەن لە سەرنجەکان'\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: 'شاردنەوەی پەخشە ڕاستەوخۆکان'\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: 'شاردنەوەی کرداری بەشینەوە'\n    Hide Chapters: 'شاردنەوەی بڕگەکان'\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n  Data Settings:\n    Data Settings: 'دراوە'\n    Select Export Type: 'دیاریکردنی جۆری هەناردە'\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: 'پەڕگەی مێژوو'\n    Playlist File: 'پەڕگەی پێڕستی لێدان'\n    Export Subscriptions: ''\n    Export FreeTube: 'هەناردەکردنی فریتیوب'\n    Export YouTube: 'هەناردەکردنی یوتیوب'\n    Export NewPipe: 'هەناردەکردنی نیوپایپ'\n    Import History: 'هاوردەکردنی مێژوو'\n    Export History: 'هەناردەکردنی مێژوو'\n    Import Playlists: 'هاوردەکردنی پێڕستی لێدان'\n    Export Playlists: 'هەناردەکردنی پێڕستی لێدان'\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: 'پەڕگەی نادرووستی مێژوو'\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: 'گشت پێڕستەکانی لێدان بەڕێکی هاوردران'\n    All playlists has been successfully exported: 'هەموو پێڕستەکانی لێدان بەڕێکی هەناردران'\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n    Search history: مێژووی گەڕان\n  Proxy Settings:\n    Proxy Settings: 'پێشکار'\n    Enable Tor / Proxy: 'کاراکردنی تۆر / پێشکار'\n    Proxy Protocol: 'پرۆتۆکۆلی پێشکار'\n    Proxy Host: 'خانەخوێی پێشکار'\n    Proxy Port Number: 'ژمارەی دەرچەی پێشکار'\n    Clicking on Test Proxy will send a request to: 'کرتە کردن لە تاقیکردنەوەی پێشکار، داخوازییەک دەنێرێت بۆ'\n    Test Proxy: 'تاقیکردنەوەی پێشکار'\n    Your Info: 'زانیارییەکانت'\n    Ip: 'ئای پی'\n    Country: 'وڵات'\n    Region: 'هەرێم'\n    City: 'شار'\n    Error getting network information. Is your proxy configured properly?: ''\n    Proxy Password: تێپەڕەوشەی پێشکار\n    Proxy Username: ناوی بەکارهێنەری پێشکار\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: 'هیچ مەکە'\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: 'شاردنەوەی میلی گەڕان'\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: 'تێپەڕەوشە'\n    Enter Password To Unlock: 'تێپەڕەوشە بنووسە بۆ کردنەوەی کڵۆمی ڕێکخستنەکان'\n  Password Settings:\n    Password Settings: 'تێپەڕەوشە'\n    Set Password To Prevent Access: ''\n    Set Password: 'دانانی تێپەڕەوشە'\n    Remove Password: 'لادانی تێپەڕەوشە'\n  Sort Settings Sections (A-Z): ڕیزکردنی بەشەکانی ڕێکخستن (ئ-ێ)\n  Return to Settings Menu: بگەڕێوە بۆ پێڕستی ڕێکخستنەکان\nAbout:\n  #On About page\n  About: 'دەربارە'\n  Beta: ''\n  Source code: 'کۆدی سەرچاوە'\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: 'یارمەتی'\n  FreeTube Wiki: 'ویکی فریتیوب'\n  FAQ: 'پرسیارە دووبارەکان'\n  Discussions: ''\n  Report a problem: 'سکاڵا لە کێشەیەک بکە'\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: 'وێبگە'\n  Blog: 'بلۆگ'\n  Email: 'ئیمێڵ'\n  Mastodon: 'ماستادۆن'\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: 'وەرگێڕان'\n  Credits: ''\n  these people and projects: ''\n  Donate: 'بەخشین'\n\n  AGPLv3: ''\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: 'هەموو کەناڵەکان'\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': '{number} دیاریکراوە'\n  Select All: 'دیاریکردنی هەموویان'\n  Select None: 'دیاری نەکردنی هیچیان'\n  Delete Selected: 'سڕینەوەی دیاریکراوەکان'\n  Add Selected To Profile: ''\n  No channel(s) have been selected: 'هیچ کەناڵێک دیاری نەکراوە'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: 'ئەم کەناڵە بوونی نییە'\n  This channel does not allow searching: 'ئەم کەناڵە ڕێ بە گەڕان نادات'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: 'ڤیدیۆکان'\n    This channel does not currently have any videos: 'ئەم کەناڵە ئێستا هیچ ڤیدیۆیەکی نییە'\n    Sort Types:\n      Newest: 'نوێترین'\n      Oldest: 'کۆنترین'\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: 'ڕاستەوخۆ'\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: 'پێڕستی لێدان'\n    This channel does not currently have any playlists: 'ئەم کەناڵە ئێستا هیچ پێڕستێکی لێدانی نییە'\n    Sort Types:\n      Last Video Added: 'دوایین ڤیدیۆ زیادکراوەکان'\n      Newest: 'نوێترین'\n      Oldest: 'کۆنترین'\n  Podcasts:\n    Podcasts: 'پۆدکاستەکان'\n    This channel does not currently have any podcasts: 'ئەم کەناڵە ئێستا هیچ پۆدکاستێکی نییە'\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  About:\n    About: 'دەربارە'\n    Channel Description: 'پێناسی کەناڵ'\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: 'وردەکاری'\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: '{votes} دەنگ'\n    Reveal Answers: ''\n    Hide Answers: 'شاردنەوەی وەڵامەکان'\nVideo:\n  Mark As Watched: 'وەکو تەمەشاکراو نیشانی بکە'\n  Remove From History: 'لە مێژوو لای ببە'\n  Video has been marked as watched: 'ڤیدیۆکە وەکو تەمەشاکراو نیشان کراوە'\n  Video has been removed from your history: 'ڤیدیۆکە لە مێژووەکەت لابرا'\n  Save Video: 'پاشەکەوتکردنی ڤیدیۆ'\n  Video has been saved: 'ڤیدیۆکە پاشەکەوت کرا'\n  Video has been removed from your saved list: 'ڤیدیۆکە لە لیستەی پاشەکەوت کراوەکان لابرا'\n  Open in YouTube: 'کردنەوە لە یوتیوب'\n  Copy YouTube Link: 'بەستەری یوتیوب لەبەر بگرەوە'\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: 'کردنەوەی کەناڵ لە یوتیوب'\n  Copy YouTube Channel Link: 'لەبەرگرتنەوەی بەستەری کەناڵی یوتیوب'\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Views: 'بینراو'\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: 'تەمەشاکراو'\n  Autoplay: 'خۆلێدان'\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: 'دەمەتەقێی ڕاستەوخۆ کارایە. کە پەیامەکان نێدران لێرە دەردەکەون.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: 'بڵاوکرایەوە لە'\n  Streamed on: ''\n  Started streaming on: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: 'ڤیدیۆ'\n    playlist: 'پێڕستی لێدان'\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n#& Videos\n  Unhide Channel: پیشاندانی کەناڵ\n  Hide Channel: شاردنەوەی کەناڵ\n#& Playlists\n  Player:\n    You appear to be offline: وا دیارە دەرهێڵیت.\n    Autoplay is off: خۆلێدان خامۆشە\n    Autoplay is on: خۆلێدان هەڵکراوە\nPlaylist:\n  #& About\n  Playlist: 'پێڕستی لێدان'\n  View Full Playlist: ''\n  Last Updated On: ''\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    AuthorAscending: دانەر (ئ-ی)\n    AuthorDescending: دانەر (ی-ئ)\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\nShare:\n  Share Video: 'هاوبەشکردنی ڤیدیۆ'\n  Share Channel: 'هاوبەشکردنی کەناڵ'\n  Share Playlist: 'هاوبەشکردنی پێڕستی لێدان'\n  Include Timestamp: ''\n  Copy Link: 'لەبەرگرتنەوەی بەستەر'\n  Open Link: 'کردنەوەی بەستەر'\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: 'بڕگەکان'\n\nMini Player: 'لێدەری گچکە'\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: 'سەرەتا نوێترینەکان'\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'پیشاندانی وەڵامدانەوەی زۆرتر'\n  There are no comments available for this video: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: 'ئەندام'\n  Subscribed: ''\n  Hearted: ''\nUp Next: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"(بنەڕەت: '{defaultCustomArguments}')\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: 'لێدانی ڤیدیۆی دواتر'\nPlaying Previous Video: 'لێدانی ڤیدیۆی پێشوو'\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nYes: 'بەڵێ'\nNo: 'نەخێر'\nOk: 'باشە'\nGo to page: بڕۆ بۆ {page}\nSearch Listing:\n  Label:\n    4K: ٤ک\n    Subtitles: ژێرنووس\n    8K: ٨ک\n    360 Video: ٣٦٠°\n    New: نوێ\n    3D: ٣ ڕەهەندی\n    VR180: VR١٨٠\nRight-click or hold to see history: کرتەی ڕاست بکە یان ڕایگرە بۆ بینینی مێژوو\nFeed:\n  Refresh Feed: تازەکردنەوەی {subscriptionName}\nshortcutLabelSeparator: ｜\nKeyboardShortcutPrompt:\n  Sections:\n    App:\n      General: 'کاربەرنامە: گشتیی'\n      Situational: 'کاربەرنامە: بارودۆخی'\n  Last Chapter: دوا بڕگە\n  Next Chapter: بڕگەی دواتر\n  Toggle Developer Tools: زامنی ئامرازەکانی گەشەپێدەر\ncheckmark: ✓\nshortcutJoinOperator: +\n"
  },
  {
    "path": "static/locales/cs.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Čeština'\n\n# Webkit Menu Bar\nFile: 'Soubor'\nQuit: 'Ukončit'\nEdit: 'Editovat'\nUndo: 'Zpět'\nRedo: 'Předělat'\nCut: 'Vyjmout'\nCopy: 'Kopírovat'\nPaste: 'Vložit'\nDelete: 'Smazat'\nSelect all: 'Vybrat vše'\nToggle Developer Tools: 'Přepnout vývojářské nástroje'\nActual size: 'Současná velikost'\nZoom in: 'Přiblížit'\nZoom out: 'Oddálit'\nToggle fullscreen: 'Přepnout na celou obrazovku'\nWindow: 'Okno'\nMinimize: 'Minimalizovat'\nClose: 'Zavřít'\nBack: 'Zpět'\nForward: 'Dopředu'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videa'\n  Shorts: Shorts\n  Live: Živě\n  Posts: Příspěvky\n  Sort By: Seřadit podle\n\n  Counts:\n    Video Count: 1 video | {count} videí\n    Channel Count: 1 kanál | {count} kanálů\n    Subscriber Count: 1 odběratel | {count} odběratelů\n    View Count: 1 zhlédnutí | {count} zhlédnutí\n    Watching Count: 1 sledující | {count} sledujících\n    Like Count: 1 líbí se mi | {count} líbí se mi\n    Comment Count: 1 komentář | {count} komentářů\nVersion {versionNumber} is now available!  Click for more details: 'Je k dispozici verze {versionNumber}! Klikněte pro více informací'\nDownload From Site: 'Stáhnout ze stránky'\nA new blog is now available, {blogTitle}. Click to view more: 'Je dostupný nový článek na blogu: {blogTitle}. Kliknutím zobrazíte více'\n\n# Search Bar\nSearch / Go to URL: 'Hledat / Přejít na URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Vyhledávací filtry'\n  Sort By:\n    Most Relevant: 'Nejrelevantnější'\n    Rating: 'Hodnocení'\n    Upload Date: 'Datum nahrání'\n    View Count: 'Počet zhlédnutí'\n  Time:\n    Time: 'Čas'\n    Any Time: 'Kdykoliv'\n    Last Hour: 'Poslední hodina'\n    Today: 'Dnes'\n    This Week: 'Tento týden'\n    This Month: 'Tento měsíc'\n    This Year: 'Tento rok'\n  Type:\n    Type: 'Typ'\n    All Types: 'Všechny typy'\n    Videos: 'Videa'\n    Channels: 'Kanály'\n    #& Playlists\n    Movies: Filmy\n  Duration:\n    Duration: 'Trvání'\n    All Durations: 'Všechny trvání'\n    Short (< 4 minutes): 'Krátké (< 4 minuty)'\n    Long (> 20 minutes): 'Dlouhé (> 20 minut)'\n  # On Search Page\n    Medium (4 - 20 minutes): Střední (4 - 20 minut)\n  Search Results: 'Výsledky hledání'\n  Fetching results. Please wait: 'Načítání výsledků. Prosím, čekejte'\n  Fetch more results: 'Načíst více výsledků'\n# Sidebar\n  There are no more results for this search: Pro toto hledání nejsou k dispozici žádné další výsledky\n  Features:\n    HD: HD\n    360 Video: 360° video\n    Subtitles: Titulky\n    Features: Vlastnosti\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Živě\n    4K: 4K\n    Location: Místo\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Vymazat filtry\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Odběry'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Tento profil má velký počet odběrů.  Vynucení RSS, aby se zabránilo omezení rychlosti'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Váš seznam odběrů je prázdný. Pokud chcete importovat své odběry, přejděte do Nastavení dat a vyberte Importovat odběry. Můžete také jednoduše vyhledat kanál a přihlásit se u něj k odběru.'\n  Load More Videos: 'Načíst více videí'\n  Error Channels: Kanály s chybami\n  Empty Channels: Vaše odebírané kanály momentálně nemají žádná videa.\n  Disabled Automatic Fetching: Máte zakázané automatické získávání odběrů. Obnovte odběry, abyste je zde mohli vidět.\n  Subscriptions Tabs: Karty s odběry\n  All Subscription Tabs Hidden: Všechny karty předplatného jsou skryté. Chcete-li zde zobrazit obsah, zrušte prosím skrytí některých záložek v sekci „{subsection}“ v „{settingsSection}“.\n  Load More Posts: Načíst další příspěvky\n  Empty Posts: Vaše odebírané kanály momentálně nemají žádné příspěvky.\nTrending:\n  Trending: 'Trendy'\n  Trending Tabs: Tabulka trendů\n  Gaming: Hry\n  Sports: Sporty\nMost Popular: 'Populární'\nPlaylists: 'Playlisty'\nUser Playlists:\n  Your Playlists: 'Vaše playlisty'\n  Search bar placeholder: Hledat playlisty\n  Empty Search Message: V tomto playlistu nejsou žádná videa, která by odpovídala vašemu vyhledávání\n  AddVideoPrompt:\n    Search in Playlists: Hledat v playlistech\n    Save: Uložit\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Videa přidána do 1 playlistu | Videa přidána do {playlistCount} playlistů\"\n      You haven't selected any playlist yet.: Zatím jste nevybrali žádný playlist.\n    Select a playlist to add your N videos to: Vyberte playlist, do kterého přidat vaše video | Vyberte playlist, do kterého přidat vašich {videoCount} videí\n    N playlists selected: Vybráno {playlistCount}\n    Added {count} Times: Již přidáno | Přidáno {count}krát\n    Allow Adding Duplicate Video(s): Povolit duplicitní přidávání videí\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": Již přidáno {videoCount}/{totalVideoCount} videí\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": Bude přidáno {videoCount}/{totalVideoCount} videí\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Nejsou zde žádná videa k odstranění.\n      Video has been removed: Video bylo odstraněno\n      Playlist has been updated.: Playlist byl aktualizován.\n      There was an issue with updating this playlist.: Při úpravě tohoto playlistu se vyskytla chyba.\n      This video cannot be moved up.: Toto video nelze posunout nahoru.\n      This playlist is protected and cannot be removed.: Tento playlist je chráněn a nelze jej odstranit.\n      Playlist {playlistName} has been deleted.: Playlist {playlistName} byl odstraněn.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Některá videa v playlistu ještě nejsou načtena. Kliknutím sem je přesto zkopírujete.\n      This playlist does not exist: Tento playlist neexistuje\n      Playlist name cannot be empty. Please input a name.: Název playlistu nemůže být prázdný. Zadejte prosím název.\n      There was a problem with removing this video: Při odstraňování videa se vyskytl problém\n      \"{videoCount} video(s) have been removed\": 1 video bylo odstraněno | {videoCount} videí bylo odstraněno\n      This video cannot be moved down.: Toto video nejde posunout dolů.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Tento playlist bude nyní použit pro rychlé uložení namísto playlistu {oldPlaylistName}. Klikněte sem pro zrušení akce\n      Reverted to use {oldPlaylistName} for quick bookmark: Playlist {oldPlaylistName} byl navrácen pro rychlé uložení\n      This playlist is now used for quick bookmark: Tento playlist bude nyní použit pro rychlé uložení\n      This playlist is already being used for quick bookmark.: Tento playlist je již používán pro rychlou záložku.\n      This playlist has a video with a duration error: Tento playlist obsahuje nejméně jedno video, které nemá dobu trvání. Bude seřazeno tak, jako by mělo dobu trvání nula.\n      Video has been removed. Click here to undo.: Video bylo odstraněno. Klikněte sem pro zrušení akce.\n    Search for Videos: Hledat videa\n  Are you sure you want to delete this playlist? This cannot be undone: Opravdu chcete odstranit tento playlist? Tato akce je nevratná.\n  Sort By:\n    LatestPlayedFirst: Datum přehrání (nejnovější)\n    EarliestCreatedFirst: Datum vytvoření (nejstarší)\n    LatestCreatedFirst: Datum vytvoření (nejnovější)\n    EarliestUpdatedFirst: Datum úpravy (nejstarší)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Datum přehrání (nejstarší)\n    LatestUpdatedFirst: Datum úpravy (nejnovější)\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Nemáte žádné playlisty. Klikněte na tlačítko pro vytvoření nového playlistu.\n  Remove from Playlist: Odebrat z playlistu\n  Save Changes: Uložit změny\n  CreatePlaylistPrompt:\n    Create: Vytvořit\n    Toast:\n      There was an issue with creating the playlist.: Při vytváření playlistu se vyskytla chyba.\n      Playlist {playlistName} has been successfully created.: Playlist {playlistName} byl úspěšně vytvořen.\n      There is already a playlist with this name. Please pick a different name.: Playlist s tímto názvem již existuje. Zvolte prosím jiný název.\n    New Playlist Name: Název nového playlistu\n  This playlist currently has no videos.: V tomto playlistu momentálně nejsou žádná videa.\n  Add to Playlist: Přidat do playlistu\n  Move Video Down: Posunout video dolů\n  Playlist Name: Název playlistu\n  Remove Watched Videos: Odstranit zhlédnutá videa\n  Move Video Up: Posunout video nahoru\n  Cancel: Zrušit\n  Delete Playlist: Odstranit playlist\n  Create New Playlist: Vytvořit nový playlist\n  Edit Playlist Info: Upravit informace o playlistu\n  Copy Playlist: Kopírovat playlist\n  Playlist Description: Popis playlistu\n  Add to Favorites: Přidat do playlistu {playlistName}\n  Remove from Favorites: Odebrat z playlistu {playlistName}\n  Enable Quick Bookmark With This Playlist: Zapnout u tohoto playlistu rychlé uložení\n  Playlists with Matching Videos: Playlisty s odpovídajícími videi\n  Quick Bookmark Enabled: Rychlá záložka zapnuta\n  Cannot delete the quick bookmark target playlist.: Nemůžete odstranit cílový playlist rychlé záložky.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Opravdu chcete odstranit 1 duplicitní video z tohoto playlistu? Tato akce je nevratná. | Opravdu chcete odstranit {playlistItemCount} duplicitních videí z tohoto playlistu? Tato akce je nevratná.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Opravdu chcete odstranit 1 zhlédnuté video z tohoto playlistu? Tato akce je nevratná. | Opravdu chcete odstranit {playlistItemCount} zhlédnutých videí z tohoto playlistu? Tato akce je nevratná.\n  Remove Duplicate Videos: Odstranit duplicitní videa\n  Export Playlist: Exportovat tento playlist\n  The playlist has been successfully exported: Playlist byl úspěšně exportován\n  TotalTimePlaylist: 'Celkový čas: {duration}'\n  Export list of URLs: Exportovat seznam adres URL\nHistory:\n  # On History Page\n  History: 'Historie'\n  Watch History: 'Historie zhlédnutých videí'\n  Your history list is currently empty.: 'Vaše historie je momentálně prázdná.'\n  Empty Search Message: Ve vaší historii nejsou žádná videa, která by odpovídala vašemu vyhledávání\n  Search bar placeholder: Hledat v historii\n  Case Sensitive Search: Vyhledávání citlivé na velikost písmen\n  DateOldestHistory: Datum zhlédnutí (nejstarší)\n  DateNewestHistory: Datum zhlédnutí (nejnovější)\nSettings:\n  # On Settings Page\n  Settings: 'Nastavení'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Aby se změny projevily, je třeba aplikaci restartovat. Restartovat a použít změny?'\n  General Settings:\n    General Settings: 'Obecné'\n    Check for Updates: 'Kontrolovat aktualizace'\n    Check for Latest Blog Posts: 'Kontrolovat nejnovější příspěvky na blogu'\n    Fallback to Non-Preferred Backend on Failure: 'Při chybě přepnout na nepreferovaný backend'\n    Enable Search Suggestions: 'Zapnout návrhy vyhledávání'\n    Default Landing Page: 'Výchozí vstupní stránka'\n    Locale Preference: 'Předvolby jazyka'\n    Preferred API Backend:\n      Preferred API Backend: 'Preferovaný API backend'\n      Local API: 'Lokální API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Typ zobrazení videí'\n      Grid: 'Mřížka'\n      List: 'Seznam'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Předvolby náhledů'\n      Default: 'Výchozí'\n      Beginning: 'Začátek'\n      Middle: 'Střed'\n      End: 'Konec'\n      Hidden: Skryté\n      Blur: Rozmazané\n    Region for Trending: 'Oblast pro trendy'\n        #! List countries\n    View all Invidious instance information: Zobrazit všechny informace o instancích Invidious\n    System Default: Podle systému\n    Clear Default Instance: Vymazat výchozí instanci\n    Set Current Instance as Default: Nastavit současnou instanci jako výchozí\n    Current instance will be randomized on startup: Při spuštění bude vybrána náhodná instance\n    Current Invidious Instance: Současná instance Invidious\n    No default instance has been set: Není nastavena žádná výchozí instance\n    The currently set default instance is {instance}: Aktuální výchozí instance je {instance}\n    External Link Handling:\n      No Action: Žádná akce\n      Ask Before Opening Link: Před otevřením odkazu se zeptat\n      Open Link: Otevřít odkaz\n      External Link Handling: Zpracování externích odkazů\n    Auto Load Next Page:\n      Label: Automaticky načíst další stránku\n      Tooltip: Automaticky načítat další stránky a komentáře.\n    Open Deep Links In New Window: Otevírat adresy předané aplikaci FreeTube v novém okně\n    Minimize to system tray: Minimalizovat do systémové lišty\n  Theme Settings:\n    Theme Settings: 'Motiv'\n    Match Top Bar with Main Color: 'Přizpůsobit horní lištu hlavní barvě'\n    Expand Side Bar by Default: 'Ve výchozím stavu rozbalený postranní panel'\n    Disable Smooth Scrolling: 'Zakázat plynulé posouvání'\n    UI Scale: 'Měřítko rozhraní'\n    Base Theme:\n      Base Theme: 'Základní motiv'\n      Black: 'Černý'\n      Dark: 'Tmavý'\n      Light: 'Světlý'\n      Dracula: 'Drákula'\n      System Default: Podle systému\n      Catppuccin Mocha: Catppuccin Mocha\n      Hot Pink: Horká růžová\n      Pastel Pink: Pastelově růžová\n      Nordic: Nordic\n      Solarized Dark: Solarizovaná tmavá\n      Solarized Light: Solarizovaná světlá\n      Gruvbox Dark: Gruvbox tmavý\n      Gruvbox Light: Gruvbox světlý\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: Everforest Dark Hard\n      Everforest Dark Low: Everforest Dark Low\n      Everforest Light Hard: Everforest Light Hard\n      Everforest Light Medium: Everforest Light Medium\n      Everforest Light Low: Everforest Light Low\n      Everforest Dark Medium: Everforest Dark Medium\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Hlavní barva motivu'\n      Red: 'Červená'\n      Pink: 'Růžová'\n      Purple: 'Fialová'\n      Deep Purple: 'Temně fialová'\n      Indigo: 'Indigo'\n      Blue: 'Modrá'\n      Light Blue: 'Světle modrá'\n      Cyan: 'Azurová'\n      Teal: 'Modrozelená'\n      Green: 'Zelená'\n      Light Green: 'Světle zelená'\n      Lime: 'Limetková'\n      Yellow: 'Žlutá'\n      Amber: 'Jantarová'\n      Orange: 'Oranžová'\n      Deep Orange: 'Temně oranžová'\n      Dracula Cyan: 'Azurový drákula'\n      Dracula Green: 'Zelený drákula'\n      Dracula Orange: 'Oranžový drákula'\n      Dracula Pink: 'Růžový drákula'\n      Dracula Purple: 'Fialový drákula'\n      Dracula Red: 'Červený drákula'\n      Dracula Yellow: 'Žlutý drákula'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky\n      Catppuccin Mocha Red: Catppuccin Mocha Red\n      Catppuccin Mocha Green: Catppuccin Mocha Green\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender\n      Solarized Yellow: Solarizovaná žlutá\n      Solarized Orange: Solarizovaná oranžová\n      Solarized Red: Solarizovaná červená\n      Solarized Magenta: Solarizovaná purpurová\n      Solarized Violet: Solarizovaná fialová\n      Solarized Blue: Solarizovaná modrá\n      Solarized Cyan: Solarizovaná azurová\n      Solarized Green: Solarizovaná zelená\n      Gruvbox Dark Green: Gruvbox tmavě zelený\n      Gruvbox Dark Yellow: Gruvbox tmavě žlutý\n      Gruvbox Dark Blue: Gruvbox tmavě modrý\n      Gruvbox Dark Purple: Gruvbox tmavě fialový\n      Gruvbox Dark Orange: Gruvbox tmavě oranžový\n      Gruvbox Light Red: Gruvbox světle červený\n      Gruvbox Light Purple: Gruvbox světle fialový\n      Gruvbox Dark Aqua: Gruvbox tmavě azurový\n      Gruvbox Light Blue: Gruvbox světle modrý\n      Gruvbox Light Orange: Gruvbox světle oranžový\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Catppuccin Frappe Green: Catppuccin Frappe Green\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Sapphire\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Red\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maroon\n      Catppuccin Frappe Sky: Catppuccin Frappe Sky\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Dark Green: Everforest Dark Green\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Dark Blue\n      Everforest Dark Purple: Everforest Dark Purple\n      Everforest Light Red: Everforest Light Red\n      Everforest Light Orange: Everforest Light Orange\n      Everforest Light Yellow: Everforest Light Yellow\n      Everforest Light Green: Everforest Light Green\n      Everforest Light Purple: Everforest Light Purple\n      Everforest Dark Orange: Everforest Dark Orange\n      Everforest Light Blue: Everforest Light Blue\n      Everforest Dark Red: Everforest Dark Red\n      Everforest Dark Yellow: Everforest Dark Yellow\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n    Secondary Color Theme: 'Sekundární barva motivu'\n        #* Main Color Theme\n    Hide Side Bar Labels: Skrýt popisky na bočním panelu\n    Hide FreeTube Header Logo: Skrýt logo FreeTube v záhlaví\n  Player Settings:\n    Player Settings: 'Přehrávač'\n    Play Next Video: 'Automaticky přehrávat doporučená videa'\n    Turn on Subtitles by Default: 'Ve výchozím nastavení povolit titulky'\n    Autoplay Videos: 'Automaticky spouštět videa'\n    Proxy Videos Through Invidious: 'Proxy videa prostřednictvím Invidious'\n    Autoplay Playlists: 'Automaticky přehrávat videa v playlistu'\n    Enable Theatre Mode by Default: 'Ve výchozím nastavení povolit režim kino'\n    Default Volume: 'Výchozí hlasitost'\n    Default Playback Rate: 'Výchozí rychlost přehrávání'\n    Default Video Format:\n      Default Video Format: 'Výchozí formát videa'\n      Dash Formats: 'Formát DASH'\n      Legacy Formats: 'Starší formáty'\n      Audio Formats: 'Zvukové formáty'\n    Default Quality:\n      Default Quality: 'Výchozí kvalita'\n      Auto: 'Automaticky'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Čas do automatického přehrání\n    Display Play Button In Video Player: Zobrazit tlačítko Přehrát v přehrávači videa\n    Scroll Volume Over Video Player: Měnit hlasitost posuvem kolečka myši na přehrávači\n    Fast-Forward / Rewind Interval: Interval rychlého přetáčení vpřed / vzad\n    Scroll Playback Rate Over Video Player: Měnit rychlost přehrávání posuvem kolečka myši\n    Max Video Playback Rate: Maximální rychlost přehrávání videa\n    Video Playback Rate Interval: Interval rychlosti přehrávání videa\n    Screenshot:\n      Error:\n        Forbidden Characters: Zakázané znaky\n        Empty File Name: Prázdný název souboru\n      File Name Label: Vzor názvu souboru\n      File Name Tooltip: Můžete použít proměnné níže. %Y Rok 4 číslice. %M Měsíc 2 číslice. %D Den 2 číslice. %H Hodina 2 číslice. %N Minuta 2 číslice. %S Sekunda 2 číslice. %T Milisekunda 3 číslice. %s Sekunda videa. %t Milisekunda videa 3 číslice. %i ID videa.\n      Ask Path: Zeptat se na složku pro uložení\n      Folder Label: Složka snímků obrazovky\n      Enable: Povolit snímek obrazovky\n      Format Label: Formát snímku obrazovky\n      Quality Label: Kvalita snímku obrazovky\n      Folder Button: Vybrat složku\n    Enter Fullscreen on Display Rotate: Při otočení displeje přejít na celou obrazovku\n    Skip by Scrolling Over Video Player: Posouvat čas posuvem kolečka myši na přehrávači\n    Autoplay Interruption Timer: Čas přerušení automatického přehrávání\n    Default Viewing Mode:\n      Theater: Kino\n      Default Viewing Mode: Výchozí režim sledování\n      Full Screen: Celá obrazovka\n      External Player: Externí přehrávač ({externalPlayerName})\n      Picture in Picture: Obraz v obraze\n  Privacy Settings:\n    Privacy Settings: 'Soukromí'\n    Remember History: 'Zapamatovat historii sledování'\n    Save Watched Progress: 'Uložit průběh zhlédnutých videí'\n    Clear Search Cache: 'Vymazat mezipaměť vyhledávání'\n    Are you sure you want to clear out your search cache?: 'Opravdu chcete vymazat mezipaměť vyhledávání?'\n    Search cache has been cleared: 'Cache vyhledávání byla vymazána'\n    Remove Watch History: 'Odstranit historii sledování'\n    Are you sure you want to remove your entire watch history?: 'Opravdu chcete odstranit historii viděných videí?'\n    Watch history has been cleared: 'Historie viděných videí byla odstraněna'\n    Remove All Subscriptions / Profiles: 'Odstranit všechny odběry / profily'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Opravdu chcete odstranit všechny odběry a profily? Tato akce je nevratná.'\n    Save Watched Videos With Last Viewed Playlist: Uložit zhlédnutá videa s naposledy zobrazeným playlistem\n    All playlists have been removed: Všechny playlisty byly odstraněny\n    Remove All Playlists: Odstranit všechny playlisty\n    Are you sure you want to remove all your playlists?: Opravdu chcete odstranit všechny své playlisty?\n    Remember Search History: Zapamatovat historii vyhledávání\n    Are you sure you want to clear out your search history and cache?: Opravdu chcete vymazat svou historii a mezipaměť vyhledávání?\n    Clear Search History and Cache: Vymazat historii a mezipaměť vyhledávání\n    Search history and cache have been cleared: Historie a mezipaměť vyhledávání byly vymazány\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automaticky\n        Semi-auto: Poloautomaticky\n        Never: Nikdy\n      Tooltip: Automaticky = Uložit po každém opuštění stránky s videem, pokud video skončí nebo pokud se vyskytne chyba (např. vypršení relace sledování). Poloautomaticky = Stejné jako Automaticky kromě opuštění stránky videa, průběh lze uložit ručně kliknutím na tlačítko Uložit průběh sledování, nacházejícím se pod přehrávačem.\n  Subscription Settings:\n    Subscription Settings: 'Odběry'\n    Fetch Feeds from RSS: 'Získávat odběry z RSS'\n    Fetch Automatically: Automaticky načítat odběry\n    Confirm Before Unsubscribing: Zamezit nechtěným odběrům\n    To: Do\n    'Limit the number of videos displayed for each channel': Omezit počet videí zobrazených u každého kanálu\n  Distraction Free Settings:\n    Distraction Free Settings: 'Rozptylování'\n    Hide Video Views: 'Skrýt počet přehrání videa'\n    Hide Video Likes And Dislikes: 'Skrýt hodnocení videa'\n    Hide Channel Subscribers: 'Skrýt odběratele kanálu'\n    Hide Comment Likes: 'Skrýt hodnocení komentářů'\n    Hide Recommended Videos: 'Skrýt doporučená videa'\n    Hide Trending Videos: 'Skrýt trendy'\n    Hide Popular Videos: 'Skrýt populární videa'\n    Hide Live Chat: 'Skrýt chat'\n    Hide Active Subscriptions: Skrýt aktivní odběry\n    Hide Playlists: Skrýt playlisty\n    Hide Video Description: Skrýt popis videa\n    Hide Comments: Skrýt komentáře\n    Hide Live Streams: Skrýt živé přenosy\n    Hide Sharing Actions: Skrýt akce sdílení\n    Hide Videos on Watch: 'Skrýt přehraná videa'\n    Hide Chapters: Skrýt kapitoly\n    Hide Upcoming Premieres: Skrýt nadcházející premiéry\n    Hide Channels: Skrýt videa z kanálů\n    Hide Channels Placeholder: ID kanálu\n    Display Titles Without Excessive Capitalisation: Zobrazit názvy bez nadměrného použití velkých písmen a interpunkce\n    Hide Featured Channels: Skrýt doporučené kanály\n    Hide Channel Playlists: Skrýt kartu „Playlisty“ u kanálů\n    Hide Channel Shorts: Skrýt kartu „Shorts“ u kanálů\n    Sections:\n      Side Bar: Postranní lišta\n      Channel Page: Stránka kanálu\n      Watch Page: Stránka sledování\n      General: Obecné\n      Subscriptions Page: Stránka s odběry\n    Hide Channel Podcasts: Skrýt kartu „Podcasty“ u kanálů\n    Hide Channel Releases: Skrýt kartu „Vydání“ u kanálů\n    Hide Subscriptions Shorts: Skrýt Shorts odběrů\n    Hide Subscriptions Videos: Skrýt videa odběrů\n    Hide Subscriptions Live: Skrýt živá vysílání odběrů\n    Hide Profile Pictures in Comments: Skrýt profilové obrázky v komentářích\n    Hide Channels Invalid: Zadané ID kanálu je neplatné\n    Hide Channels Disabled Message: Některé kanály byly zablokovány pomocí ID a nebyly zpracovány. Při aktualizaci těchto ID je funkce zablokována\n    Hide Channels Already Exists: ID kanálu již existuje\n    Hide Channels API Error: Chyba při načítání uživatele se zadaným ID. Zkontrolujte prosím, zda je zadané ID správné.\n    Hide Videos, Playlists and Channels Containing Text: Skrýt videa a playlisty obsahující text\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Slovo, část slova nebo fráze\n    Hide Channel Home: Skrýt kartu „Domovská stránka“ u kanálů\n    Show Added Items: Zobrazit přidané položky\n    Hide Channel Courses: Skrýt kartu „Kurzy“ u kanálů\n    Hide Subscriptions Posts: Skrýt příspěvky odběrů\n    Hide Channel Posts: Skrýt kartu „Příspěvky“ u kanálů\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Vybrat typ exportu'\n    Import Subscriptions: 'Importovat odběry'\n    Export Subscriptions: 'Exportovat odebírané kanály'\n    Export FreeTube: 'Exportovat FreeTube'\n    Export YouTube: 'Exportovat YouTube'\n    Export NewPipe: 'Exportovat NewPipe'\n    Import History: 'Importovat historii'\n    Export History: 'Exportovat historii'\n    Profile object has insufficient data, skipping item: 'Objekt profilu má nedostatečná data, přeskakuji položku'\n    All subscriptions and profiles have been successfully imported: 'Všechny odebírané kanály a profily byly úspěšně importovány'\n    All subscriptions have been successfully imported: 'Všechny odebírané kanály byly úspěšně importovány'\n    Invalid subscriptions file: 'Vadný soubor odebíraných kanálů'\n    Invalid history file: 'Vadný soubor s historií'\n    Subscriptions have been successfully exported: 'Odebírané kanály byly úspěšně exportovány'\n    History object has insufficient data, skipping item: 'Objekt historie má nedostatečná data, přeskakuji položku'\n    All watched history has been successfully imported: 'Historie zhlédnutých videí byla úspěšně importována'\n    All watched history has been successfully exported: 'Historie zhlédnutých videí byla úspěšně exportována'\n    Unable to read file: 'Nelze přečíst soubor'\n    Unable to write file: 'Soubor nelze uložit'\n    Unknown data key: 'Neznámý datový klíč'\n    How do I import my subscriptions?: 'Jak mohu importovat své odebírané kanály?'\n    Manage Subscriptions: Spravovat odběry\n    Import Playlists: Importovat playlisty\n    Export Playlists: Exportovat playlisty\n    Playlist insufficient data: Nedostačující data pro playlist \"{playlist}\", přeskakuji\n    All playlists has been successfully imported: Všechny playlisty byly úspěšně importovány\n    All playlists has been successfully exported: Všechny playlisty byly úspěšně exportovány\n    History File: Soubor historie\n    Subscription File: Soubor odběrů\n    Playlist File: Soubor playlistů\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Tato možnost exportuje videa ze všech playlistů do jednoho playlistu s názvem „Favorites“.\\nJak exportovat a importovat videa z playlistů do starších verzí FreeTube:\\n1. Povolte tuto možnost a exportujte své playlisty.\\n2. Odstraňte všechny své stávající playlisty možností Odstranit všechny playlisty v nastavení soukromí.\\n3. Spusťte starší verzi FreeTube a importujte exportované playlisty.\"\n      Label: Exportovat playlisty pro starší verze FreeTube\n\n    Search history file: Soubor historie vyhledávání\n    Search history: Historie vyhledávání\n    Import search history: Importovat historii vyhledávání\n    Export search history: Exportovat historii vyhledávání\n    All search history has been successfully imported: Veškerá historie vyhledávání byla úspěšně importována\n    All search history has been successfully exported: Veškerá historie vyhledávání byla úspěšně exportována\n  Proxy Settings:\n    Proxy Settings: Proxy\n    City: Město\n    Ip: IP\n    Your Info: Vaše informace\n    Enable Tor / Proxy: Povolit Tor / proxy\n    Region: Region\n    Country: Země\n    Test Proxy: Otestovat proxy\n    Clicking on Test Proxy will send a request to: Kliknutím na Otestovat proxy se odešle dotaz na\n    Proxy Port Number: Port proxy\n    Proxy Host: Adresa proxy\n    Proxy Protocol: Protokol proxy\n    Error getting network information. Is your proxy configured properly?: Chyba při získávání informací o síti. Je vaše proxy správně nakonfigurována?\n    Proxy Warning: FreeTube nemá vestavěný proxy server, ale může se připojit k externímu proxy serveru, například k proxy serveru běžícímu na vašem počítači, jako je Tor, nebo k externímu proxy serveru, jako je proxy server SOCKS5 poskytovaný některými sítěmi VPN. Pokud je tato funkce povolena, ujistěte se, že je proxy server/Tor správně nakonfigurován, jinak FreeTube nebude moci načítat žádná data.\n    Proxy Username: Uživatelské jméno proxy\n    Proxy Password: Heslo proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Upozornit při přeskočení segmentu\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API SponsorBlock (výchozí je https://sponsor.ajay.app)\n    Enable SponsorBlock: Zapnout SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Do Nothing: Nic nedělat\n      Skip Option: Možnost přeskočení\n      Auto Skip: Automaticky přeskočit\n      Prompt To Skip: Zeptat se na přeskočení\n      Show In Seek Bar: Zobrazit v liště\n    Category Color: Barva kategorie\n    UseDeArrowTitles: Použít názvy videí z DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': Adresa URL API generátoru náhledů DeArrow (výchozí je https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Použít službu DeArrow pro náhledy\n  External Player Settings:\n    Custom External Player Arguments: Argumenty vlastního externího přehrávače\n    Custom External Player Executable: Spustitelný vlastní externí přehrávač\n    Ignore Unsupported Action Warnings: Ignorovat varování u nepodporovaných akcí\n    External Player: Externí přehrávač\n    External Player Settings: Externí přehrávač\n    Players:\n      None:\n        Name: Žádný\n    Ignore Default Arguments: Ignorovat výchozí argumenty\n  Parental Control Settings:\n    Parental Control Settings: Rodičovská kontrola\n    Hide Search Bar: Skrýt lištu vyhledávání\n    Show Family Friendly Only: Zobrazit pouze obsah vhodný pro rodiny\n    Hide Unsubscribe Button: Skrýt tlačítko ke zrušení odběru\n    Hide Uploader on Watch page: Skrýt autora na stránce sledování\n  Experimental Settings:\n    Experimental Settings: Experimentální\n    Warning: Tato nastavení jsou experimentální, při jejich aktivaci může docházet k pádům. Důrazně doporučujeme vytvářet zálohy. Používejte na vlastní nebezpečí!\n    Replace HTTP Cache: Nahradit mezipaměť HTTP\n  Password Dialog:\n    Enter Password To Unlock: Pro odemknutí nastavení zadejte heslo\n    Password: Heslo\n  Password Settings:\n    Password Settings: Heslo\n    Set Password To Prevent Access: Nastavte heslo pro zabránění přístupu k nastavení\n    Remove Password: Odebrat heslo\n    Set Password: Nastavit heslo\n  Sort Settings Sections (A-Z): Seřadit sekce nastavení (A-Z)\n  Return to Settings Menu: Vrátit se do nastavení\n  SABR:\n    Label: Povolti SABR jako backend DASH\n    Tooltip: SABR se v budoucím vydání stane jediným backendem DASH a nelze jej zakázat. Tento přepínač je poskytnut v případě, že má raná implementace závažné problémy.\nAbout:\n  #On About page\n  About: 'O aplikaci'\n  #& About\n  Source code: Zdrojový kód\n  Beta: Beta\n  Donate: Přispět\n  Credits: Poděkování\n  room rules: pravidla místnosti\n  Chat on Matrix: Chat na síti Matrix\n  Mastodon: Mastodon\n  Email: E-mail\n  Blog: Blog\n  Website: Webové stránky\n  FAQ: Často kladené dotazy\n  FreeTube Wiki: Wiki FreeTube\n  Downloads / Changelog: Ke stažení / Seznam změn\n  Translate: Překlady\n  these people and projects: těmto lidem a projektům\n  Please check for duplicates before posting: Před odesláním prosím zkontrolujte duplicity\n  GitHub issues: Chyby na GitHub\n  Report a problem: Nahlásit problém\n  Help: Nápověda\n  GitHub releases: Vydání na GitHubu\n  Discussions: Diskuze\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licencováno pod {licenseLink}\n  Please read the {roomRulesLink}: Přečtěte si prosím {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube existuje díky {creditsPageLink}\nProfile:\n  Profile Select: 'Výběr profilu'\n  All Channels: 'Všechny kanály'\n  Profile Manager: 'Správce profilu'\n  Create New Profile: 'Vytvořit nový profil'\n  Edit Profile: 'Editovat profil'\n  Color Picker: 'Výběr barvy'\n  Custom Color: 'Vlastní barva'\n  Profile Preview: 'Náhled profilu'\n  Create Profile: 'Vytvořit profil'\n  Update Profile: 'Aktualizovat profil'\n  Make Default Profile: 'Vytvořit výchozí profil'\n  Delete Profile: 'Odstranit profil'\n  Are you sure you want to delete this profile?: 'Opravdu chcete odstranit tento profil?'\n  All subscriptions will also be deleted.: 'Budou také odstraněny všechny odběry.'\n  Your profile name cannot be empty: 'Jméno profilu nemůže být prázdné'\n  Profile has been created: 'Profil byl vytvořen'\n  Profile has been updated: 'Profil byl upraven'\n  Your default profile has been set to {profile}: 'Váš výchozí profil byl nastaven na {profile}'\n  Removed {profile} from your profiles: 'Profil {profile} byl odebrán'\n  Your default profile has been changed to your primary profile: 'Váš výchozí profil byl změněn na primární profil'\n  '{profile} is now the active profile': '{profile} je nyní aktivním profilem'\n  Subscription List: 'Seznam odebíraných kanálů'\n  Other Channels: 'Ostatní kanály'\n  '{number} selected': '{number} vybrán'\n  Select All: 'Vybrat vše'\n  Select None: 'Zrušit výběr'\n  Delete Selected: 'Odstranit vybrané'\n  Add Selected To Profile: 'Přidat vybrané do profilu'\n  No channel(s) have been selected: 'Nebyly vybrány žádné kanály'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Toto je váš primární profil.  Opravdu chcete odstranit vybrané kanály?  Stejné kanály budou odstraněny ze všech profilů, ve kterých se nacházejí.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Opravdu chcete odstranit vybrané kanály?  Kanál tím nebude odstraněn z žádného jiného profilu.'\n#On Channel Page\n  Profile Filter: Filtr profilu\n  Profile Settings: Profil\n  Toggle Profile List: Přepnout seznam profilů\n  Open Profile Dropdown: Otevřít rozbalovací nabídku profilu\n  Close Profile Dropdown: Zavřít rozbalovací nabídku profilu\n  Profile Name: Jméno profilu\n  Edit Profile Name: Upravit jméno profilu\n  Create Profile Name: Vytvořit jméno profilu\nChannel:\n  Subscribe: 'Odebírat'\n  Unsubscribe: 'Zrušit odběr'\n  Channel has been removed from your subscriptions: 'Kanál byl odebrán z vašich odběrů'\n  Removed subscription from {count} other channel(s): 'Odběr odebrán z {count} dalších kanálů'\n  Added channel to your subscriptions: 'Kanál přidán do vašich odběrů'\n  Search Channel: 'Hledat v kanálu'\n  Your search results have returned 0 results: 'Vaše vyhledávání přineslo 0 výsledků'\n  Videos:\n    Videos: 'Videa'\n    This channel does not currently have any videos: 'Tento kanál momentálně nemá žádné videa'\n    Sort Types:\n      Newest: 'Nejnovější'\n      Oldest: 'Nejstarší'\n      Most Popular: 'Populární'\n  Playlists:\n    Playlists: 'Playlisty'\n    This channel does not currently have any playlists: 'Tento kanál nemá žádné playlisty'\n    Sort Types:\n      Last Video Added: 'Nejnověji přidané videa'\n      Newest: 'Nejnovější'\n      Oldest: 'Nejstarší'\n  About:\n    About: 'Informace'\n    Channel Description: 'Popis kanálu'\n    Featured Channels: 'Doporučené kanály'\n    Tags:\n      Tags: Štítky\n      Search for: Hledat štítek „{tag}“\n    Details: Podrobnosti\n    Joined: Připojeno\n    Location: Umístění\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Tento kanál je věkově omezen a v současné době jej nelze procházet na FreeTube.\n  This channel does not exist: Tento kanál neexistuje\n  This channel does not allow searching: Tento kanál neumožňuje vyhledávání\n  Channel Tabs: Karty kanálů\n  Posts:\n    This channel currently does not have any posts: Tento kanál v současné době nemá žádné příspěvky\n    Hide Answers: Skrýt odpovědi\n    votes: '{votes} hlasů'\n    Reveal Answers: Odhalit odpovědi\n    Video hidden by FreeTube: Video skryté programem FreeTube\n    View Full Post: Zobrazit celý příspěvek\n    Viewing Posts Only Supported By Invidious: Zobrazení příspěvků je podporováno pouze službou Invidious. Přejděte do karty komunity kanálu pro zobrazení jejího obsahu bez Invidious.\n  Live:\n    Live: Živě\n    This channel does not currently have any live streams: Tento kanál v současné době nemá žádné živé přenosy\n  Shorts:\n    This channel does not currently have any shorts: Tento kanál nemá žádné shorts\n  Releases:\n    Releases: Vydání\n    This channel does not currently have any releases: Tento kanál momentálně nemá žádná vydání\n  Podcasts:\n    This channel does not currently have any podcasts: Tento kanál momentálně nemá žádné podcasty\n    Podcasts: Podcasty\n  Home:\n    Home: Domovská stránka\n    View Playlist: Zobrazit playlist\n  Courses:\n    Courses: Kurzy\n    This channel does not currently have any courses: Tento kanál momentálně nemá žádné kurzy\nVideo:\n  Mark As Watched: 'Označit jako zhlédnuto'\n  Remove From History: 'Odstranit z historie'\n  Video has been marked as watched: 'Video bylo označeno jako zhlédnuté'\n  Video has been removed from your history: 'Video bylo odstraněno z vaší historie'\n  Open in YouTube: 'Otevřít na YouTube'\n  Copy YouTube Link: 'Kopírovat YouTube odkaz'\n  Open YouTube Embedded Player: 'Otevřít vložený přehrávač YouTube'\n  Copy YouTube Embedded Player Link: 'Zkopírovat odkaz na vložený přehrávač YouTube'\n  Open in Invidious: 'Otevřít na Invidious'\n  Copy Invidious Link: 'Kopírovat Invidious odkaz'\n  Open Channel in YouTube: 'Otevřít kanál na YouTube'\n  Copy YouTube Channel Link: 'Kopírovat odkaz kanálu YouTube'\n  Open Channel in Invidious: 'Otevřít kanál na Invidious'\n  Copy Invidious Channel Link: 'Kopírovat odkaz Invidious kanálu'\n  Views: 'Zhlédnutí'\n  Loop Playlist: 'Smyčka playlistu'\n  Shuffle Playlist: 'Zamíchat playlist'\n  Reverse Playlist: 'Obrátit playlist'\n  Previous: 'Předchozí'\n  Next: 'Další'\n  Watched: 'Zhlédnuto'\n  Autoplay: 'Automatické přehrávání'\n  Starting soon, please refresh the page to check again: 'Začínáme brzy, obnovte prosím stránku pro opětovnou kontrolu'\n  # As in a Live Video\n  Live: 'Živě'\n  Live Now: 'Živě nyní'\n  Live Chat: 'Živý chat'\n  Enable Live Chat: 'Zapnout živý chat'\n  Live Chat is currently not supported in this build.: 'Živý chat není v této verzi programu podporován.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Živý chat je povolen.  Po odeslání se zde zobrazí zprávy chatu.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Živý chat momentálně není podporován s Invidious API. Je vyžadováno přímé připojení k YouTube.'\n  Published:\n    In less than a minute: Za méně než minutu\n  Published on: 'Publikováno'\n#& Videos\n  Started streaming on: Začátek vysílání\n  Streamed on: Vysíláno\n  Video has been saved: Video bylo uloženo\n  Save Video: Uložit video\n  Video has been removed from your saved list: Video bylo odstraněno z vašeho uloženého seznamu\n  Sponsor Block category:\n    music offtopic: Není hudba\n    interaction: Interakce\n    self-promotion: Sebepropagace\n    outro: Závěr\n    intro: Úvod\n    sponsor: Sponzor\n    recap: Shrnutí\n    filler: Výplň\n  External Player:\n    Unsupported Actions:\n      opening specific video in a playlist (falling back to opening the video): Otevření specifického videa v seznamu skladeb\n      opening playlists: otevírání playlistů\n      starting video at offset: spuštění videa v určitém úseku\n      looping playlists: opakovaní seznamů skladeb\n      shuffling playlists: míchání seznamů skladeb\n      reversing playlists: obrácení seznamů skladeb\n      setting a playback rate: nastavení rychlosti přehrávání\n    playlist: playlist\n    UnsupportedActionTemplate: '{externalPlayer} nepodporuje: {action}'\n    OpeningTemplate: Otevřít {videoOrPlaylist} v {externalPlayer}...\n    video: video\n    OpenInTemplate: Otevřít v {externalPlayer}\n  Premieres: Premiéra\n  Show Super Chat Comment: Zobrazit komentář Super Chat\n  Scroll to Bottom: Posunout dolů\n  Upcoming: Nadcházející\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Živý chat není pro tento stream k dispozici. Je možné, že byl vypnut nahrávajícím.\n  Unhide Channel: Zobrazit kanál\n  Hide Channel: Skrýt kanál\n  More Options: Další možnosti\n  Player:\n    Stats:\n      Player Dimensions: Rozměry přehrávače {width}x{height}\n      Bitrate: 'Datový tok: {bitrate} kb/s'\n      Volume: 'Hlasitost: {volumePercentage} %'\n      CodecsVideoAudioNoItags: 'Kodeky: {videoCodec} / {audioCodec}'\n      Stats: Statistiky\n      Video ID: 'ID videa: {videoId}'\n      Media Formats: 'Formáty médií: {formats}'\n      Resolution: 'Rozlišení: {width}x{height}{''@''}{frameRate}'\n      Bandwidth: 'Šířka pásma: {bandwidth} kb/s'\n      Buffered: 'Načteno: {bufferedPercentage} %'\n      Dropped Frames / Total Frames: 'Vypuštěno snímků: {droppedFrames} / Celkem snímků: {totalFrames}'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Kodeky: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n    Skipped segment: Přeskočen segment {segmentCategory}\n    TranslatedCaptionTemplate: '{language} (přeloženo z jazyka {originalLanguage})'\n    Audio Tracks: Zvukové stopy\n    Theatre Mode: Režim kina\n    Exit Theatre Mode: Opustit režim kina\n    Full Window: Celé okno\n    Exit Full Window: Opustit celé okno\n    Take Screenshot: Pořídit snímek\n    Show Stats: Zobrazit statistiky\n    Hide Stats: Skrýt statistiky\n    You appear to be offline: Zdá se, že jste offline.\n    Playback will resume automatically when your connection comes back: Přehrávání bude automaticky pokračovat, jakmile budete opět připojeni.\n    Autoplay is off: Automatické přehrávání je vypnuto\n    Autoplay is on: Automatické přehrávání je zapnuto\n  IP block: YouTube zablokoval sledování videí z vaší IP adresy. Zkuste prosím přepnout na jinou VPN nebo proxy.\n  Unlisted: Neveřejné\n  MembersOnly: Videa určená pouze pro členy nelze na FreeTube sledovat, protože vyžadují přihlášení k účtu Google a placené členství v kanálu nahrávajícího.\n  AgeRestricted: Videa s věkovým omezením nelze na FreeTube sledovat, protože vyžadují přihlášení ke službě Google a použití účtu YouTube s ověřeným věkem.\n  DeArrow:\n    Show Modified Details: Zobrazit upravené podrobnosti\n    Show Original Details: Zobrazit původní podrobnosti\n  DRMProtected: Videa chráněná DRM nelze v aplikaci FreeTube přehrávat, protože vyžadují proprietární komponenty s uzavřeným zdrojovým kódem. Pokud chcete toto video sledovat, přehrajte si ho na oficiálních stránkách YouTube ve webovém prohlížeči s podporou DRM.\n#& Playlists\n  Save Watched Progress: Uložit průběh sledování\n  Watched Progress Saved: Průběh sledování uložen\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Zbývající čas prvotní reklamy: {remindingTimeSeconds} s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Zbývající čas pauzy SABR: {remindingTimeSeconds} s'\n  Popout Live Chat: Vyskakovací chat\nPlaylist:\n  #& About\n  View Full Playlist: 'Zobrazit celý seznam skladeb'\n  Last Updated On: 'Naposledy upraveno'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlist\n  Sort By:\n    DateAddedNewest: Datum přidání (nejnovější)\n    DateAddedOldest: Datum přidání (nejstarší)\n    AuthorAscending: Autor (A-Z)\n    AuthorDescending: Autor (Z-A)\n    VideoTitleDescending: Název (Z-A)\n    VideoTitleAscending: Název (A-Z)\n    Custom: Vlastní\n    VideoDurationAscending: Doba trvání (nejkratší)\n    VideoDurationDescending: Doba trvání (nejdelší)\n    PublishedOldest: Datum zveřejnění (nejstarší)\n    PublishedNewest: Datum zveřejnění (nejnovější)\nChange Format:\n  Change Media Formats: 'Změnit formát videa'\n  Use Dash Formats: 'Použít formáty DASH'\n  Use Legacy Formats: 'Použít starší formáty'\n  Use Audio Formats: 'Použít zvukové formáty'\n  Dash formats are not available for this video: 'Formáty DASH nejsou pro toto video dostupné'\n  Audio formats are not available for this video: 'Zvukové formáty nejsou pro toto video dostupné'\n  Legacy formats are not available for this video: Starší formáty nejsou pro toto video dostupné\nShare:\n  Share Video: 'Sdílet video'\n  Share Playlist: 'Sdílet playlist'\n  Include Timestamp: 'Včetně časového razítka'\n  Copy Link: 'Kopírovat odkaz'\n  Open Link: 'Otevřít odkaz'\n  Copy Embed: 'Kopírovat vložené'\n  Open Embed: 'Otevřít vložené'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL bylo zkopírováno do schránky'\n  Invidious Embed URL copied to clipboard: 'Vložené URL Invidious bylo zkopírováno do schránky'\n  Invidious Channel URL copied to clipboard: 'URL kanálu Invidious bylo zkopírováno do schránky'\n  YouTube URL copied to clipboard: 'URL YouTube bylo zkopírováno do schránky'\n  YouTube Embed URL copied to clipboard: 'Vložené URL YouTube bylo zkopírováno do schránky'\n  YouTube Channel URL copied to clipboard: 'URL kanálu YouTube bylo zkopírováno do schránky'\n\n  Share Channel: Sdílet kanál\n  Share Post: Sdílet příspěvek\nMini Player: 'Mini přehrávač'\nComments:\n  Comments: 'Komentáře'\n  Click to View Comments: 'Kliknutím zobrazíte komentáře'\n  Getting comment replies, please wait: 'Načítání odpovědí na komentář, čekejte prosím'\n  There are no more comments for this video: 'U tohoto videa nejsou žádné další komentáře'\n  Hide Comments: 'Skrýt komentáře'\n  Top comments: 'Nejlepší komentáře'\n  Newest first: 'Nejnovější první'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'K tomuto videu nejsou dostupné žádné komentáře'\n  Load More Comments: 'Načíst další komentáře'\n  Show More Replies: Načíst více výsledků\n  Pinned by: připnuto uživatelem\n  Member: Člen\n  View {replyCount} replies: Zobrazit 1 odpověď | Zobrazit {replyCount} odpovědí\n  Hearted: Se srdíčkem\n  Subscribed: Odebíráno\n  There are no comments available for this post: U tohoto příspěvku nejsou dostupné žádné komentáře\n  Hide {replyCount} replies: Skrýt 1 odpověď | Skrýt {replyCount} odpovědí\n  View 1 reply from {channelName}: Zobrazit 1 odpověď od {channelName}\n  View {replyCount} replies from {channelName} and others: Zobrazit {replyCount} odpovědí od {channelName} a dalších\nUp Next: 'Další'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Vyberte backend, který FreeTube používá k získávání informací. Místní API má integrovaný extraktor. Invidious API vyžaduje připojení k server Invidious.'\n    Fallback to Non-Preferred Backend on Failure: 'Pokud má vaše preferované API problém, FreeTube se automaticky pokusí použít vaše nepreferované API jako záložní metodu, pokud je povoleno.'\n    Thumbnail Preference: 'Všechny miniatury v celém FreeTube budou nahrazeny snímkem z videa, rozmazány nebo skryty namísto výchozí miniatury.'\n    Invidious Instance: 'Instance Invidious, ke které se FreeTube připojí za účelem volání API.'\n    Region for Trending: 'Oblast pro trendy vám umožní vybrat si zemi, ze které si přejete zobrazovat videa v trendech.'\n    External Link Handling: \"Zvolte výchozí chování při kliknutí na odkaz, který nelze otevřít ve FreeTube.\\nVe výchozím nastavení otevře FreeTube odkaz ve vašem výchozím prohlížeči.\\n\"\n    Open Deep Links In New Window: Adresy předané aplikaci FreeTube, například rozšířením pro prohlížeč nebo argumenty v příkazovém řádku, budou otevřeny v novém okně.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Připojí se k Invidious, aby poskytoval videa namísto přímého připojení k YouTube.'\n    Default Video Format: 'Nastavte formáty použité při přehrávání videa. Formáty DASH umožní přehrávat vyšší kvality. Starší formáty jsou omezeny na maximálně 360p, ale používají menší šířku pásma. Zvukové formáty jsou streamy obsahující pouze audio.'\n    Scroll Playback Rate Over Video Player: Když je kurzor na videu, stisknutím a podržením Ctrl (Command na Mac) a posouváním kolečka myši nahoru a dolu ovládejte rychlost přehrávání. Stisknutím a podržením Ctrl (Command na Mac) a stisknutím levého tlačítka myši se rychle vrátíte na výchozí rychlost přehrávání (1x, pokud není změněná v nastavení).\n    Skip by Scrolling Over Video Player: Pomocí rolovacího kolečka můžete video přeskakovat ve stylu MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Je-li povoleno, FreeTube použije RSS místo své výchozí metody pro získání vašich odběrů. RSS je rychlejší a brání blokování IP, neposkytuje ale určité informace, jako je délka videa, stav vysílání nebo příspěvky'\n\n# Toast Messages\n    Fetch Automatically: Při povolení tohoto nastavení FreeTube po spuštění a při přepnutí profilu automaticky načte vaše nová videa od vašich odběrů.\n  External Player Settings:\n    Ignore Warnings: Potlačuje varování, kdy současný externí přehrávač nepodporuje aktuální akci (např. obrácení seznamů skladeb apod.).\n    External Player: Volba externího přehrávače zobrazí ikonu pro otevření videa (či seznamu skladeb, pokud je podporován) v externím přehrávači, na náhledu. Varování, nastavení Invidious neovlivňují externí přehrávače.\n    Custom External Player Arguments: Jakékoliv vlastní argumenty příkazové řádky, které chcete předávat externímu přehrávač.\n    Custom External Player Executable: Ve výchozím nastavení Freetube předpokládá, že vybraný externí přehrávač lze nalézt přes proměnnou prostředí cesty PATH. V případě potřeby zde lze nastavit vlastní cestu.\n    DefaultCustomArgumentsTemplate: \"(Výchozí: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Neodesílat externímu přehrávači žádné výchozí argumenty kromě adresy URL videa (např. rychlost přehrávání, adresu URL playlistu atd.). Tato možnost se nevztahuje na vlastní argumenty.\n  Experimental Settings:\n    Replace HTTP Cache: Zakáže mezipaměť HTTP Electronu a povolí vlastní mezipaměť pro obrázky v paměti. Povede to ke zvýšenému využití RAM.\n  Distraction Free Settings:\n    Hide Channels: Zadejte ID kanálu pro skrytí všech videí, playlistů a samotného kanálu před zobrazením ve vyhledávání, trendech, nejpopulárnějších a doporučených. Zadané ID kanálu se musí zcela shodovat a rozlišují se v něm velká a malá písmena.\n    Hide Subscriptions Live: Toto nastavení je nadřazeno nastavením celé aplikace „{appWideSetting}“ v části „{subsection}“ v části „{settingsSection}“\n    Hide Videos, Playlists and Channels Containing Text: Zadejte slovo, část slova nebo frázi (velká a malá písmena nejsou rozlišovány) pro skrytí všech videí a playlistů, jejichž původní názvy obsahují zadání, napříč celým FreeTube, vyjma historie, vašich playlistů a videí uvnitř playlistů.\n    Hide Videos on Watch: Skrýt zhlédnutá videa z karet Videa, Shorts a Živě na stránkách odběrů a kanálů. Toto neovlivňuje domovskou kartu na stránkách kanálů\n  SponsorBlock Settings:\n    UseDeArrowTitles: Nahradit názvy videí vlastními názvy od uživatelů DeArrow.\n    UseDeArrowThumbnails: Nahradit náhledy videa těmi ze služby DeArrow.\nLocal API Error (Click to copy): 'Chyba lokálního API (kliknutím zkopírujete)'\nInvidious API Error (Click to copy): 'Chyba Invidious API (kliknutím zkopírujete)'\nFalling back to Invidious API: 'Přepínám na Invidious API'\nFalling back to Local API: 'Přepínám na lokální API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Toto video není k dispozici z důvodu chybějících formátů. K tomu může dojít z důvodu nedostupnosti země.'\nLoop is now disabled: 'Smyčka je vypnuta'\nLoop is now enabled: 'Smyčka je zapnuta'\nShuffle is now disabled: 'Zamíchání je vypnuto'\nShuffle is now enabled: 'Zamíchání je zapnuto'\nThe playlist has been reversed: 'Playlist byl obrácen'\nPlaying Next Video: 'Přehrávání dalšího videa'\nPlaying Previous Video: 'Přehrát předchozí video'\nCanceled next video autoplay: 'Automatické přehrávání dalšího videa bylo zrušeno'\n'The playlist has ended. Enable loop to continue playing': 'Seznam skladeb skončil.  Chcete-li pokračovat v přehrávání, povolte smyčku'\n\nYes: 'Ano'\nNo: 'Ne'\nPlaying Next Video Interval: Přehrávání dalšího videa bez prodlevy Kliknutím zrušíte. | Přehrávání dalšího videa za {nextVideoInterval} s. Kliknutím zrušíte. | Přehrávání dalšího videa za {nextVideoInterval} s. Kliknutím zrušíte.\nMore: Více\nUnknown YouTube url type, cannot be opened in app: Neznámý typ adresy URL YouTube, nelze v aplikaci otevřít\nOpen New Window: Otevřít nové okno\nDefault Invidious instance has been cleared: Výchozí instance Invidious byla vymazána\nDefault Invidious instance has been set to {instance}: Výchozí instance Invidious byla nastavena na {instance}\nSearch Bar:\n  Clear Input: Vymazat\n  Remove: Odstranit\nExternal link opening has been disabled in the general settings: Otevírání externích odkazů bylo zakázáno v obecných nastaveních\nAre you sure you want to open this link?: Opravdu chcete otevřít tento dokaz?\nNew Window: Nové okno\nChannels:\n  Channels: Kanály\n  Title: Seznam kanálů\n  Unsubscribe Prompt: Opavdu chcete zrušit odběr kanálu „{channelName}“?\n  Empty: Seznam vašich kanálů je momentálně prázdný.\n  Search bar placeholder: Hledat kanály\n  Count: Nalezeno {number} kanálů.\nScreenshot Success: Snímek uložen\nScreenshot Error: Snímek selhal. {error}\nClipboard:\n  Cannot access clipboard without a secure connection: Nelze přistupovat ke schránce bez zabezpečeného připojení\n  Copy failed: Kopírování do schránky selhalo\nChapters:\n  Chapters: Kapitoly\n  Key Moments: Klíčové momenty\nPreferences: Předvolby\nOk: Ok\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Tento hashtag nemá žádná videa\nChannel Hidden: Kanál {channel} přidán do filtru kanálů\nGo to page: Přejít na {page}\nChannel Unhidden: Kanál {channel} odebrán z filtrů kanálů\nTrimmed input must be at least N characters long: Oříznutý vstup musí být dlouhý alespoň 1 znak | Oříznutý vstup musí být dlouhý alespoň {length} znaků\nTag already exists: Štítek „{tagName}“ již existuje\nClose Banner: Zavřít panel\nAge Restricted:\n  This channel is age restricted: Tento kanál je omezen věkem\n  This video is age restricted: Toto video je omezeno věkem\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nFeed:\n  Feed Last Updated: 'Zdroj {feedName} naposledy aktualizován: {date}'\n  Refresh Feed: Obnovit {subscriptionName}\nMoments Ago: před chvílí\nYes, Delete: Ano, odstranit\nYes, Restart: Ano, restartovat\nYes, Open Link: Ano, otevřít odkaz\nCancel: Zrušit\nSearch character limit: Vyhledávaný dotaz obsahuje více znaků, než povolený limit ({searchCharacterLimit})\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Titulky\n    Closed Captions: Skryté titulky\n    360 Video: 360°\n    New: Nové\n    8K: 8K\n    VR180: VR180\n    3D: 3D\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Šipka dolů\n  arrowup: Šipka nahoru\n  arrowright: Šipka vpravo\n  arrowleft: Šipka vlevo\n  shift: Shift\n  enter: Enter\n  plus: Plus\nRight-click or hold to see history: Klikněte pravým pro zobrazení historie\nAutoplay Interruption Timer: Automatické přehrávání zrušeno kvůli {autoplayInterruptionIntervalHours} hodinám nečinnosti\nDescription:\n  Expand Description: '...další'\n  Collapse Description: Zobrazit méně\nKeyboardShortcutPrompt:\n  Refresh: Obnovit zdroj s nejnovějším obsahem\n  Full Window: Přepnout celé okno\n  Keyboard Shortcuts: Klávesové zkratky\n  Sections:\n    App:\n      Situational: Aplikace: situační\n      General: Aplikace: obecné\n    Video:\n      General: Video: obecné\n      Playback: Video: přehrávání\n  Show Keyboard Shortcuts: Zobrazit klávesové zkratky\n  History Backward: Přejít o jednu stránku zpět\n  History Forward: Přejít o jednu stránku vpřed\n  Navigate to Settings: Přejít na stránku Nastavení\n  Captions: Přepnout titulky\n  Stats: Zobrazit statistiku videa\n  Fullscreen: Přepnout celou obrazovku\n  Play: Přepnout pozastavení\n  Large Fast Forward: Přejít o 10 sekund vpřed / přetočit video vpřed na základě aktuální rychlosti přehrávání\n  Mute: Přepnout ztlumení\n  Decrease Video Speed: Snížit rychlost přehrávání na základě intervalu rychlosti přehrávání\n  Increase Video Speed: Zvýšit rychlost přehrávání na základě intervalu rychlosti přehrávání\n  Take Screenshot: Pořídit snímek obrazovky\n  Minimize Window: Minimalizovat okno\n  Close Window: Zavřít okno\n  Toggle Developer Tools: Přepnout vývojářské nástroje\n  Reset Zoom: Resetovat úroveň přiblížení / velikosti rozhraní\n  Zoom In: Přiblížit\n  Zoom Out: Oddálit\n  Focus Search: Zaměřit na lištu vyhledávání\n  Search in New Window: Hledat v novém okně\n  Last Frame: Předchozí snímek (při pozastavení)\n  Next Frame: Další snímek (při pozastavení)\n  Volume Up: Zvýšit hlasitost\n  Volume Down: Snížit hlasitost\n  Small Fast Forward: Přeskočit vpřed o X sekund v závislosti na intervalu přetáčení vpřed a aktuální rychlosti přehrávání videa\n  Last Chapter: Poslední kapitola\n  Next Chapter: Další kapitola\n  Navigate to History: Přejít na stránku Historie\n  New Window: Vytvořit nové okno\n  Theatre Mode: Přepnout režim kina\n  Focus Secondary Search: Zaměřit sekundární vyhledávací lištu (pokud existuje)\n  Picture in Picture: Přepnout režim obrazu v obraze\n  Large Rewind: Přejít o 10 sekund zpět / přetočit video zpět na základě aktuální rychlosti přehrávání\n  Small Rewind: Přeskočit zpět o X sekund v závislosti na intervalu přetáčení zpět a aktuální rychlosti přehrávání videa\n  Skip by Tenths: Přeskočit skrz video podle procenta (3 přeskočí na 30 % doby trvání)\n  End: Posunout na konec videa\n  Home: Posunout na začátek videa\n  Skip to Next Video: Přeskočit na další video v playlistu nebo další doporučené video\n  Skip to Previous Video: Přeskočit na předchozí video v playlistu\nshortcutLabelSeparator: ｜\nCompact side navigation: Kompaktní boční navigace\nExpand side navigation: Rozbalit boční navigaci\n"
  },
  {
    "path": "static/locales/cy.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Cymraeg'\n\n# Webkit Menu Bar\nFile: 'Ffeil'\nNew Window: 'Ffenestr Newydd'\nPreferences: 'Dewisiadau'\nQuit: 'Gadael'\nEdit: 'Golygu'\nUndo: 'Dadwneud'\nRedo: 'Ail-wneud'\nCut: 'Torri'\nCopy: 'Copïo'\nPaste: 'Gludo'\nDelete: 'Dileu'\nSelect all: 'Dewis y cyfan'\nToggle Developer Tools: 'Toglo Teclynnau Datblygwr'\nActual size: 'Gwir faint'\nZoom in: 'Chwyddo i mewn'\nZoom out: 'Chwyddo allan'\nToggle fullscreen: 'Toglo sgrin lawn'\nWindow: 'Ffenestr'\nMinimize: 'Lleihau'\nClose: 'Cau'\nBack: 'Nôl'\nForward: 'Ymlaen'\nOpen New Window: 'Agor Ffenestr Newydd'\nGo to page: 'Mynd i {page}'\n\nVersion {versionNumber} is now available!  Click for more details: 'Mae Fersiwn {versionNumber} bellach ar gael!  Cliciwch am fwy o manylion'\nDownload From Site: 'Llwytho i lawr o''r Wefan'\nA new blog is now available, {blogTitle}. Click to view more: 'Mae blogiad newydd bellach ar gael, {blogTitle}. Cliciwch i weld mwy'\nAre you sure you want to open this link?: 'Ydych chi wir eisiau agor y ddolen hon?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Fideos'\n  Shorts: 'Byrion'\n  Live: 'Byw'\n  Sort By: Trefnu yn Ôl\n  Counts:\n    Video Count: '1 fideo| {count} fideo'\n    Channel Count: '1 sianel | {count} sianel'\n    Subscriber Count: '1 tanysgrifiwr| {count} o danysgrifwyr'\n    View Count: '1 golwg | {count} golwg'\n    Watching Count: '1 yn gwylio | {count} yn gwylio'\n\n# Search Bar\n    Like Count: 1 hoffi | {count} hoffi\n    Comment Count: 1 sylw | {count} sylw\n  Posts: Postiadau\nSearch / Go to URL: 'Chwilio / Mynd i URL'\nSearch Bar:\n  Clear Input: 'Clirio Mewnbwn'\n  # In Filter Button\n  Remove: Tynnu\nSearch Filters:\n  Search Filters: 'Hidlyddion Chwilio'\n  Sort By:\n    Most Relevant: 'Mwyaf Perthnasol'\n    Rating: 'Sgôr'\n    Upload Date: 'Dyddiad Llwytho i Fyny'\n    View Count: 'Cyfrif Golygon'\n  Time:\n    Time: 'Amser'\n    Any Time: 'Unrhyw Bryd'\n    Last Hour: 'Yr Awr Diwethaf'\n    Today: 'Heddiw'\n    This Week: 'Wythnos Yma'\n    This Month: 'Mis Yma'\n    This Year: 'Eleni'\n  Type:\n    Type: 'Math'\n    All Types: 'Pob Math'\n    Videos: 'Fideos'\n    Channels: 'Sianeli'\n    Movies: 'Ffilmiau'\n    #& Playlists\n  Duration:\n    Duration: 'Hyd'\n    All Durations: 'Pob Hyd'\n    Short (< 4 minutes): 'Byr (< 4 munud)'\n    Medium (4 - 20 minutes): 'Canolig (4 - 20 munud)'\n    Long (> 20 minutes): 'Hir (> 20 munud)'\n  # On Search Page\n  Search Results: 'Canlyniadau Chwilio'\n  Fetching results. Please wait: 'Wrthi''n nôl canlyniadau. Arhoswch os gwelwch yn dda'\n  Fetch more results: 'Mwy o ganlyniadau'\n  There are no more results for this search: 'Dim canlyniadau pellach ar gyfer y chwilio hwn'\n# Sidebar\n  Features:\n    Creative Commons: Creative Commons\n    Live: Byw\n    360 Video: Fideo 360\n    Location: Lleoliad\n    HDR: HDR\n    VR180: VR180\n    HD: HD\n    Subtitles: Isdeitlau\n    3D: 3D\n    Features: Nodweddion\n    4K: 4K\n  Clear Filters: Clirio'r Hidlyddion\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Tanysgrifiadau'\n  # channels that were likely deleted\n  Error Channels: 'Sianeli gyda Gwallau'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Mae gan y proffil hwn nifer fawr o danysgrifiadau.  Yn gorfodi RSS i osgoi cyfyngu ar gyfraddau'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Mae eich rhestr Tanysgrifio yn wag ar hyn o bryd. Os ydych chi am fewnforio''ch tanysgrifiadau gallwch fynd i Gosodiadau Data a dewis Mewnforio Tanysgrifiadau neu gallwch chwilio am sianel a thanysgrifio iddyn nhw.'\n  Disabled Automatic Fetching: 'Rydych wedi analluogi cyrchu tanysgrifiad awtomatig. Adnewyddwch danysgrifiadau i''w gweld yma.'\n  Empty Channels: 'Nid oes gan eich sianeli tanysgrifio unrhyw fideos ar hyn o bryd.'\n  Empty Posts: 'Nid oes gan eich sianeli tanysgrifio unrhyw bostiadau ar hyn o bryd.'\n  Load More Videos: 'Llwytho Mwy o Fideos'\n  Load More Posts: 'Llwytho Mwy o Bostiadau'\n  Subscriptions Tabs: 'Tabiau Tanysgrifio'\n  All Subscription Tabs Hidden: 'Mae pob tab tanysgrifio wedi''i guddio. I weld cynnwys yma, dadguddiwch rhai tabiau yn yr adran \"{subsection}\" yn \"{settingsSection}\".'\nMore: 'Rhagor'\nChannels:\n  Channels: 'Sianeli'\n  Title: 'Rhestr Sianeli'\n  Search bar placeholder: 'Chwilio''r Sianeli'\n  Count: 'Wedi canfod {number} sianel.'\n  Empty: 'Mae eich rhestr sianeli yn wag ar hyn o bryd.'\n  Unsubscribe Prompt: 'Ydych chi''n siŵr eich bod am ddad-danysgrifio o \"{channelName}\"?'\nTrending:\n  Trending: 'Trendio'\n  Gaming: 'Gemau'\n  Trending Tabs: 'Tabiau Trendio'\n  Sports: Chwaraeon\nMost Popular: 'Poblogaidd'\nPlaylists: 'Rhestrau'\nUser Playlists:\n  Your Playlists: 'Eich Rhestrau Chwarae'\n  Empty Search Message: 'Nid oes unrhyw fideos yn y rhestr chwarae hon sy''n cyfateb i''ch chwilio'\n  Search bar placeholder: 'Chwilio am Restrau Chwarae'\n  This playlist currently has no videos.: Nid oes gan y rhestr chwarae hon unrhyw fideos ar hyn o bryd.\n  Add to Favorites: Ychwanegu at {playlistName}\n  Move Video Up: Symud Fideo i Fyny\n  Move Video Down: Symud Fideo i Lawr\n  AddVideoPrompt:\n    Save: Cadw\n    Select a playlist to add your N videos to: Dewiswch restr chwarae i ychwanegu eich fideo i | Dewiswch restr chwarae i ychwanegu eich {videoCount} fideos ati\n    Added {count} Times: Wedi'u Hychwanegu Eisoes | Ychwanegwyd {count} Gwaith\n    Toast:\n      You haven't selected any playlist yet.: Nid ydych wedi dewis unrhyw restr chwarae eto.\n      \"Video(s) added to {playlistCount} playlists\": \"Fideo(au) wedi'u hychwanegu at 1 rhestr chwarae | Fideo(au) wedi'u hychwanegu at {playlistCount} rhestr chwarae\"\n    Allow Adding Duplicate Video(s): Caniatáu Ychwanegu Fideo(s) Dyblyg\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": \"{videoCount}/{totalVideoCount} Fideo i'w Hychwanegu\"\n    N playlists selected: \"{playlistCount} Wedi'u Dewis\"\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": \"{videoCount}/{totalVideoCount} Fideos Eisoes wedi'u Hychwanegu\"\n    Search in Playlists: Chwilio o fewn Rhestrau Chwarae\n  Add to Playlist: Ychwanegu at y Rhestr Chwarae\n  Remove from Favorites: Tynnu o {playlistName}\n  Quick Bookmark Enabled: Nod Tudalen Cyflym wedi'i Galluogi\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Ydych chi'n siŵr eich bod am dynnu 1 fideo a wyliwyd o'r rhestr chwarae hon? Nid oes modd dadwneud hyn. | A ydych yn siŵr eich bod am ddileu {playlistItemCount} fideo a wyliwyd o'r rhestr chwarae hon? Nid oes modd dadwneud hyn.\n  Sort By:\n    LatestCreatedFirst: Dyddiad Crëwyd (Diweddaraf)\n    NameAscending: A-Z\n    EarliestCreatedFirst: Dyddiad Crëwyd (Hynaf)\n    LatestUpdatedFirst: Dyddiad Diweddarwyd (Mwyaf Newydd)\n    NameDescending: Z-A\n    LatestPlayedFirst: Dyddiad Chwaraewyd (Mwyaf Newydd)\n    EarliestPlayedFirst: Dyddiad Chwaraewyd (Hynaf)\n    EarliestUpdatedFirst: Dyddiad Diweddarwyd (Hynaf)\n  SinglePlaylistView:\n    Toast:\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Nid yw rhai fideos yn y rhestr chwarae wedi'u llwytho eto. Cliciwch yma i gopïo beth bynnag.\n      There were no videos to remove.: Nid oedd yna unrhyw fideos i'w tynnu.\n      This playlist has a video with a duration error: Mae'r rhestr chwarae hon yn cynnwys o leiaf un fideo nad oes ganddo hyd, bydd yn cael ei drefnu fel pe bai eu hyd yn sero.\n      This video cannot be moved up.: Nid oes modd symud y fideo hwn i fyny.\n      This video cannot be moved down.: Nid oes modd symud y fideo hwn i lawr.\n      Video has been removed: Mae'r fideo wedi'i dynnu\n      There was a problem with removing this video: Bu anhawster wrth dynnu'r fideo hwn\n      This playlist is already being used for quick bookmark.: Mae'r rhestr chwarae hon eisoes yn cael ei defnyddio ar gyfer nod tudalen cyflym.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Mae'r rhestr chwarae hon bellach yn cael ei defnyddio ar gyfer nodau tudalen cyflym yn lle {oldPlaylistName}. Cliciwch yma i ddadwneud\n      Reverted to use {oldPlaylistName} for quick bookmark: Wedi dychwelyd i ddefnyddio {oldPlaylistName} ar gyfer nod tudalen cyflym\n      Playlist has been updated.: Mae'r rhestr chwarae wedi'i diweddaru.\n      \"{videoCount} video(s) have been removed\": 1 fideo wedi'i dynnu | Mae {videoCount} fideo wedi'u dileu\n      This playlist is now used for quick bookmark: Mae'r rhestr chwarae hon bellach yn cael ei defnyddio ar gyfer nodau tudalen cyflym\n      This playlist is protected and cannot be removed.: Mae'r rhestr chwarae hon wedi'i diogelu ac nid oes modd ei dileu.\n      Playlist {playlistName} has been deleted.: Mae rhestr chwarae {playlistName} wedi'i dileu.\n      Playlist name cannot be empty. Please input a name.: Nid oes moddi'r rhestr chwarae fod yn wag. Rhowch enw.\n      There was an issue with updating this playlist.: Bu anhawster gyda diweddaru'r rhestr chwarae hon.\n      This playlist does not exist: Nid yw'r rhestr chwarae hon yn bodoli\n      Video has been removed. Click here to undo.: Mae'r fideo wedi'i dynnu. Cliciwch i ddadwneud.\n    Search for Videos: Chwilio am Fideos\n  CreatePlaylistPrompt:\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Mae yna restr chwarae gyda'r enw hwn yn barod. Dewiswch enw gwahanol.\n      Playlist {playlistName} has been successfully created.: Mae rhestr chwarae {playlistName} wedi'i chreu'n llwyddiannus.\n      There was an issue with creating the playlist.: Roedd problem gyda chreu'r rhestr chwarae.\n    New Playlist Name: Enw Rhestr Chwarae Newydd\n    Create: Creu\n  Export Playlist: Allforio'r Rhestr Chwarae Hon\n  The playlist has been successfully exported: Mae'r rhestr chwarae wedi'i allforio'n llwyddiannus\n  Delete Playlist: Dileu Rhestr Chwarae\n  Remove from Playlist: Dileu o'r Rhestr Chwarae\n  Playlist Name: Enw Rhestr Chwarae\n  Playlist Description: Disgrifiad o'r Rhestr Chwarae\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Ydych chi'n siŵr eich bod am dynnu 1 fideo dyblyg o'r rhestr chwarae hon? Nid oes modd dadwneud hyn. | Ydych chi'n siŵr eich bod am ddileu {playlistItemCount} fideo dyblyg o'r rhestr chwarae hon? Nid oes modd dadwneud hyn.\n  Cancel: Diddymu\n  Edit Playlist Info: Golygu Manylion Rhestr Chwarae\n  Copy Playlist: Copïo Rhestr Chwarae\n  Cannot delete the quick bookmark target playlist.: Methu dileu'r rhestr chwarae targed nod tudalen cyflym.\n  You have no playlists. Click on the create new playlist button to create a new one.: Nid oes gennych unrhyw restrau chwarae. Cliciwch ar y botwm creu rhestr chwarae newydd i greu un newydd.\n  Playlists with Matching Videos: Rhestrau chwarae gyda Fideos Cyfatebol\n  Create New Playlist: Creu Rhestr Chwarae Newydd\n  Enable Quick Bookmark With This Playlist: Galluogi Nod Tudalen Cyflym Gyda'r Rhestr Chwarae Hon\n  Remove Watched Videos: Dileu Fideos Wedi'u Gwylio\n  Are you sure you want to delete this playlist? This cannot be undone: Ydych chi'n siŵr eich bod am ddileu'r rhestr chwarae hon? Nid oes modd dadwneud hyn.\n  Save Changes: Cadw'r Newidiadau\n  Remove Duplicate Videos: Dileu Fideos Dyblyg\n  TotalTimePlaylist: 'Cyfanswm amser: {duration}'\n  Export list of URLs: Allforio'r rhestr o URLau\nHistory:\n  # On History Page\n  History: 'Hanes'\n  Watch History: 'Hanes Gwylio'\n  Your history list is currently empty.: 'Mae eich rhestr hanes yn wag ar hyn o bryd.'\n  Empty Search Message: 'Nid oes unrhyw fideos yn eich hanes sy''n cyfateb i''ch chwilio'\n  Search bar placeholder: \"Chwilio yn eich Hanes\"\n  Case Sensitive Search: Chwilio Nodau Mawr neu Fach\n  DateOldestHistory: Dyddiad Gwyliwyd (Hynaf)\n  DateNewestHistory: Dyddiad Gwyliwyd (Mwyaf Newydd)\nSettings:\n  # On Settings Page\n  Settings: 'Gosodiadau'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Mae angen i''r ap ailgychwyn er mwyn i newidiadau ddod i rym. Ailgychwyn a gosod y newidiadau?'\n  General Settings:\n    General Settings: 'Cyffredinol'\n    Check for Updates: 'Chwilio am Ddiweddariadau'\n    Check for Latest Blog Posts: 'Gwirio am y Postiadau Blog Diweddaraf'\n    Fallback to Non-Preferred Backend on Failure: 'Nôl i''r Cefn Diddewis ar Fethiant'\n    Enable Search Suggestions: 'Galluogi Awgrymiadau Chwilio'\n    Default Landing Page: 'Tudalen Glanio Ragosodedig'\n    Locale Preference: 'Dewis Iaith'\n    System Default: 'Rhagosodiad y System'\n    Preferred API Backend:\n      Preferred API Backend: 'Cefn API Dewisol'\n      Local API: 'API Lleol'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Math Fideo i''w Wylio'\n      Grid: 'Grid'\n      List: 'Rhestr'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Dewisiadau Llun Bach'\n      Default: 'Rhagosodedig'\n      Beginning: 'Dechrau'\n      Middle: 'Canol'\n      End: 'Diwedd'\n      Hidden: 'Cuddiedig'\n      Blur: 'Pŵl'\n    Current Invidious Instance: 'Enghraifft Invidious Cyfredol'\n    The currently set default instance is {instance}: 'Yr enghraifft rhagosodedig a osodwyd ar hyn o bryd yw {instance}'\n    No default instance has been set: 'Nid oes enghraifft rhagosodedig wedi''i gosod'\n    Current instance will be randomized on startup: 'Bydd yr enghraifft gyfredol ar gael ar hap wrth gychwyn'\n    Set Current Instance as Default: 'Gosod yr Enghraifft Gyfredol fel Rhagosodiad'\n    Clear Default Instance: 'Clirio''r Enghraifft Rhagosodedig'\n    View all Invidious instance information: 'Gweld holl fanylion enghraifft Invidious'\n    Region for Trending: 'Rhanbarth Trendio'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Trin Cyswllt Allanol'\n      Open Link: 'Agor Dolen'\n      Ask Before Opening Link: 'Gofyn Cyn Agor Dolen'\n      No Action: 'Dim Gweithred'\n    Auto Load Next Page:\n      Label: Llwytho'r Dudalen Nesaf yn Awtomatig\n      Tooltip: Llwytho tudalennau a sylwadau ychwanegol yn awtomatig.\n    Open Deep Links In New Window: Agor URLs Wedi'u Pasio i FreeTube mewn Ffenest Newydd\n    Minimize to system tray: Lleihau i ddror y system\n  Theme Settings:\n    Theme Settings: 'Thema'\n    Match Top Bar with Main Color: 'Cydweddu Bar Uchaf gyda Phrif Lliw'\n    Expand Side Bar by Default: 'Ehangu Bar Ochr fel rhagosodedig'\n    Disable Smooth Scrolling: 'Analluogi Sgrolio Llyfn'\n    UI Scale: 'Graddfa UI'\n    Hide Side Bar Labels: 'Cuddio Labeli Bar Ochr'\n    Hide FreeTube Header Logo: 'Cuddio Logo Pennawd FreeTube'\n    Base Theme:\n      Base Theme: 'Thema Sylfaenol'\n      Black: 'Du'\n      Dark: 'Tywyll'\n      System Default: 'Rhagosodiad y System'\n      Light: 'Golau'\n      Dracula: 'Draciwla'\n      Catppuccin Mocha: 'Catppuccin Mocha'\n      Pastel Pink: 'Pinc Meddal'\n      Hot Pink: 'Pinc Poeth'\n      Solarized Dark: Heulog Tywyll\n      Solarized Light: Heulog Golau\n      Nordic: Nordaidd\n      Gruvbox Dark: Gruvbox Tywyll\n      Gruvbox Light: Golau Gruvbox\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: Everforest Tywyll Caled\n      Everforest Dark Medium: Everforest Canolig Tywyll\n      Everforest Dark Low: Everforest Tywyll Isel\n      Everforest Light Hard: Everforest Caled Golau\n      Everforest Light Medium: Everforest Canolig Golau\n      Everforest Light Low: Everforest Isel Golau\n      Catppuccin Latte: Latte Catppuccino\n    Main Color Theme:\n      Main Color Theme: 'Thema Prif Lliw'\n      Red: 'Coch'\n      Pink: 'Pinc'\n      Purple: 'Porffor'\n      Deep Purple: 'Porffor Dwfn'\n      Indigo: 'Indigo'\n      Blue: 'Glas'\n      Light Blue: 'Glas Golau'\n      Cyan: 'Gwyrddlas'\n      Teal: 'Gwyrddlas Tywyll'\n      Green: 'Gwyrdd'\n      Light Green: 'Gwyrdd Golau'\n      Lime: 'Leim'\n      Yellow: 'Melyn'\n      Amber: 'Ambr'\n      Orange: 'Oren'\n      Deep Orange: 'Oren Dwfn'\n      Dracula Cyan: 'Cyan Dracula'\n      Dracula Green: 'Gwyrdd Draciwla'\n      Dracula Orange: 'Oren Draciwla'\n      Dracula Pink: 'Pinc Draciwla'\n      Dracula Purple: 'Piws Draciwla'\n      Dracula Red: 'Coch Draciwla'\n      Dracula Yellow: 'Melyn Draciwla'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mocha Rosewater'\n      Catppuccin Mocha Flamingo: 'Catppuccin Mocha Fflamingo'\n      Catppuccin Mocha Pink: 'Catppuccin Mocha Pinc'\n      Catppuccin Mocha Mauve: 'Catppuccin Mocha Mauve'\n      Catppuccin Mocha Red: 'Catppuccin Mocha Coch'\n      Catppuccin Mocha Maroon: 'Catppuccin Mocha Maroon'\n      Catppuccin Mocha Peach: 'Catppuccin Mocha Peach'\n      Catppuccin Mocha Yellow: 'Catppuccin Mocha Melyn'\n      Catppuccin Mocha Green: 'Catppuccin Mocha Gwyrdd'\n      Catppuccin Mocha Teal: 'Corhwyaden Catppuccin Mocha'\n      Catppuccin Mocha Sky: 'Awyr Catppuccin Mocha'\n      Catppuccin Mocha Sapphire: 'Catppuccin Mocha Sapphire'\n      Catppuccin Mocha Blue: 'Catppuccin Mocha Glas'\n      Catppuccin Mocha Lavender: 'Catppuccin Mocha Lafant'\n      Gruvbox Light Red: Gruvbox Golau Coch\n      Solarized Red: Coch Heulog\n      Solarized Violet: Fioled Heulog\n      Gruvbox Dark Green: Gruvbox Gwyrdd Tywyll\n      Gruvbox Dark Yellow: Gruvbox Melyn Tywyll\n      Gruvbox Dark Blue: Gruvbox Glas Tywyll\n      Gruvbox Dark Purple: Gruvbox Porffor Tywyll\n      Gruvbox Dark Aqua: Aqua Tywyll Gruvbox\n      Gruvbox Dark Orange: Gruvbox Oren Tywyll\n      Gruvbox Light Blue: Gruvbox Glas Ysgafn\n      Gruvbox Light Purple: Gruvbox Porffor Ysgafn\n      Gruvbox Light Orange: Gruvbox Oren Ysgafn\n      Solarized Magenta: Magenta Heulog\n      Solarized Orange: Oren Heulog\n      Solarized Green: Gwyrdd Heulog\n      Solarized Yellow: Melyn Heulog\n      Solarized Blue: Glas Heulog\n      Solarized Cyan: Cyan Heulog\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Fflamingo\n      Catppuccin Frappe Blue: Catppuccin Frappe Glas\n      Catppuccin Frappe Sky: Catppuccin Frappe awyr\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Saffir\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Dŵr Rhosyn\n      Catppuccin Frappe Pink: Catppuccin Frappe Pinc\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Coch\n      Catppuccin Frappe Maroon: Catppuccin Frappe Marŵn\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Yellow: Catppuccin Frappe Melyn\n      Catppuccin Frappe Green: Catppuccin Frappe Gwyrdd\n      Catppuccin Frappe Teal: Corhwyaden Frappe Catppuccin\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lafant\n      Everforest Dark Red: Everforest Coch Tywyll\n      Everforest Dark Orange: Everforest Oren Tywyll\n      Everforest Dark Yellow: Everforest Melyn Tywyll\n      Everforest Dark Green: Everforest Gwyrdd Tywyll\n      Everforest Dark Aqua: Everforest Aqua Tywyll\n      Everforest Light Red: Everforest Coch Golau\n      Everforest Dark Blue: Everforest Glas Tywyll\n      Everforest Dark Purple: Everforest Porffor Tywyll\n      Everforest Light Orange: Everforest Oren Golau\n      Everforest Light Yellow: Everforest Melyn Golau\n      Everforest Light Green: Everforest Gwyrdd Golau\n      Everforest Light Aqua: Everforest Aqua Golau\n      Everforest Light Blue: Everforest Glas Golau\n      Everforest Light Purple: Everforest Porffor Golau\n      Catppuccin Latte Mauve: Latte Catppuccino Porffor\n      Catppuccin Latte Red: Latte Catppuccino Coch\n    Secondary Color Theme: 'Thema Lliw Eilaidd'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'Chwaraewr'\n    Play Next Video: 'Awtochwarae Fidoes wedi''u Hargymell'\n    Turn on Subtitles by Default: 'Galluogi Isdeitlau Drwy Rhagosodiad'\n    Autoplay Videos: 'Cychwyn Fideos yn Awtomatig'\n    Proxy Videos Through Invidious: 'Fideos Dirprwy Trwy Invidious'\n    Autoplay Playlists: 'Awtochwarae Fideos Rhestrau Chwarae'\n    Enable Theatre Mode by Default: 'Galluogi Modd Theatr fel rhagosodiad'\n    Scroll Volume Over Video Player: 'Sgrolio Sain Dros Chwaraewr Fideo'\n    Scroll Playback Rate Over Video Player: 'Sgrolio Graddfa Chwarae Nôl Dros Chwaraewr Fideo'\n    Skip by Scrolling Over Video Player: 'Symud drwy Sgrolio Dros Chwaraewr Fideo'\n    Display Play Button In Video Player: 'Dangos Botwm Chwarae yn y Chwaraewr Fideo'\n    Enter Fullscreen on Display Rotate: 'Mynd i''r Sgrin Lawn wrth Cylchdroi Dangosydd'\n    Next Video Interval: 'Amserydd Cyfrif Lawr Awtochwarae'\n    Fast-Forward / Rewind Interval: 'Ysbaid Ymlaen / Nôl Cyflym'\n    Default Volume: 'Sain Rhagosodedig'\n    Default Playback Rate: 'Cyfradd Chwarae Rhagosodedig'\n    Max Video Playback Rate: 'Cyfradd Uchaf Chwarae Fideo'\n    Video Playback Rate Interval: 'Ysbaid Cyfradd Chwarae Fideo'\n    Default Video Format:\n      Default Video Format: 'Fformat Fideo Rhagosodedig'\n      Dash Formats: 'Fformatau DASH'\n      Legacy Formats: 'Hen Fformatau'\n      Audio Formats: 'Fformatau Sain'\n    Default Quality:\n      Default Quality: 'Ansawdd Rhagosodedig'\n      Auto: 'Awtomatig'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: 'Galluogi Lluniau Sgrin'\n      Format Label: 'Fformat Lluniau Sgrin'\n      Quality Label: 'Ansawdd Llun Sgrin'\n      Ask Path: 'Gofyn am Ffolder Cadw'\n      Folder Label: 'Ffolder Llun Sgrin'\n      Folder Button: 'Dewis Ffolder'\n      File Name Label: 'Patrwm Enw Ffeil'\n      File Name Tooltip: 'Gallwch ddefnyddio newidynnau isod. %Y Blwyddyn 4 digid. % M Mis 2 ddigid. %D Diwrnod 2 ddigid. % H Awr 2 ddigid. % N Munud 2 ddigid. %S Ail 2 ddigid. % T Millisecond 3 digid. %s Eiliad Fideo. %t Fideo Millisecond 3 digid. %i ID fideo.'\n      Error:\n        Forbidden Characters: 'Nodau Gwaharddedig'\n        Empty File Name: 'Enw Ffeil Gwag'\n    Autoplay Interruption Timer: Amserydd Oedi Awtochwarae\n    Default Viewing Mode:\n      Default Viewing Mode: Y Modd Gwylio Rhagosodedig\n      Full Screen: Sgrin Lawn\n      Picture in Picture: Llun mewn Llun\n      External Player: Chwaraewr Allanol ({externalPlayerName})\n      Theater: Theatr\n  External Player Settings:\n    External Player Settings: 'Chwaraewr Allanol'\n    External Player: 'Chwaraewr Allanol'\n    Ignore Unsupported Action Warnings: 'Anwybyddu Rhybuddion Gweithredu Heb Gefnogaeth'\n    Custom External Player Executable: 'Gweithredwr Chwaraewr Allanol Cyfaddas'\n    Custom External Player Arguments: 'Ymresymiadau Chwaraewr Allanol Cyfaddas'\n    Players:\n      None:\n        Name: 'Dim'\n    Ignore Default Arguments: Anwybyddu Ymresymiadau Rhagosodedig\n  Privacy Settings:\n    Privacy Settings: 'Preifatrwydd'\n    Remember History: 'Cofio Hanes Gwylio'\n    Save Watched Progress: 'Cadw''r Cynnydd Gwylio'\n    Save Watched Videos With Last Viewed Playlist: 'Cadw Fideos Wedi''u Gwylio Gyda Rhestr Chwarae Gwylio Diwethaf'\n    Clear Search Cache: 'Clirio''r Storfa Chwilio'\n    Are you sure you want to clear out your search cache?: 'Ydych chi''n siŵr eich bod am glirio''ch storfa chwilio?'\n    Search cache has been cleared: 'Mae''r storfa chwilio wedi''i chlirio'\n    Remove Watch History: 'Dileu Hanes Gwylio'\n    Are you sure you want to remove your entire watch history?: 'Ydych chi''n siŵr eich bod am ddileu eich hanes gwylio i gyd?'\n    Watch history has been cleared: 'Mae hanes gwylio wedi''i glirio'\n    Remove All Subscriptions / Profiles: 'Dileu Pob Tanysgrifiad / Proffil'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'A ydych yn siŵr eich bod am ddileu pob tanysgrifiad a phroffil?  Nid oes modd dadwneud hyn.'\n    All playlists have been removed: Mae'r holl restrau chwarae wedi'u dileu\n    Remove All Playlists: Dileu Pob Rhestr Chwarae\n    Are you sure you want to remove all your playlists?: Ydych chi'n siŵr eich bod am ddileu eich holl restrau chwarae?\n    Remember Search History: Cofio Hanes Chwilio\n    Clear Search History and Cache: Clirio Hanes Chwilio a'r Storfa\n    Are you sure you want to clear out your search history and cache?: Ydych chi'n siŵr eich bod eisiau clirio'ch hanes chwilio a'r storfa?\n    Search history and cache have been cleared: Mae'r hanes chwilio a'r storfa wedi'u clirio\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Awto\n        Semi-auto: Rhannol awto\n        Never: Byth\n      Tooltip: Awto = Cadw wrth gau pob tudalen fideo, pan mae fideo wedi gorffen a gwall wedi digwydd (e.e. cyfyngiad graddio a chyfnod gwylio wedi dod i ben). Rhannol awto = Fel Awto heblaw wrth adael tudalen fideo a gall gadw cynnydd gyda llaw drwy fotwm Cadw Cynnydd Gwylio, wedi'i leoli o dan y chwaraewr fideo.\n  Subscription Settings:\n    Subscription Settings: 'Tanysgrifiad'\n    Fetch Feeds from RSS: 'Nôl Ffrwd o''r RSS'\n    Fetch Automatically: 'Nôl Ffrwd yn Awtomatig'\n    Confirm Before Unsubscribing: Cadarnhau Cyn Dad-danysgrifio\n    To: At\n    'Limit the number of videos displayed for each channel': Cyfyngu ar nifer y fideos sy'n cael eu dangos ar gyfer pob sianel\n  Distraction Free Settings:\n    Distraction Free Settings: 'Dim Tarfu'\n    Sections:\n      Side Bar: 'Bar Ochr'\n      Subscriptions Page: 'Tudalen Tanysgrifiadau'\n      Channel Page: 'Tudalen Sianel'\n      Watch Page: 'Tudalen Wylio'\n      General: 'Cyffredinol'\n    Hide Video Views: 'Cuddio Golygon Fideo'\n    Hide Video Likes And Dislikes: 'Cuddio Hoffi a Chasáu Fideos'\n    Hide Channel Subscribers: 'Cuddio Tanysgrifwyr Sianel'\n    Hide Comment Likes: 'Cuddio Sylwadau Hoffi'\n    Hide Recommended Videos: 'Cuddio Fideos Da'\n    Hide Trending Videos: 'Cuddio Fideos Trendio'\n    Hide Popular Videos: 'Cuddio Fideos Poblogaidd'\n    Hide Playlists: 'Cuddio Rhestrau Chwarae'\n    Hide Live Chat: 'Cuddio Sgwrsio Byw'\n    Hide Active Subscriptions: 'Cuddio Tanysgrifiadau Gweithredol'\n    Hide Video Description: 'Cuddio Disgrifiad Fideo'\n    Hide Comments: 'Cuddio Sylwadau'\n    Hide Profile Pictures in Comments: 'Cuddio Lluniau Proffil mewn Sylwadau'\n    Display Titles Without Excessive Capitalisation: 'Dangos Teitlau Heb Prif Lythrennu Ac Atalnodi Gormodol'\n    Hide Live Streams: 'Cuddio Ffrydiau Byw'\n    Hide Upcoming Premieres: 'Cuddio Cyflwyniadau i''r Dyfodol'\n    Hide Sharing Actions: 'Cuddio Gweithredoedd Rhannu'\n    Hide Videos on Watch: 'Cuddio Fideos wrth Wylio'\n    Hide Chapters: 'Cuddio Penodau'\n    Hide Channels: 'Cuddio Fideos o Sianeli'\n    Hide Channels Disabled Message: 'Cafodd rhai sianeli eu rhwystro gan ddefnyddio dull adnabod ac ni chawsant eu prosesu. Mae nodwedd wedi''i rhwystro tra bod yr IDau hynny''n cael eu diweddaru'\n    Hide Channels Placeholder: 'ID Sianel'\n    Hide Channels Invalid: 'Roedd ID y sianel a ddarparwyd yn annilys'\n    Hide Channels API Error: 'Gwall wrth adalw defnyddiwr gyda''r ID a ddarparwyd. Gwiriwch eto a yw''r ID yn gywir.'\n    Hide Channels Already Exists: 'Mae ID y sianel eisoes yn bodoli'\n    Hide Featured Channels: 'Cuddio Sianeli Nodwedd'\n    Hide Channel Playlists: 'Cuddio Tab \"Rhestrau Chwarae\" Sianel'\n    Hide Channel Shorts: 'Cuddio Tab Sianel \"Byrion\"'\n    Hide Channel Podcasts: 'Cuddio Tab Sianel \"Podlediadau\"'\n    Hide Channel Releases: 'Cuddio Tab Sianel \"Rhyddhau\"'\n    Hide Subscriptions Videos: 'Cuddio Fideos Tanysgrifiadau'\n    Hide Subscriptions Shorts: 'Cuddio Tanysgrifiadau Byrion'\n    Hide Subscriptions Live: 'Cuddio Tanysgrifiadau Byw'\n    Hide Videos, Playlists and Channels Containing Text: Cuddio Fideos a Rhestrau Chwarae sy'n Cynnwys Testun\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Gair, Darn o Arian, neu Ymadrodd\n    Show Added Items: Dangos Eitemau Ychwanegwyd\n    Hide Channel Home: Cuddio Tab Sianel \"Cartref\"\n    Hide Channel Courses: Cuddio Tab \"Cyrsiau\" Sianel\n    Hide Channel Posts: Cuddio Tab Sianel \"Postiadau\"\n    Hide Subscriptions Posts: Cuddio Tabiau Tanysgrifiadau\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Dewis y Math o Allforio'\n    Import Subscriptions: 'Mewnforio Tanysgrifiadau'\n    Subscription File: 'Ffeil Tanysgrifio'\n    History File: 'Ffeil Hanes'\n    Playlist File: 'Ffeil Rhestr Chwarae'\n    Export Subscriptions: 'Allforio Tanysgrifiadau'\n    Export FreeTube: 'Allforio FreeTube'\n    Export YouTube: 'Allforio YouTube'\n    Export NewPipe: 'Allforio NewPipe'\n    Import History: 'Mewnforio Hanes'\n    Export History: 'Allforio Hanes'\n    Import Playlists: 'Mewnforio Rhestrau Chwarae'\n    Export Playlists: 'Allforio Rhestrau Chwarae'\n    Profile object has insufficient data, skipping item: 'Nid oes gan y gwrthrych proffil ddigon o ddata, gan hepgor yr eitem'\n    All subscriptions and profiles have been successfully imported: 'Mae''r holl danysgrifiadau a phroffiliau wedi''u mewnforio''n llwyddiannus'\n    All subscriptions have been successfully imported: 'Mae pob tanysgrifiad wedi''i fewnforio''n llwyddiannus'\n    Invalid subscriptions file: 'Ffeil tanysgrifiadau annilys'\n    Invalid history file: 'Ffeil hanes annilys'\n    Subscriptions have been successfully exported: 'Mae tanysgrifiadau wedi''u hallforio''n llwyddiannus'\n    History object has insufficient data, skipping item: 'Nid oes gan y gwrthrych hanes ddigon o ddata, gan hepgor yr eitem'\n    All watched history has been successfully imported: 'Mae''r holl hanes gwylio wedi''i fewnforio''n llwyddiannus'\n    All watched history has been successfully exported: 'Mae''r holl hanes gwylio wedi''i allforio''n llwyddiannus'\n    Playlist insufficient data: 'Dim digon o ddata ar gyfer rhestr chwarae \"{playlist}\", hepgor eitem'\n    All playlists has been successfully imported: 'Mae''r holl restrau chwarae wedi''u mewnforio yn llwyddiannus'\n    All playlists has been successfully exported: 'Mae''r holl restrau chwarae wedi''u hallforio''n llwyddiannus'\n    Unable to read file: 'Methu darllen ffeil'\n    Unable to write file: 'Methu ysgrifennu ffeil'\n    Unknown data key: 'Allwedd ddata anhysbys'\n    How do I import my subscriptions?: 'Sut ydw i''n mewnforio fy nhanysgrifiadau?'\n    Manage Subscriptions: 'Rheoli Tanysgrifiadau'\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Mae'r opsiwn hwn yn allforio fideos o bob rhestr chwarae i un rhestr chwarae o'r enw 'Ffefrynnau'.\\nSut i allforio a mewnforio fideos mewn rhestrau chwarae ar gyfer fersiwn hŷn o FreeTube:\\n1. Allforio eich rhestri chwarae gyda'r opsiwn hwn wedi'i alluogi.\\n2. Dileu eich holl restrau chwarae presennol gan ddefnyddio'r opsiwn Dileu Pob Rhestr Chwarae o dan Gosodiadau Preifatrwydd.\\n 3. Lansio'r fersiwn hŷn o FreeTube a mewngludo'r rhestri chwarae allforio.\\\"\"\n      Label: Allforio Rhestrau Chwarae Fersiynau FreeTube Hŷn\n    Search history file: Ffeil hanes chwilio\n    Search history: Hanes chwilio\n    Import search history: Mewnforio hanes chwilio\n    Export search history: Allforio hanes chwilio\n    All search history has been successfully imported: Mae'r holl hanes chwilio wedi'i fewnforio'n llwyddiannus\n    All search history has been successfully exported: Mae'r holl hanes chwilio wedi'i allforio'n llwyddiannus\n  Proxy Settings:\n    Proxy Settings: 'Dirprwy'\n    Enable Tor / Proxy: 'Galluogi Tor/Dirprwy'\n    Proxy Protocol: 'Protocol Dirprwy'\n    Proxy Host: 'Gweinydd Dirprwy'\n    Proxy Port Number: 'Rhif Porth Dirprwy'\n    Clicking on Test Proxy will send a request to: 'Bydd clicio ar Test Proxy yn anfon cais at'\n    Test Proxy: 'Profi Dirprwy'\n    Your Info: 'Eich Manylion'\n    Ip: 'Ip'\n    Country: 'Gwlad'\n    Region: 'Rhanbarth'\n    City: 'Dinas'\n    Error getting network information. Is your proxy configured properly?: 'Gwall wrth gael manylion rhwydwaith. A yw eich dirprwy wedi''i ffurfweddu''n gywir?'\n    Proxy Warning: Nid oes gan FreeTube ddirprwy mewnol ond gall gysylltu â dirprwy allanol, fel un sy'n rhedeg ar eich peiriant fel Tor neu ddirprwy allanol fel dirprwy SOCKS5 a ddarperir gan rai VPNs. Os yw wedi'i alluogi, gwnewch yn siŵr bod eich dirprwy/Tor wedi'i ffurfweddu'n gywir, neu ni fydd FreeTube yn gallu nôl unrhyw ddata.\n    Proxy Username: Enw defnyddiwr Dirprwy\n    Proxy Password: Cyfrinair Dirprwy\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'SponsorBlock'\n    Enable SponsorBlock: 'Galluogi SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'Url API SponsorBlock (Y rhagosodiad yw https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'Rhoi gwybod pan fydd segment y noddwr yn cael ei hepgor'\n    UseDeArrowTitles: 'Defnyddio Teitlau Fideo DeArrow'\n    Skip Options:\n      Skip Option: 'Hepgor y Dewis'\n      Auto Skip: 'Awto-Hepgor'\n      Show In Seek Bar: 'Dangos yn y Bar Chwilio'\n      Prompt To Skip: 'Annog i Hepgor'\n      Do Nothing: 'Gwneud Dim'\n    Category Color: 'Lliw Categori'\n    UseDeArrowThumbnails: Defnyddio DeArrow ar gyfer lluniau bach\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Thumbnail Generator API (Y rhagosodiad yw https://dearrow-thumb.ajay.app)\n  Parental Control Settings:\n    Parental Control Settings: 'Rheolaeth Rhieni'\n    Hide Unsubscribe Button: 'Cuddio Botwm Dad-danysgrifio'\n    Show Family Friendly Only: 'Dangos Dim ond Addas i Deuluoedd'\n    Hide Search Bar: 'Cuddio''r Bar Chwilio'\n    Hide Uploader on Watch page: Cuddio'r Llwythwr ar y dudalen Gwylio\n  Experimental Settings:\n    Experimental Settings: 'Arbrofol'\n    Warning: 'Mae''r gosodiadau hyn yn arbrofol, gallan nhw achosi chwalu wrth eu galluogi. Rydym yn argymell yn gryf gwneud copïau wrth gefn. Defnyddiwch ar eich menter eich hun!'\n    Replace HTTP Cache: 'Disodli Cache HTTP'\n  Password Dialog:\n    Password: 'Cyfrinair'\n    Enter Password To Unlock: 'Rhowch gyfrinair i ddatgloi gosodiadau'\n  Password Settings:\n    Password Settings: 'Cyfrinair'\n    Set Password To Prevent Access: 'Gosod cyfrinair i atal mynediad i osodiadau'\n    Set Password: 'Gosod Cyfrinair'\n    Remove Password: 'Tynnu Cyfrinair'\n  Return to Settings Menu: Nôl i'r Ddewislen Gosodiadau\n  Sort Settings Sections (A-Z): Adrannau Gosodiadau Trefnu (A-Z)\nAbout:\n  #On About page\n  About: 'Ynghylch'\n  Beta: 'Beta'\n  Source code: 'Cod ffynhonnell'\n  Downloads / Changelog: 'Llwytho i lawr / Cofnod newid'\n  GitHub releases: 'Ryddhau drwy GitHub'\n  Help: 'Cymorth'\n  FreeTube Wiki: 'Wici FreeTube'\n  FAQ: 'Cwestiynau Cyffredin'\n  Discussions: 'Sgyrsiau'\n  Report a problem: 'Adrodd am broblem'\n  GitHub issues: 'Materion GitHub'\n  Please check for duplicates before posting: 'Gwirio am ddyblygiadau cyn postio'\n  Website: 'Gwefan'\n  Blog: 'Blog'\n  Email: 'E-bost'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Sgwrsio ar Matrix'\n  room rules: 'rheolau ystafell'\n  Translate: 'Cyfieithu'\n  Credits: 'Cydnabyddiaeth'\n  these people and projects: 'y bobl a''r projectau hyn'\n  Donate: 'Cyfrannu'\n\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Trwyddedwyd o dan {licenseLink}\n  FreeTube is made possible by {creditsPageLink}: Mae Freetube ar gael oherwydd {creditsPageLink}\n  Please read the {roomRulesLink}: Darllenwch y {roomRulesLink}\nProfile:\n  Profile Settings: 'Proffil'\n  Toggle Profile List: 'Toglo Rhestr Proffil'\n  Profile Select: 'Dewis Proffil'\n  Profile Filter: 'Hidlydd Proffil'\n  All Channels: 'Pob Sianel'\n  Profile Manager: 'Rheoli Proffiliau'\n  Create New Profile: 'Creu Proffil Newydd'\n  Edit Profile: 'Golygu Proffil'\n  Edit Profile Name: 'Golygu Enw Proffil'\n  Create Profile Name: 'Creu Enw Proffil'\n  Profile Name: 'Enw Proffil'\n  Color Picker: 'Dewisydd Lliw'\n  Custom Color: 'Lliw Addas'\n  Profile Preview: 'Rhagweld Proffil'\n  Create Profile: 'Creu Proffil'\n  Update Profile: 'Diweddaru Proffil'\n  Make Default Profile: 'Gwneud Proffil Rhagosodedig'\n  Delete Profile: 'Dileu Proffil'\n  Are you sure you want to delete this profile?: 'Ydych chi''n siŵr eich bod am ddileu''r proffil hwn?'\n  All subscriptions will also be deleted.: 'Bydd pob tanysgrifiad hefyd yn cael ei ddileu.'\n  Your profile name cannot be empty: 'Ni all eich enw proffil fod yn wag'\n  Profile has been created: 'Mae proffil wedi''i greu'\n  Profile has been updated: 'Mae''r proffil wedi''i ddiweddaru'\n  Your default profile has been set to {profile}: 'Mae eich proffil rhagosodedig wedi''i osod i {profile}'\n  Removed {profile} from your profiles: 'Wedi tynnu {profile} o''ch proffiliau'\n  Your default profile has been changed to your primary profile: 'Mae eich proffil rhagosodedig wedi''i newid i''ch prif broffil'\n  '{profile} is now the active profile': '{profile} yw''r proffil gweithredol bellach'\n  Subscription List: 'Rhestr Tanysgrifiadau'\n  Other Channels: 'Sianeli Eraill'\n  '{number} selected': 'Mae {number} wedi''i ddewis'\n  Select All: 'Dewis y Cyfan'\n  Select None: 'Dewis Dim'\n  Delete Selected: 'Dileu''r Dewis'\n  Add Selected To Profile: 'Ychwanegu''r Dewis i Broffil'\n  No channel(s) have been selected: 'Dim sianel(i) wedi''u dewis'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Dyma''ch prif broffil.  Ydych chi''n siŵr eich bod am ddileu''r sianeli a ddewiswyd?  Bydd yr un sianeli yn cael eu dileu mewn unrhyw broffil sydd ynddo.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ydych chi''n siŵr eich bod am ddileu''r sianeli a ddewiswyd?  Ni fydd hyn yn dileu''r sianel o unrhyw broffil arall.'\n  Close Profile Dropdown: 'Cau''r Cwymplen Proffil'\n  Open Profile Dropdown: 'Agor Cwymplen Proffil'\n#On Channel Page\nChannel:\n  Subscribe: 'Tanysgrifio'\n  Unsubscribe: 'Dad-danysgrifio'\n  Channel has been removed from your subscriptions: 'Mae''r sianel wedi''i dynnu o''ch tanysgrifiadau'\n  Removed subscription from {count} other channel(s): 'Tynnwyd y tanysgrifiad o {count} sianel(i) arall'\n  Added channel to your subscriptions: 'Ychwanegwyd sianel at eich tanysgrifiadau'\n  Search Channel: 'Chwilio''r Sianel'\n  Your search results have returned 0 results: 'Mae eich canlyniadau chwilio wedi dod o hyd i 0 canlyniad'\n  This channel does not exist: 'Nid yw''r sianel hon yn bodoli'\n  This channel does not allow searching: 'Nid yw''r sianel hon yn caniatáu chwilio'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'Mae cyfyngiad oedran ar y sianel hon ac ar hyn o bryd nid oes modd ei gweld yn FreeTube.'\n  Channel Tabs: 'Tabiau Sianel'\n  Videos:\n    Videos: 'Fideos'\n    This channel does not currently have any videos: 'Nid oes gan y sianel hon unrhyw fideos ar hyn o bryd'\n    Sort Types:\n      Newest: 'Diweddaraf'\n      Oldest: 'Hynaf'\n      Most Popular: 'Poblogaidd'\n  Shorts:\n    This channel does not currently have any shorts: 'Nid oes gan y sianel hon unrhyw rhai byr ar hyn o bryd'\n  Live:\n    Live: 'Byw'\n    This channel does not currently have any live streams: 'Nid oes gan y sianel hon unrhyw ffrydiau byw ar hyn o bryd'\n  Playlists:\n    Playlists: 'Rhestrau Chwarae'\n    This channel does not currently have any playlists: 'Nid oes gan y sianel hon unrhyw restrau chwarae ar hyn o bryd'\n    Sort Types:\n      Last Video Added: 'Y Fideo Diwethaf a Ychwanegwyd'\n      Newest: 'Diweddaraf'\n      Oldest: 'Hynaf'\n  Podcasts:\n    Podcasts: 'Podlediadau'\n    This channel does not currently have any podcasts: 'Nid oes gan y sianel hon unrhyw bodlediadau ar hyn o bryd'\n  Releases:\n    Releases: 'Rhyddhadau'\n    This channel does not currently have any releases: 'Nid oes gan y sianel hon unrhyw fideos newydd ar hyn o bryd'\n  About:\n    About: 'Ynghylch'\n    Channel Description: 'Disgrifiad o''r Sianel'\n    Tags:\n      Tags: 'Tagiau'\n      Search for: 'Chwilio am \"{tag}\"'\n    Details: 'Manylion'\n    Joined: 'Dyddiad ymuno'\n    Location: 'Lleoliad'\n    Featured Channels: 'Sianeli Enghreifftiol'\n  Posts:\n    This channel currently does not have any posts: 'Nid oes gan y sianel hon unrhyw bostiadau ar hyn o bryd'\n    votes: '{votes} pleidlais'\n    Reveal Answers: 'Datgelu Atebion'\n    Hide Answers: 'Cuddio Atebion'\n    Video hidden by FreeTube: Fideo wedi'i guddio gan FreeTube\n    View Full Post: Gweld Post Llawn\n    Viewing Posts Only Supported By Invidious: Dim ond Invidious sy'n cefnogi Gweld Postiadau. Ewch i dab cymunedol sianel i weld cynnwys yno heb Invidious.\n  Home:\n    Home: Cartref\n    View Playlist: Gweld Rhestr Chwarae\n  Courses:\n    Courses: Cyrsiau\n    This channel does not currently have any courses: Nid oes gan y sianel hon unrhyw gyrsiau ar hyn o bryd\nVideo:\n  Mark As Watched: 'Marcio wedi''i Wylio'\n  Remove From History: 'Dileu o''r Hanes'\n  Video has been marked as watched: 'Fideo wedi''i farcio fel wedi''i wylio'\n  Video has been removed from your history: 'Mae''r fideo wedi''i dynnu o''ch hanes'\n  Save Video: 'Cadw''r Fideo'\n  Video has been saved: 'Mae''r fideo wedi''i gadw'\n  Video has been removed from your saved list: 'Mae''r fideo wedi''i dynnu oddi ar eich rhestr sydd wedi''i chadw'\n  Open in YouTube: 'Agor yn YouTube'\n  Copy YouTube Link: 'Copïo Dolen YouTube'\n  Open YouTube Embedded Player: 'Agor Chwaraewr Mewnblannu YouTube'\n  Copy YouTube Embedded Player Link: 'Copïo Dolen Chwaraewr Mewnblanwyd YouTube'\n  Open in Invidious: 'Agor yn Invidious'\n  Copy Invidious Link: 'Copïo Dolen Invidious'\n  Open Channel in YouTube: 'Agor Sianel yn YouTube'\n  Copy YouTube Channel Link: 'Copïo Dolen Sianel YouTube'\n  Open Channel in Invidious: 'Agor Sianel yn Invidious'\n  Copy Invidious Channel Link: 'Copïo Dolen Sianel Invidious'\n  Hide Channel: 'Cuddio Sianel'\n  Unhide Channel: 'Dangos Sianel'\n  Views: 'Golygon'\n  Loop Playlist: 'Cylchu Rhestr Chwarae'\n  Shuffle Playlist: 'Cymysgu Rhestr Chwarae'\n  Reverse Playlist: 'Gwrthdroi Rhestr Chwarae'\n  Previous: 'Blaenorol'\n  Next: 'Nesaf'\n  Watched: 'Wedi gwylio'\n  Autoplay: 'Awtochwarae'\n  Starting soon, please refresh the page to check again: 'Yn dechrau''n fuan, adnewyddwch y dudalen i wirio eto'\n  # As in a Live Video\n  Premieres: 'Premières'\n  Upcoming: 'I ddod'\n  Live: 'Byw'\n  Live Now: 'Yn Fyw'\n  Live Chat: 'Sgwrsio Byw'\n  Enable Live Chat: 'Galluogi Sgwrsio Byw'\n  Live Chat is currently not supported in this build.: 'Nid yw Sgwrsio Byw yn cael ei gefnogi yn yr fersiwn hwn ar hyn o bryd.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Mae sgwrsio byw wedi''i galluogi.  Bydd negeseuon sgwrsio yn ymddangos yma ar ôl eu hanfon.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Nid yw Sgwrsio Byw yn cael ei gefnogi gan yr API Invidious ar hyn o bryd.  Mae angen cysylltiad uniongyrchol â YouTube.'\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'Nid yw Sgwrsio Byw ar gael ar gyfer y ffrwd hon. Mae''n bosib ei fod wedi''i analluogi gan y llwythwr.'\n  Show Super Chat Comment: 'Dangos Sylw Sgwrsio Uwch'\n  Scroll to Bottom: 'Sgroliwch i''r Gwaelod'\n  Published:\n    In less than a minute: 'Mewn llai na munud'\n  Published on: 'Cyhoeddwyd ar'\n  Streamed on: 'Wedi''i ffrydio'\n  Started streaming on: 'Wedi dechrau ffrydio'\n  Sponsor Block category:\n    sponsor: 'Noddwr'\n    intro: 'Cyflwyniad'\n    outro: 'Diweddglo'\n    self-promotion: 'Hunan-Hyrwyddo'\n    interaction: 'Rhyngweithiad'\n    music offtopic: 'Cerddoriaeth Amrywiol'\n    recap: 'Adolygu'\n    filler: 'Llenwydd'\n  External Player:\n    OpenInTemplate: 'Agor yn {externalPlayer}'\n    video: 'fideo'\n    playlist: 'rhestr chwarae'\n    OpeningTemplate: 'Yn agor {videoOrPlaylist} yn {externalPlayer}...'\n    UnsupportedActionTemplate: 'Nid yw {externalPlayer} yn cefnogi: {action}'\n    Unsupported Actions:\n      starting video at offset: 'dechrau fideo wrth wrthbwyso'\n      setting a playback rate: 'gosod cyfradd chwarae yn ôl'\n      opening playlists: 'agor rhestrau chwarae'\n      opening specific video in a playlist (falling back to opening the video): 'agor fideo penodol mewn rhestr chwarae (gan ddychwelyd i agor y fideo)'\n      reversing playlists: 'gwrthdroi rhestrau chwarae'\n      shuffling playlists: 'cymysgu rhestrau chwarae'\n      looping playlists: 'cylchu rhestrau chwarae'\n#& Videos\n  Player:\n    Take Screenshot: Tynnu Llun Sgrin\n    Stats:\n      Resolution: 'Cydraniad: {width}x{height}{''@''}{frameRate}'\n      Bitrate: 'Cyfradd didau: {bitrate} kbps'\n      Bandwidth: 'Lled band: {bandwidth} kbps'\n      Buffered: 'Byffrwyd: {bufferedPercentage}%'\n      CodecsVideoAudioNoItags: 'Codecau: {videoCodec} / {audioCodec}'\n      Dropped Frames / Total Frames: 'Fframiau a ollyngwyd: {droppedFrames} / Cyfanswm Fframiau: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      Volume: 'Sain: {volumePercentage}%'\n      Stats: Ystadegau\n      Video ID: 'ID fideo: {videoId}'\n      Media Formats: 'Fformatau Cyfryngau: {formats}'\n      CodecsVideoAudio: 'Codecau: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Player Dimensions: 'Dimensiynau Chwaraewr: {width}x{height}'\n    You appear to be offline: Mae'n ymddangos eich bod all-lein.\n    Playback will resume automatically when your connection comes back: Bydd chwarae'n ailddechrau'n awtomatig pan ddaw'ch cysylltiad yn ôl.\n    Skipped segment: Hepgorwyd {segmentCategory} segment\n    Full Window: Ffenestr Lawn\n    Show Stats: Dangos Ystadegau\n    Theatre Mode: Modd Theatr\n    TranslatedCaptionTemplate: \"{language} (cyfieithwyd o'r \\\"{originalLanguage}\\\")\"\n    Audio Tracks: Traciau Sain\n    Exit Theatre Mode: Gadael y Modd Theatr\n    Exit Full Window: Gadael Ffenest Lawn\n    Hide Stats: Cuddio Ystadegau\n    Autoplay is on: Awtochwarae ymlaen\n    Autoplay is off: Awtochwarae i ffwrdd\n  More Options: Rhagor o Ddewisiadau\n  AgeRestricted: Nid oes modd gwylio fideos â chyfyngiad oedran gyda FreeTube gan fod angen mewngofnodi Google a defnyddio cyfrif YouTube a ddilysir yn ôl oedran arnynt.\n  MembersOnly: Nid oes modd gwylio fideos aelodau-yn-unig gyda FreeTube gan fod angen mewngofnodi Google ac aelodaeth â thâl i sianel yr llwythwr.\n  Unlisted: Heb ei restru\n  IP block: Mae YouTube wedi rhwystro'ch cyfeiriad IP rhag gwylio fideos. Ceisiwch newid i VPN neu ddirprwy arall.\n  DeArrow:\n    Show Modified Details: Dangos Manylion Addasedig\n    Show Original Details: Dangos Manylion Gwreiddiol\n  DRMProtected: Nid oes modd chwarae fideos gwarchodedig DRM yn FreeTube, gan fod angen cydrannau ffynhonnell caeedig perchnogol arnynt. Os ydych chi am wylio'r fideo hwn, gwyliwch ef ar wefan swyddogol YouTube mewn porwr gwe sydd wedi'i alluogi i chwarae DRM.\n#& Playlists\n  Save Watched Progress: Cadw Cynnydd Gwylio\n  Watched Progress Saved: Cynnydd Gwylio Wedi'i Gadw\n  Popout Live Chat: Llamlen Sgwrs\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Amser hysbysiadau cyn cyflwyniad: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': \"Amser cefnu SABR sy'n weddill: {remindingTimeSeconds}s\"\nPlaylist:\n  #& About\n  Playlist: 'Rhestr chwarae'\n  View Full Playlist: 'Gweld Rhestr Chwarae Llawn'\n  Last Updated On: 'Diweddarwyd Diwethaf ar'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    Custom: Cyfaddas\n    AuthorDescending: Awdur (Z-A)\n    VideoTitleAscending: Teitl (A-Z)\n    VideoTitleDescending: Teitl (Z-A)\n    VideoDurationDescending: Hyd (Hiraf)\n    DateAddedNewest: Dyddiad ychwanegwyd (Mwyaf Newydd)\n    AuthorAscending: Awdur (A-Z)\n    VideoDurationAscending: Hyd (Byrraf)\n    DateAddedOldest: Dyddiad ychwanegwyd (Hynaf)\n    PublishedNewest: Dyddiad cyhoeddwyd (Mwyaf Newydd)\n    PublishedOldest: Dyddiad cyhoeddwyd (Hynaf)\nChange Format:\n  Change Media Formats: 'Newid Fformatau Cyfryngau'\n  Use Dash Formats: 'Defnyddio Fformatau DASH'\n  Use Legacy Formats: 'Defnyddio Hen Fformatau'\n  Use Audio Formats: 'Defnyddio Fformatau Sain'\n  Dash formats are not available for this video: 'Nid oes fformatau DASH ar gael ar gyfer y fideo hwn'\n  Audio formats are not available for this video: 'Nid oes fformatau sain ar gael ar gyfer y fideo hwn'\n  Legacy formats are not available for this video: Nid oes hen fformatau ar gael ar gyfer y fideo hwn\nShare:\n  Share Video: 'Rhannu Fideo'\n  Share Channel: 'Rhannu Sianel'\n  Share Playlist: 'Rhannu Rhestr Chwarae'\n  Include Timestamp: 'Cynnwys Amser'\n  Copy Link: 'Copïo Dolen'\n  Open Link: 'Agor Dolen'\n  Copy Embed: 'Copi Mewnblaniad'\n  Open Embed: 'Agor Mewnblaniad'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious wedi''i gopïo i''r clipfwrdd'\n  Invidious Embed URL copied to clipboard: 'URL Mewnblaniad Invidious wedi''i gopïo i''r clipfwrdd'\n  Invidious Channel URL copied to clipboard: 'URL Sianel Invidious wedi''i gopïo i''r clipfwrdd'\n  YouTube URL copied to clipboard: 'URL YouTube wedi''i gopïo i''r clipfwrdd'\n  YouTube Embed URL copied to clipboard: 'URL Mewnblaniad YouTube wedi''i gopïo i''r clipfwrdd'\n  YouTube Channel URL copied to clipboard: 'URL Sianel YouTube wedi''i gopïo i''r clipfwrdd'\n  Share Post: Rhannu'r Postiad\nClipboard:\n  Copy failed: 'Methodd copïo i''r clipfwrdd'\n  Cannot access clipboard without a secure connection: 'Methu cael mynediad at y clipfwrdd heb gysylltiad diogel'\n\nChapters:\n  Chapters: 'Penodau'\n  Key Moments: Eiliadau Allweddol\nMini Player: 'Chwaraewr Bach'\nComments:\n  Comments: 'Sylwadau'\n  Click to View Comments: 'Cliciwch i Weld Sylwadau'\n  Getting comment replies, please wait: 'Yn derbyn atebion sylwadau, arhoswch'\n  There are no more comments for this video: 'Nid oes mwy o sylwadau ar gyfer y fideo hwn'\n  Hide Comments: 'Cuddio Sylwadau'\n  Top comments: 'Sylwadau poblogaidd'\n  Newest first: 'Diweddaraf yn gyntaf'\n  View {replyCount} replies: 'Gweld 1 ateb | Gweld {replyCount} ateb'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'Dangos Rhagor o Atebion'\n  There are no comments available for this video: 'Nid oes unrhyw sylwadau ar gael ar gyfer y fideo hwn'\n  Load More Comments: 'Llwytho Rhagor o Sylwadau'\n  Pinned by: 'Piniwyd gan'\n  Member: 'Aelod'\n  Subscribed: 'Tanysgrifiwyd'\n  Hearted: 'Hoffwyd'\n  There are no comments available for this post: Nid oes unrhyw sylwadau ar gael ar gyfer y cofnod hon\n  Hide {replyCount} replies: Cuddio 1 ateb | Cuddio {replyCount} ateb\n  View 1 reply from {channelName}: Gweld 1 ateb gan {channelName}\n  View {replyCount} replies from {channelName} and others: Gweld {replyCount} ateb gan {channelName} ac eraill\nUp Next: 'Nesaf'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Dewiswch y peirianwaith cefn y mae FreeTube yn ei ddefnyddio i gael data. Mae''r API lleol yn echdynnwr mewnol. Mae''r API Invidious angen gweinydd Invidious i gysylltu ag ef.'\n    Fallback to Non-Preferred Backend on Failure: 'Pan fydd gan eich API dewisol broblem, bydd FreeTube yn ceisio defnyddio''ch API nad yw''n well gennych yn awtomatig fel dull wrth gefn pan fydd wedi''i alluogi.'\n    Thumbnail Preference: 'Bydd holl luniau bach FreeTube yn cael eu newid i ffrâm o''r fideo, pŵl neu gudd yn lle''r llun bach rhagosodedig.'\n    Invidious Instance: 'Yr enghraifft Invidious y bydd FreeTube yn cysylltu ag ef ar gyfer galwadau API.'\n    Region for Trending: 'Mae''r rhanbarth o dueddiadau yn caniatáu ichi ddewis fideos tueddiadol o''r wlad rydych chi am eu gweld.'\n    External Link Handling: |\n      Dewiswch yr ymddygiad rhagosodedig pan fydd dolen, nad oes modd ei hagor yn FreeTube, yn cael ei chlicio.\n      Fel rhagosodiad bydd FreeTube yn agor y ddolen a gliciwyd yn eich porwr rhagosodedig.\n    Open Deep Links In New Window: Mae URLau wedi'u trosglwyddo i FreeTube, megis trwy ailgyfeirio estyniadau porwr neu ymresymiadau llinell orchymyn, yn cael eu hagor mewn ffenestr newydd.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Bydd yn cysylltu ag Invidious i weini fideos yn lle gwneud cysylltiad uniongyrchol â YouTube.'\n    Default Video Format: 'Gosodwch y fformatau i''w defnyddio pan fydd fideo yn chwarae. Gall fformatau DASH chwarae ansoddau uwch. Mae hen fformatau wedi''u cyfyngu i uchafswm o 360p ond yn defnyddio llai o led band. Mae fformatau sain yn ffrydiau sain yn unig.'\n    Scroll Playback Rate Over Video Player: 'Tra bod y cyrchwr dros y fideo, pwyswch a daliwch y fysell Control (Command Key ar Mac) a sgroliwch olwyn y llygoden ymlaen neu yn ôl i reoli''r gyfradd chwarae. Pwyswch a dal y fysell Rheoli (Command Key ar Mac) a chliciwch i''r chwith ar y llygoden i ddychwelyd yn gyflym i''r gyfradd chwarae rhagosodedig (1x oni bai ei fod wedi''i newid yn y gosodiadau).'\n    Skip by Scrolling Over Video Player: 'Defnyddiwch yr olwyn sgrolio i symud yn gyflym trwy''r fideo, arddull MPV.'\n  External Player Settings:\n    External Player: 'Bydd dewis chwaraewr allanol yn dangos eicon, ar gyfer agor y fideo (rhestr chwarae os yw''n cael ei gefnogi) yn y chwaraewr allanol, ar y llun bach. Rhybudd, nid yw gosodiadau Invidious yn effeithio ar chwaraewyr allanol.'\n    Custom External Player Executable: 'Fel rhagosodiad, bydd FreeTube yn cymryd y bydd modd dod o hyd i''r chwaraewr allanol a ddewiswyd trwy''r newidyn amgylchedd PATH. Os oes angen, mae modd gosod llwybr cyfaddas yma.'\n    Ignore Warnings: 'Atal rhybuddion pan nad yw''r chwaraewr allanol cyfredol yn cefnogi''r weithred gyfredol (e.e. gwrthdroi rhestri chwarae, ac ati).'\n    Custom External Player Arguments: 'Unrhyw ymresymiadau llinell orchymyn cyfaddas rydych am eu trosglwyddo i''r chwaraewr allanol.'\n    DefaultCustomArgumentsTemplate: \"(Rhagosodiad: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Peidiwch ag anfon unrhyw ymresymiadau rhagosodedig at y chwaraewr allanol ar wahân i'r URL fideo (e.e. cyfradd chwarae, URL rhestr chwarae, ac ati). Bydd ymresymiadau cyfaddas yn dal i gael eu trosglwyddo.\n  Distraction Free Settings:\n    Hide Channels: 'Rhowch ID sianel i guddio''r holl fideos, rhestri chwarae a''r sianel ei hun rhag ymddangos wrth chwilio, tueddu, mwyaf poblogaidd ac argymell. Rhaid i ID y sianel fod yn cyfateb yn llwyr ac mae''n sensitif i faint nodau.'\n    Hide Subscriptions Live: 'Mae''r gosodiad hwn wedi''i ddiystyru gan y gosodiad \"{appWideSetting}\" ar draws yr ap, yn adran \"{subsection}\" y \"{settingsSection}\"'\n    Hide Videos, Playlists and Channels Containing Text: Rhowch air, darn gair, neu ymadrodd (anwybyddu maint nodau) i guddio'r holl fideos a rhestri chwarae y mae eu teitlau gwreiddiol yn ei gynnwys trwy FreeTube gyfan, ac eithrio dim ond Hanes, Eich Rhestrau Chwarae, a fideos o fewn rhestrau chwarae.\n    Hide Videos on Watch: Yn cuddio fideos wedi'u gwylio o'r tabiau Fideos, Byrion a Byw ar dudalennau Tanysgrifio a Sianeli, Dyw hyn ddim yn effeithio ar y tab Cartref ar dudalennau Sianel\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Pan fydd wedi''i alluogi, bydd FreeTube yn defnyddio RSS yn lle ei ddull rhagosodedig ar gyfer cydio yn eich ffrwd tanysgrifio. Mae RSS yn gyflymach ac yn atal rhwystro IP, ond nid yw''n darparu gwybodaeth benodol fel hyd fideo, statws byw neu bostiadau'\n    Fetch Automatically: 'Pan fydd wedi''i alluogi, bydd FreeTube yn nôl eich ffrwd tanysgrifio yn awtomatig wrth gychwyn a phan fydd ffenestr newydd yn cael ei hagor.'\n  Experimental Settings:\n    Replace HTTP Cache: 'Yn analluogi storfa HTTP ar ddisg Electron ac yn galluogi storfa delwedd mewn cof cyfaddas. Bydd yn arwain at fwy o ddefnydd o RAM.'\n  SponsorBlock Settings:\n    UseDeArrowTitles: 'Amnewid teitlau fideo gyda theitlau a gyflwynwyd gan ddefnyddwyr o DeArrow.'\n\n# Toast Messages\n    UseDeArrowThumbnails: Amnewid lluniau bach fideo gyda lluniau bach o DeArrow.\nLocal API Error (Click to copy): 'Gwall API Lleol (Cliciwch i''w gopïo)'\nInvidious API Error (Click to copy): 'Gwall API Invidious (Cliciwch i''w gopïo)'\nFalling back to Invidious API: 'Dychwelyd i Invidious API'\nFalling back to Local API: 'Dychwelyd i Local API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Nid yw''r fideo hwn ar gael oherwydd fformatau coll. Gall hyn ddigwydd oherwydd nad yw gwlad ar gael.'\nUnknown YouTube url type, cannot be opened in app: 'Math url YouTube anhysbys, nid oes modd ei agor yn ap'\nLoop is now disabled: 'Cylchu nawr wedi''i hanalluogi'\nLoop is now enabled: 'Cylchu nawr wedi''i galluogi'\nShuffle is now disabled: 'Cymysgu nawr wedi''i analluogi'\nShuffle is now enabled: 'Cymysgu nawr wedi''i alluogi'\nThe playlist has been reversed: 'Mae''r rhestr chwarae wedi''i wrthdroi'\nPlaying Next Video: 'Yn Chwarae''r Fideo Nesaf'\nPlaying Previous Video: 'Yn Chwarae''r Fideo Blaenorol'\nPlaying Next Video Interval: 'Chwarae''r fideo nesaf mewn dim o dro. Cliciwch i ddiddymu. | Yn chwarae''r fideo nesaf ymhen {nextVideoInterval} eiliad. Cliciwch i ddiddymu. | Yn chwarae''r fideo nesaf ymhen {nextVideoInterval} eiliad. Cliciwch i ddiddymu.'\nCanceled next video autoplay: 'Wedi diddymu awtochwarae fideo nesaf'\n\nDefault Invidious instance has been set to {instance}: 'Mae''r enghraifft ragosodedig Invidious wedi''i osod i {instance}'\nDefault Invidious instance has been cleared: 'Mae''r enghraifft rhagosodedig o Invidious wedi''i chlirio'\n'The playlist has ended. Enable loop to continue playing': 'Mae''r rhestr chwarae wedi dod i ben.  Galluogwch gylchu i barhau i chwarae'\nExternal link opening has been disabled in the general settings: 'Mae agor dolen allanol wedi''i analluogi yn y gosodiadau cyffredinol'\nScreenshot Success: 'Llun sgrin wedi''i gadw'\nScreenshot Error: 'Methodd y llun sgrin. {error}'\nChannel Hidden: 'Mae {channel} wedi''i ychwanegu at hidlydd sianeli'\nChannel Unhidden: '{channel} wedi''i dynnu o''r hidlydd sianeli'\n\nHashtag:\n  Hashtag: 'Hashnod'\n  This hashtag does not currently have any videos: 'Nid oes gan yr hashnod hwn unrhyw fideos ar hyn o bryd'\nYes: 'Iawn'\nNo: 'Na'\nOk: 'Iawn'\nSearch character limit: Mae'r ymholiad chwilio hwn yn fwy na {searchCharacterLimit} nod\nCancel: Diddymu\nSearch Listing:\n  Label:\n    Subtitles: Isdeitlau\n    New: Newydd\n    3D: 3D\n    4K: 4K\n    Closed Captions: Capsiynau Caeedig\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\nFeed:\n  Feed Last Updated: 'Diweddarwyd ffrwd {feedName} ddiwethaf: {date}'\n  Refresh Feed: Adnewyddu {subscriptionName}\nClose Banner: Cau'r Faner\nYes, Delete: Iawn, Dileu\nYes, Restart: Iawn, Ailgychwyn\nYes, Open Link: Iawn, Agor Dolen\nAge Restricted:\n  This channel is age restricted: Mae cyfyngiad oedran ar y sianel hon\n  This video is age restricted: Mae cyfyngiad oedran ar y fideo hwn\nMoments Ago: eiliad yn ôl\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nTrimmed input must be at least N characters long: Rhaid i fewnbwn wedi'i docio fod o leiaf 1 nod o hyd | Rhaid i fewnbwn wedi'i docio fod o leiaf {length} nod\nTag already exists: Mae'r tag \"{tagName}\" eisoes yn bodoli\nKeyboardShortcutPrompt:\n  Search in New Window: Chwilio mewn ffenestr newydd\n  Last Frame: Ffrâm flaenorol (tra wedi oedi)\n  Next Frame: Ffrâm nesaf (tra wedi oedi)\n  Volume Up: Cynyddu lefel y sain\n  Volume Down: Gostwng lefel y sain\n  Show Keyboard Shortcuts: Dangos llwybrau byr bysellfwrdd\n  Focus Secondary Search: Canolbwyntiwch ar yr ail far chwilio (os oes un yn bresennol)\n  Captions: Toglo capsiynau YMLAEN/DIFFODD\n  Stats: Dangos ystadegau fideo\n  Fullscreen: Toglo sgrin lawn\n  Small Fast Forward: Eiliadau Ymlaen Cyflym X yn seiliedig ar yr Ysbaid Cyflym Ymlaen a'r Gyfradd Chwarae Fideo gyfredol\n  Keyboard Shortcuts: Llwybrau Byr Bysellfwrdd\n  Sections:\n    Video:\n      Playback: Fideo: Chwarae\n      General: Fideo: Cyffredinol\n    App:\n      Situational: 'Ap: Sefyllfaol'\n      General: Ap: Cyffredinol\n  History Forward: Ymlaen un dudalen\n  New Window: Creu ffenestr newydd\n  Large Rewind: Nôl 10 eiliad / Dychwelyd fideo yn seiliedig ar y Gyfradd Chwarae Fideo gyfredol\n  Play: Toglo chwarae / oedi\n  Mute: Toglo tewi\n  Decrease Video Speed: Lleihau cyflymder fideo yn seiliedig ar Ysbaid Cyfradd Chwarae Fideo\n  Full Window: Toglo ffenestr lawn\n  Skip by Tenths: Symud trwy fideo yn ôl canran (3 symudiad i 30% o'i hyd )\n  Take Screenshot: Tynnu llun sgrin\n  History Backward: Nôl un dudalen\n  Navigate to Settings: Llywio i'r dudalen Gosodiadau\n  Navigate to History: Llywio i'r dudalen Hanes\n  Refresh: Adnewyddu ffrwd gyda'r cynnwys diweddaraf\n  Picture in Picture: Toglo modd Llun-mewn-Llun\n  Large Fast Forward: Ymlaen 10 eiliad / Ymlaen Cyflym Fideo yn seiliedig ar y Gyfradd Chwarae Fideo gyfredol\n  Increase Video Speed: Cynyddu cyflymder fideo yn seiliedig ar Ysbaid Cyfradd Chwarae Fideo\n  Theatre Mode: Toglo modd theatr\n  Minimize Window: Lleihau ffenestr\n  Close Window: Cau ffenestr\n  Toggle Developer Tools: Toglo offer datblygwr\n  Reset Zoom: Ailosod lefel chwyddo / graddfa UI\n  Zoom In: Chwyddo mewn\n  Zoom Out: Chwyddo allan\n  Focus Search: Canolbwyntio ar y bar chwilio\n  Small Rewind: Dychwelyd X eiliadau yn seiliedig ar yr Ysbaid Dychwelyd a'r Gyfradd Chwarae Fideo gyfredol\n  Last Chapter: Pennod Olaf\n  Next Chapter: Pennod Nesaf\n  Home: Chwilio i ddechrau'r fideo\n  End: Chwilio i ddiwedd y fideo\n  Skip to Next Video: Ymlaen i'r fideo nesaf yn y rhestr chwarae neu fideo sy'n cael ei argymell\n  Skip to Previous Video: Nôl i'r fideo blaenorol mewn rhestr chwarae\nDescription:\n  Expand Description: '...rhagor'\n  Collapse Description: Dangos llai\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nKeys:\n  arrowup: Saeth i Fyny\n  ctrl: Ctrl\n  arrowdown: Saeth i Lawr\n  arrowright: Saeth Dde\n  arrowleft: Saeth Chwith\n  shift: Shift\n  plus: Plws\n  alt: Alt\n  enter: Enter\nRight-click or hold to see history: De-gliciwch neu ddal i weld yr hanes\nAutoplay Interruption Timer: Diddymwyd awtochwarae oherwydd {autoplayInterruptionIntervalHours} awr o heb ei ddefnyddio\nshortcutLabelSeparator: ｜\nCompact side navigation: Ochr llywio cryno\nExpand side navigation: Ehangu llywio ochr\n"
  },
  {
    "path": "static/locales/da.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Dansk'\n\n# Webkit Menu Bar\nFile: 'Fil'\nQuit: 'Afslut'\nEdit: 'Redigér'\nUndo: 'Fortryd'\nRedo: 'Omgør'\nCut: 'Klip'\nCopy: 'Kopiér'\nPaste: 'Indsæt'\nDelete: 'Slet'\nSelect all: 'Vælg alt'\nToggle Developer Tools: 'Slå udviklerværktøjer til/fra'\nActual size: 'Faktisk størrelse'\nZoom in: 'Zoom ind'\nZoom out: 'Zoom ud'\nToggle fullscreen: 'Slå fuld skærm til/fra'\nWindow: 'Vindue'\nMinimize: 'Minimér'\nClose: 'Luk'\nBack: 'Tilbage'\nForward: 'Fremad'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: Videoer\n\n  Counts:\n    Watching Count: 1 ser | {count} ser\n    Subscriber Count: 1 abonnent | {count} abonnenter\n    View Count: 1 visning | {count} visninger\n    Video Count: 1 video | {count} videoer\n    Channel Count: 1 kanal | {count} kanaler\n    Comment Count: 1 kommentar | {count} kommentarer\n    Like Count: 1 kan lide | {count} kan lide\n  Posts: Opslag\n  Live: Live\n  Sort By: Sortér efter\n  Shorts: Shorts\nVersion {versionNumber} is now available!  Click for more details: 'Version {versionNumber} er nu tilgængelig!  Klik for flere detaljer'\nDownload From Site: 'Hent fra websted'\nA new blog is now available, {blogTitle}. Click to view more: 'En ny blog er nu tilgængelig, {blogTitle}. Klik for at se mere'\n\n# Search Bar\nSearch / Go to URL: 'Søg/gå til URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Søgefiltre'\n  Sort By:\n    Most Relevant: 'Mest relevante'\n    Rating: 'Bedømmelse'\n    Upload Date: 'Dato for upload'\n    View Count: 'Visningstal'\n  Time:\n    Time: 'Tid'\n    Any Time: 'Altid'\n    Last Hour: 'Sidste time'\n    Today: 'I dag'\n    This Week: 'Denne uge'\n    This Month: 'Denne måned'\n    This Year: 'I år'\n  Type:\n    Type: 'Type'\n    All Types: 'Alle typer'\n    Videos: 'Videoer'\n    Channels: 'Kanaler'\n    #& Playlists\n    Movies: Film\n  Duration:\n    Duration: 'Varighed'\n    All Durations: 'Alle varigheder'\n    Short (< 4 minutes): 'Kort (< 4 minutter)'\n    Long (> 20 minutes): 'Lang (> 20 minutter)'\n  # On Search Page\n    Medium (4 - 20 minutes): Mellemlang (4-20 minutter)\n  Search Results: 'Søgeresultater'\n  Fetching results. Please wait: 'Henter resultater. Vent venligst'\n  Fetch more results: 'Hent flere resultater'\n# Sidebar\n  There are no more results for this search: Der er ikke flere resultater for denne søgning\n  Features:\n    Subtitles: Undertekster\n    HD: HD\n    3D: 3D\n    4K: 4K\n    Live: Live\n    HDR: HDR\n    Features: Funktioner\n    Location: Placering\n    360 Video: 360° video\n    VR180: VR180\n    Creative Commons: Creative Commons\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnenter'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Din abonnementsliste er tom. Hvis du vil importere dine abonnementer, gå til \"Dataindstillinger\" og vælg \"Importér Abonnementer\" – eller søg efter en kanal og abonner på den.'\n  Load More Videos: Indlæs flere videoer\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Denne profil har et stort antal abonnenter. Gennemtvinger RSS for at undgå adgangsbegrænsning\n  Error Channels: Kanaler med fejl\n  Empty Channels: De kanaler, du abonnerer på, har i øjeblikket ingen videoer.\n  Disabled Automatic Fetching: Du har deaktiveret automatisk hentning af abonnenter. Opdatér abonnenter for at se dem her.\n  Empty Posts: De kanaler, du abonnerer på, har i øjeblikket ingen opslag.\n  Load More Posts: Indlæs flere opslag\n  Subscriptions Tabs: Abonnement-faner\n  All Subscription Tabs Hidden: Alle abonnement-faner er skjult. Gør nogle faner synlige i \"{subsection}\" under \"{settingsSection}\" for at se indhold her.\nTrending:\n  Trending: 'Hot lige nu'\n  Trending Tabs: Hot lige nu-faner\n  Gaming: Gaming\n  Sports: Sport\nMost Popular: 'Mest populære'\nPlaylists: 'Playlister'\nUser Playlists:\n  Your Playlists: 'Dine playlister'\n  Search bar placeholder: Søg efter playlister\n  Empty Search Message: Ingen videoer i denne playliste matcher din søgning\n  This playlist currently has no videos.: Denne playliste har ingen videoer.\n  Create New Playlist: Opret ny playliste\n  Add to Playlist: Føj til playliste\n  You have no playlists. Click on the create new playlist button to create a new one.: Du har ingen playlister. Klik på \"Opret Ny Playliste\"-knappen for at oprette en.\n  Remove from Favorites: Fjern fra {playlistName}\n  Move Video Up: Flyt video op\n  Copy Playlist: Kopiér playliste\n  Remove Watched Videos: Fjern sete videoer\n  Delete Playlist: Slet playliste\n  Sort By:\n    EarliestCreatedFirst: Tidligst oprettet\n    EarliestUpdatedFirst: Tidligst opdateret\n    LatestPlayedFirst: Afspillet for nyligt\n    LatestCreatedFirst: Nyligt oprettet\n    LatestUpdatedFirst: Nyligt opdateret\n    EarliestPlayedFirst: Tidligst afspillet\n    NameDescending: Å-A\n    NameAscending: A-Å\n  Are you sure you want to delete this playlist? This cannot be undone: Er du sikker på, at du vil slette denne playliste? Det kan ikke fortrydes.\n  SinglePlaylistView:\n    Search for Videos: Søg efter videoer\n    Toast:\n      This video cannot be moved up.: Denne video kan ikke flyttes op.\n      This video cannot be moved down.: Denne video kan ikke flyttes ned.\n      Video has been removed: Videoen blev fjernet\n      There was a problem with removing this video: Der opstod et problem med at fjerne denne video\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Nogle videoer i denne playliste er ikke indlæst endnu. Klik her for at kopiere alligevel.\n      Playlist name cannot be empty. Please input a name.: Playlistenavn kan ikke være tomt. Indtast venligst et navn.\n      This playlist is protected and cannot be removed.: Denne playliste er beskyttet og kan ikke fjernes.\n      There was an issue with updating this playlist.: Der opstod et problem med at opdatere denne playliste.\n      This playlist does not exist: Denne playliste findes ikke\n      Playlist has been updated.: Playlisten blev opdateret.\n      \"{videoCount} video(s) have been removed\": 1 video blev fjernet | {videoCount} videoer blev fjernet\n      There were no videos to remove.: Der var ingen videoer at fjerne.\n      Playlist {playlistName} has been deleted.: Playlisten \"{playlistName}\" blev slettet.\n      This playlist has a video with a duration error: Denne playliste indeholder mindst én video uden varighed. Den sorteres, som om dens varighed er nul.\n      Video has been removed. Click here to undo.: Videoen blev fjernet. Klik her for at fortryde.\n      This playlist is now used for quick bookmark: Denne playliste bruges nu til hurtig bogmærke\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Denne playliste bruges nu som hurtigt bogmærke i stedet for {oldPlaylistName}. Klik her for at fortryde\n      Reverted to use {oldPlaylistName} for quick bookmark: Tilbageført til at bruge {oldPlaylistName} til hurtigt bogmærke\n      This playlist is already being used for quick bookmark.: Denne playliste bruges allerede til hurtig bogmærke.\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: Vælg en playliste, du vil føje videoen til | Vælg en playliste, du vil føje de {videoCount} videoer til\n    N playlists selected: '{playlistCount} valgt'\n    Search in Playlists: Søg i playlister\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: Du har ikke valgt nogen playliste endnu.\n    Added {count} Times: Allerede tilføjet | Tilføjet {count} gange\n    Save: Gem\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} videoer tilføjes'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videoer allerede tilføjet'\n    Allow Adding Duplicate Video(s): Tillad tilføjelse af duplikatvideo(er)\n  CreatePlaylistPrompt:\n    Toast:\n      There was an issue with creating the playlist.: Der opstod et problem med at oprette denne playliste.\n      There is already a playlist with this name. Please pick a different name.: En playliste med dette navn findes allerede. Vælg venligst et andet navn.\n      Playlist {playlistName} has been successfully created.: Playlisten \"{playlistName}\" blev oprettet.\n    New Playlist Name: Nyt playlistenavn\n    Create: Opret\n  Move Video Down: Flyt video ned\n  Playlist Description: Playlistebeskrivelse\n  Save Changes: Gem ændringer\n  Cancel: Annullér\n  Edit Playlist Info: Redigér playlisteinfo\n  Add to Favorites: Føj til {playlistName}\n  Remove from Playlist: Fjern fra playliste\n  Playlist Name: Playlistenavn\n  The playlist has been successfully exported: Playlisten blev eksporteret\n  Export Playlist: Eksportér denne playliste\n  Playlists with Matching Videos: Playlister med matchende videoer\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Er du sikker på, at du vil fjerne 1 duplikatvideo fra denne playliste? Det kan ikke fortrydes. | Er du sikker på, at du vil fjerne {playlistItemCount} duplikatvideoer fra denne playliste? Det kan ikke fortrydes.\n  Remove Duplicate Videos: Fjern duplikatvideoer\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Er du sikker på, at du vil fjerne 1 set video fra denne playliste? Det kan ikke fortrydes. | Er du sikker på, at du vil fjerne {playlistItemCount} sete videoer fra denne playliste? Det kan ikke fortrydes.\n  Cannot delete the quick bookmark target playlist.: Kan ikke slette den hurtige bogmærke målliste.\n  Quick Bookmark Enabled: Hurtigt bogmærke aktiveret\n  Enable Quick Bookmark With This Playlist: Aktiver Hurtigt bogmærke med denne afspilningsliste\n  TotalTimePlaylist: 'Samlet tid: {duration}'\nHistory:\n  # On History Page\n  History: 'Historik'\n  Watch History: 'Visningshistorik'\n  Your history list is currently empty.: 'Din historikliste er tom.'\n  Empty Search Message: Der er ingen videoer i din historik, som matcher din søgning\n  Search bar placeholder: Søg i historik\n  Case Sensitive Search: Versalfølsom søgning\nSettings:\n  # On Settings Page\n  Settings: 'Indstillinger'\n  General Settings:\n    General Settings: 'Generel'\n    Check for Updates: 'Søg efter opdateringer'\n    Check for Latest Blog Posts: 'Søg efter seneste blogindlæg'\n    Fallback to Non-Preferred Backend on Failure: 'Fallback til ikke-foretrukken backend ved fejl'\n    Enable Search Suggestions: 'Aktivér søgeforslag'\n    Default Landing Page: 'Standard landingsside'\n    Locale Preference: 'Sprogindstilling'\n    Preferred API Backend:\n      Preferred API Backend: 'Foretrukken API-backend'\n      Local API: 'Lokal API'\n      Invidious API: 'Invidious-API'\n    Video View Type:\n      Video View Type: 'Type af videovisning'\n      Grid: 'Gitter'\n      List: 'Liste'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Præference for miniaturebilleder'\n      Default: 'Standard'\n      Beginning: 'Begyndelse'\n      Middle: 'Midten'\n      End: 'Slutning'\n      Blur: Slør\n      Hidden: Skjult\n    Region for Trending: 'Region for \"Hot lige nu\"'\n        #! List countries\n    View all Invidious instance information: Se al information om Invidious-instanser\n    Clear Default Instance: Ryd standardinstans\n    External Link Handling:\n      External Link Handling: Håndtering af eksterne links\n      Open Link: Åbn link\n      No Action: Ingen handling\n      Ask Before Opening Link: Spørg før link åbnes\n    Current instance will be randomized on startup: Den aktuelle instans vælges tilfældigt ved opstart\n    System Default: Systemstandard\n    The currently set default instance is {instance}: Den nuværende standardinstans er {instance}\n    Current Invidious Instance: Nuværende Invidious-instans\n    No default instance has been set: Ingen standardinstans er angivet\n    Set Current Instance as Default: Angiv nuværende instans som standard\n    Auto Load Next Page:\n      Label: Auto-indlæs næste side\n      Tooltip: Indlæs flere sider og kommentarer automatisk.\n    Open Deep Links In New Window: Åbn URL'er sendt til FreeTube i et nyt vindue\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Match topbjælken med hovedfarven'\n    Base Theme:\n      Base Theme: 'Basistema'\n      Black: 'Sort'\n      Dark: 'Mørk'\n      Light: 'Lys'\n      Dracula: 'Dracula'\n      System Default: Systemstandard\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastelpink\n      Nordic: Nordisk\n      Gruvbox Dark: Gruvbox Mørk\n      Gruvbox Light: Gruvbox Lys\n      Catppuccin Frappe: Catppuccin Frappe\n      Hot Pink: Hot Pink\n      Solarized Dark: Solarized Mørk\n      Solarized Light: Solarized Lys\n      Everforest Dark Medium: Everforest Mørk Mellem\n      Everforest Dark Low: Everforest Mørk Lav\n      Everforest Light Hard: Everforest Lys Hård\n      Everforest Light Medium: Everforest Lys Mellem\n      Everforest Light Low: Everforest Lys Lav\n      Everforest Dark Hard: Everforest Mørk Hård\n    Main Color Theme:\n      Main Color Theme: 'Hovedfarvetema'\n      Red: 'Rød'\n      Pink: 'Lyserød'\n      Purple: 'Lilla'\n      Deep Purple: 'Mørkelilla'\n      Indigo: 'Indigoblå'\n      Blue: 'Blå'\n      Light Blue: 'Lyseblå'\n      Cyan: 'Cyan'\n      Teal: 'Turkis'\n      Green: 'Grøn'\n      Light Green: 'Lysegrøn'\n      Lime: 'Limegrøn'\n      Yellow: 'Gul'\n      Amber: 'Rav'\n      Orange: 'Orange'\n      Deep Orange: 'Dyb Orange'\n      Dracula Cyan: 'Dracula Cyan'\n      Dracula Green: 'Dracula Grøn'\n      Dracula Orange: 'Dracula Orange'\n      Dracula Pink: 'Dracula Lyserød'\n      Dracula Purple: 'Dracula Lilla'\n      Dracula Red: 'Dracula Rød'\n      Dracula Yellow: 'Dracula Gul'\n      Catppuccin Mocha Green: Catppuccin Mocha Grøn\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosenvand\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Mauve: Capttuccin Mocha Lysviolet\n      Catppuccin Mocha Peach: Catppuccin Mocha Fersken\n      Catppuccin Mocha Yellow: Catppuccin Mocha Gul\n      Catppuccin Mocha Pink: Catppuccin Mocha Lyserød\n      Catppuccin Mocha Red: Catppuccin Mocha Rød\n      Catppuccin Mocha Maroon: Catppuccin Mocha Rødbrun\n      Catppuccin Mocha Teal: Catppuccin Mocha Turkis\n      Catppuccin Mocha Sky: Catppuccin Mocha Himmel\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Safir\n      Catppuccin Mocha Blue: Catppuccin Mocha Blå\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavendel\n      Catppuccin Frappe Maroon: Catppuccin Frappe Rødbrun\n      Catppuccin Frappe Sky: Catppuccin Frappe Himmel\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Safir\n      Catppuccin Frappe Blue: Catppuccin Frappe Blå\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavendel\n      Gruvbox Dark Green: Gruvbox Mørk Grøn\n      Gruvbox Dark Yellow: Gruvbox Mørk Gul\n      Gruvbox Light Red: Gruvbox Lys Rød\n      Solarized Green: Solarized Grøn\n      Solarized Magenta: Solarized Magenta\n      Catppuccin Frappe Mauve: Catppuccin Frappe Lilla\n      Catppuccin Frappe Red: Catppuccin Frappe Rød\n      Catppuccin Frappe Peach: Catppuccin Frappe Fersken\n      Catppuccin Frappe Yellow: Catppuccin Frappe Gul\n      Catppuccin Frappe Teal: Catppuccin Frappe Blågrøn\n      Gruvbox Dark Blue: Gruvbox Mørk Blå\n      Gruvbox Dark Purple: Gruvbox Mørk Lilla\n      Gruvbox Light Blue: Gruvbox Lys Blå\n      Solarized Red: Solarized Rød\n      Solarized Violet: Solarized Violet\n      Solarized Blue: Solarized Blå\n      Everforest Dark Orange: Everforest Mørk Orange\n      Everforest Dark Aqua: Everforest Mørk Aqua\n      Everforest Dark Blue: Everforest Mørk Blå\n      Everforest Dark Purple: Everforest Mørk Lilla\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Everforest Light Blue: Everforest Lys Blå\n      Gruvbox Dark Orange: Gruvbox Mørk Orange\n      Gruvbox Light Purple: Gruvbox Lys Lilla\n      Everforest Dark Red: Everforest Mørk Rød\n      Everforest Dark Yellow: Everforest Mørk Gul\n      Everforest Dark Green: Everforest Mørk Grøn\n      Everforest Light Orange: Everforest Lys Orange\n      Everforest Light Yellow: Everforest Lys Gul\n      Everforest Light Green: Everforest Lys Grøn\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosenvand\n      Everforest Light Aqua: Everforest Lys Aqua\n      Solarized Cyan: Solarized Cyan\n      Everforest Light Purple: Everforest Lys Lilla\n      Gruvbox Dark Aqua: Gruvbox Mørk Aqua\n      Gruvbox Light Orange: Gruvbox Lys Orange\n      Everforest Light Red: Everforest Lys Rød\n      Solarized Yellow: Solarized Gul\n      Solarized Orange: Solarized Orange\n      Catppuccin Frappe Green: Catppuccin Frappe Grøn\n    Secondary Color Theme: 'Sekundær farvetema'\n        #* Main Color Theme\n    UI Scale: UI-skala\n    Disable Smooth Scrolling: Deaktivér jævn rulning\n    Expand Side Bar by Default: Udvid sidebjælken som standard\n    Hide Side Bar Labels: Skjul sidebjælkens etiketter\n    Hide FreeTube Header Logo: Skjul FreeTube's header-logo\n  Player Settings:\n    Player Settings: 'Afspiller'\n    Play Next Video: 'Auto-afspil anbefalede videoer'\n    Turn on Subtitles by Default: 'Aktivér undertekster som standard'\n    Autoplay Videos: 'Start videoer automatisk'\n    Proxy Videos Through Invidious: 'Kør videoer gennem Invidious-proxy'\n    Autoplay Playlists: 'Auto-afspil playlister'\n    Enable Theatre Mode by Default: 'Aktivér Biograftilstand som Standard'\n    Default Volume: 'Standardlydstyrke'\n    Default Playback Rate: 'Standardafspilningshastighed'\n    Default Video Format:\n      Default Video Format: 'Standardvideoformat'\n      Dash Formats: 'DASH-formater'\n      Legacy Formats: 'Ældre formater'\n      Audio Formats: 'Lydformater'\n    Default Quality:\n      Default Quality: 'Standardkvalitet'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: Aktivér skærmbillede\n      Format Label: Skærmbilledformat\n      Quality Label: Skærmbilledkvalitet\n      Folder Button: Vælg mappe\n      File Name Label: Filnavnsmønster\n      Error:\n        Forbidden Characters: Forbudte tegn\n        Empty File Name: Tomt filnavn\n      File Name Tooltip: Du kan bruge variablerne nedenfor. %Y – år (4 cifre). %M – måned (2 cifre). %D – dag (2 cifre). %H – time (2 cifre). %N – minut (2 cifre). %S – sekund (2 cifre). %T – millisekund (3 cifre). %s – video-sekund. %t – video-millisekund (3 cifre). %i – video-ID.\n      Ask Path: Bed om lagringsmappe\n      Folder Label: Skærmbilledmappe\n    Next Video Interval: Nedtællingstimer til auto-afspilning\n    Max Video Playback Rate: Maks. videoafspilningshastighed\n    Display Play Button In Video Player: Vis afspilningsknap i videoafspiller\n    Fast-Forward / Rewind Interval: Interval for spol frem/tilbage\n    Video Playback Rate Interval: Interval for videoafspilningshastighed\n    Scroll Playback Rate Over Video Player: Rul afspilningshastighed over videoafspiller\n    Scroll Volume Over Video Player: Rul lydstyrke over videoafspiller\n    Skip by Scrolling Over Video Player: Spring over ved at rulle over videoafspiller\n    Default Viewing Mode:\n      Theater: Biograf\n      Default Viewing Mode: Standardvisningstilstand\n      Full Screen: Fuldskærm\n      Picture in Picture: Billede-i-billede\n      External Player: Ekstern afspiller ({externalPlayerName})\n    Enter Fullscreen on Display Rotate: Skift til fuldskærm ved skærmrotation\n    Autoplay Interruption Timer: Timer til afbrydelse af autoplay\n  Privacy Settings:\n    Privacy Settings: 'Privatliv'\n    Remember History: 'Husk visningshistorik'\n    Save Watched Progress: 'Gem set fremskridt'\n    Clear Search Cache: 'Ryd Søgecache'\n    Are you sure you want to clear out your search cache?: 'Er du sikker på, at du vil rydde din søgecache?'\n    Search cache has been cleared: 'Søgecache blev ryddet'\n    Remove Watch History: 'Fjern visningshistorik'\n    Are you sure you want to remove your entire watch history?: 'Er du sikker på, at du vil fjerne hele din visningshistorik?'\n    Watch history has been cleared: 'Visningshistorik blev ryddet'\n    Remove All Subscriptions / Profiles: 'Fjern alle abonnementer/profiler'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Er du sikker på, at du vil fjerne alle abonnementer og profiler? Det kan ikke fortrydes.'\n    All playlists have been removed: Alle playlister blev fjernet\n    Are you sure you want to remove all your playlists?: Er du sikker på, at du vil fjerne alle dine playlister?\n    Save Watched Videos With Last Viewed Playlist: Gem sete videoer med sidst sete playliste\n    Remove All Playlists: Fjern alle playlister\n    Remember Search History: Husk søgehistorik\n    Are you sure you want to clear out your search history and cache?: Er du sikker på, at du vil rydde din søgehistorik og cache?\n    Search history and cache have been cleared: Søgehistorik og cache blev ryddet\n    Clear Search History and Cache: Ryd søgehistorik og cache\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Auto\n        Semi-auto: Semi-auto\n        Never: Aldrig\n      Tooltip: \"Auto: Gemmer ved videoens afslutning, fejl (f.eks. hastighedsbegrænsning, udløbet session) og når du forlader siden.\\nSemi-auto: Som Auto, men gemmer ikke, når du forlader siden. Du kan gemme manuelt med knappen 'Gem set fremskridt' under videoen.\"\n  Subscription Settings:\n    Subscription Settings: 'Abonnement'\n    Fetch Feeds from RSS: 'Hent feeds fra RSS'\n    Fetch Automatically: Hent feed automatisk\n    Confirm Before Unsubscribing: Bekræft før afmelding vist for hver kanal\n    To: Til\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Vælg eksporttype'\n    Import Subscriptions: 'Importér abonnementer'\n    Export Subscriptions: 'Eksportér abonnementer'\n    Export FreeTube: 'Eksportér FreeTube'\n    Export YouTube: 'Eksportér YouTube'\n    Export NewPipe: 'Eksportér NewPipe'\n    Import History: 'Importér historik'\n    Export History: 'Eksportér historik'\n    Profile object has insufficient data, skipping item: 'Profilobjekt har utilstrækkelige data; springer element over'\n    All subscriptions and profiles have been successfully imported: 'Det lykkedes at importere alle abonnementer og profiler'\n    All subscriptions have been successfully imported: 'Det lykkedes at importere alle abonnementer'\n    Invalid subscriptions file: 'Ugyldig abonnementsfil'\n    Invalid history file: 'Ugyldig historikfil'\n    Subscriptions have been successfully exported: 'Det lykkedes at eksportere abonnementer'\n    History object has insufficient data, skipping item: 'Historikobjekt har utilstrækkelige data; springer element over'\n    All watched history has been successfully imported: 'Visningshistorik blev importeret'\n    All watched history has been successfully exported: 'Visningshistorik blev eksporteret'\n    Unable to read file: 'Kan ikke læse fil'\n    Unable to write file: 'Kan ikke skrive fil'\n    Unknown data key: 'Ukendt datanøgle'\n    How do I import my subscriptions?: 'Hvordan importerer jeg mine abonnementer?'\n    Manage Subscriptions: Administrer abonnementer\n    Export Playlists: Eksportér playlister\n    Playlist insufficient data: Utilstrækkelige data for playlisten \"{playlist}\"; springer element over\n    Import Playlists: Importér playlister\n    All playlists has been successfully imported: Playlister blev importeret\n    All playlists has been successfully exported: Playlister blev eksporteret\n    History File: Historikfil\n    Playlist File: Playlistefil\n\n    Subscription File: Abonnementsfil\n    Export Playlists For Older FreeTube Versions:\n      Label: Eksportér playlister til ældre FreeTube-versioner\n      Tooltip: \"Denne indstilling eksporterer videoer fra alle playlister til én playliste kaldet \\\"Favoritter\\\".\\nSådan eksporterer og importerer du playlister til en ældre version af FreeTube:\\n1. Eksportér dine playlister med denne indstilling aktiveret.\\n2. Slet alle eksisterende playlister via \\\"Fjern alle playlister\\\" under Privatlivsindstillinger.\\n3. Start den ældre version af FreeTube og importér de eksporterede playlister.\"\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Fejl ved hentning af netværksoplysninger. Er din proxy korrekt konfigureret?\n    City: By\n    Region: Region\n    Country: Land\n    Ip: IP\n    Your Info: Din info\n    Test Proxy: Test proxy\n    Clicking on Test Proxy will send a request to: '\"Test proxy\" sender en anmodning til'\n    Proxy Port Number: Proxy-portnummer\n    Proxy Host: Proxy-vært\n    Proxy Protocol: Proxy-protokol\n    Enable Tor / Proxy: Aktivér Tor/proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube har ikke en indbygget proxy, men kan oprette forbindelse til en ekstern proxy, f.eks. en, der kører på din maskine som Tor, eller en ekstern proxy som SOCKS5, der tilbydes af nogle VPN'er. Hvis aktiveret, så sørg for, at din proxy/Tor er konfigureret korrekt, ellers vil FreeTube ikke kunne hente nogen data.\n  Distraction Free Settings:\n    Hide Active Subscriptions: Skjul aktive abonnementer\n    Hide Live Chat: Skjul live chat\n    Hide Popular Videos: Skjul populære videoer\n    Hide Trending Videos: Skjul \"Hot lige nu\"-videoer\n    Hide Recommended Videos: Skjul anbefalede videoer\n    Hide Comment Likes: Skjul likes på kommentarer\n    Hide Channel Subscribers: Skjul kanalabonnenter\n    Hide Video Likes And Dislikes: Skjul video-likes og -dislikes\n    Hide Video Views: Skjul videovisninger\n    Distraction Free Settings: Distraktionsfri\n    Hide Live Streams: Skjul livestreams\n    Hide Comments: Skjul kommentarer\n    Hide Sharing Actions: Skjul delingshandlinger\n    Hide Videos on Watch: 'Skjul videoer, når set'\n    Hide Video Description: Skjul videobeskrivelse\n    Hide Playlists: Skjul playlister\n    Hide Upcoming Premieres: Skjul kommende premierer\n    Hide Channels: Skjul videoer fra kanaler\n    Hide Chapters: Skjul kapitler\n    Hide Channels Already Exists: Kanal-ID findes allerede\n    Hide Featured Channels: Skjul fremhævede kanaler\n    Hide Videos, Playlists and Channels Containing Text: Skjul videoer og playlister med tekst\n    Hide Profile Pictures in Comments: Skjul profilbilleder i kommentarer\n    Display Titles Without Excessive Capitalisation: Vis titler uden overdreven brug af store bogstaver og tegnsætning\n    Sections:\n      General: Generelt\n      Side Bar: Sidebjælke\n      Channel Page: Kanalside\n      Subscriptions Page: Abonnementsside\n      Watch Page: Visningsside\n    Hide Channels Placeholder: Kanal-ID\n    Hide Channels API Error: Fejl ved hentning af bruger med det angivne ID. Tjek venligst, om ID'et er korrekt.\n    Hide Channel Playlists: Skjul \"Playlister\"-fanen på kanaler\n    Hide Channel Podcasts: Skjul \"Podcasts\"-fanen på kanaler\n    Hide Channels Invalid: Det angivne kanal-ID var ugyldigt\n    Hide Channels Disabled Message: Nogle kanaler blev blokeret via ID og blev ikke behandlet. Funktionen er blokeret, mens disse ID'er opdateres\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Ord, ordfragment eller sætning\n    Hide Channel Releases: Skjul \"Udgivelser\"-fanen på kanaler\n    Show Added Items: Vis tilføjede elementer\n    Hide Channel Shorts: Skjul \"Shorts\"-fanen på kanaler\n    Hide Channel Home: Skjul \"Hjem\"-fanen på kanaler\n    Hide Channel Courses: Skjul \"Kurser\"-fanen på kanaler\n    Hide Subscriptions Live: Skjul livestreams fra abonnementer\n    Hide Subscriptions Shorts: Skjul shorts fra abonnementer\n    Hide Subscriptions Videos: Skjul videoer fra abonnementer\n    Hide Channel Posts: Skjul \"Opslag\"-fanen på kanaler\n    Hide Subscriptions Posts: Skjul opslag fra abonnementer\n  The app needs to restart for changes to take effect. Restart and apply change?: Appen skal genstartes for at ændringerne kan træde i kraft. Genstart og anvend ændringer?\n  SponsorBlock Settings:\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API-URL (standard er https://sponsor.ajay.app)\n    Skip Options:\n      Auto Skip: Spring over automatisk\n      Skip Option: \"'Spring over'-indstilling\"\n      Prompt To Skip: Spørg om at springe over\n      Show In Seek Bar: Vis i statuslinje\n      Do Nothing: Gør intet\n    Category Color: Kategorifarve\n    Notify when sponsor segment is skipped: Underret, når et sponsorsegment springes over\n    SponsorBlock Settings: SponsorBlock\n    Enable SponsorBlock: Aktivér SponsorBlock\n    UseDeArrowTitles: Brug DeArrow-videotitler\n    UseDeArrowThumbnails: Brug DeArrow til miniaturebilleder\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Thumbnail Generator API-URL (standard er https://dearrow-thumb.ajay.app)\n  Parental Control Settings:\n    Hide Unsubscribe Button: Skjul afmeldingsknap\n    Show Family Friendly Only: Vis kun familievenligt\n    Parental Control Settings: Forældrekontrol\n    Hide Search Bar: Skjul søgefelt\n  External Player Settings:\n    Custom External Player Executable: Brugerdefineret ekstern afspiller\n    Custom External Player Arguments: Brugerdefinerede argumenter for ekstern afspiller\n    External Player: Ekstern afspiller\n    Ignore Unsupported Action Warnings: Ignorer advarsler om ikke-understøttede handlinger\n    External Player Settings: Ekstern afspiller\n    Players:\n      None:\n        Name: Ingen\n    Ignore Default Arguments: Ignorer standardargumenter\n  Password Settings:\n    Set Password: Indstil adgangskode\n    Password Settings: Adgangskode\n    Remove Password: Fjern adgangskode\n    Set Password To Prevent Access: Indstil en adgangskode for at forhindre adgang til indstillinger\n  Password Dialog:\n    Password: Adgangskode\n    Enter Password To Unlock: Indtast adgangskode for at låse indstillinger op\n  Experimental Settings:\n    Experimental Settings: Eksperimentel\n    Warning: Disse indstillinger er eksperimentelle og kan forårsage nedbrud, mens de er aktiveret. Det anbefales stærkt at lave sikkerhedskopier. Brug på eget ansvar!\n    Replace HTTP Cache: Erstat HTTP-cache\n  Return to Settings Menu: Tilbage til Indstillinger Menu\n  Sort Settings Sections (A-Z): Sortering af indstillinger Sektioner (A-Z)\nAbout:\n  #On About page\n  About: 'Om'\n  #& About\n  Donate: Donér\n  these people and projects: disse mennesker og projekter\n  Credits: Krediteringer\n  Translate: Oversæt\n  room rules: reglerne for rummet\n  Chat on Matrix: Chat på Matrix\n  Mastodon: Mastodon\n  Email: E-mail\n  Blog: Blog\n  Website: Websted\n  Please check for duplicates before posting: Kontrollér venligst for duplikater før opslag\n  GitHub issues: GitHub-problemer\n  Report a problem: Rapportér et problem\n  FAQ: OSS\n  FreeTube Wiki: FreeTube Wiki\n  Help: Hjælp\n  GitHub releases: GitHub-udgivelser\n  Downloads / Changelog: Downloads / Ændringslog\n  Source code: Kildekode\n  Beta: Beta\n  Discussions: Diskussioner\n  AGPLv3: AGPLv3\nProfile:\n  Profile Select: 'Vælg profil'\n  All Channels: 'Alle kanaler'\n  Profile Manager: 'Profilhåndtering'\n  Create New Profile: 'Opret ny profil'\n  Edit Profile: 'Rediger profil'\n  Color Picker: 'Farvevælger'\n  Custom Color: 'Brugerdefineret farve'\n  Profile Preview: 'Forhåndsvisning af profil'\n  Create Profile: 'Opret profil'\n  Update Profile: 'Opdater profil'\n  Make Default Profile: 'Gør til standardprofil'\n  Delete Profile: 'Slet profil'\n  Are you sure you want to delete this profile?: 'Er du sikker på, at du vil slette denne profil?'\n  All subscriptions will also be deleted.: 'Alle abonnementer slettes også.'\n  Your profile name cannot be empty: 'Dit profilnavn må ikke være tomt'\n  Profile has been created: 'Profilen blev oprettet'\n  Profile has been updated: 'Profilen blev opdateret'\n  Your default profile has been set to {profile}: 'Din standardprofil er blevet indstillet til {profile}'\n  Removed {profile} from your profiles: 'Fjernede {profile} fra dine profiler'\n  Your default profile has been changed to your primary profile: 'Din standardprofil er blevet ændret til din primære profil'\n  '{profile} is now the active profile': '{profile} er nu den aktive profil'\n  Subscription List: 'Abonnementsliste'\n  Other Channels: 'Andre kanaler'\n  '{number} selected': '{number} valgt'\n  Select All: 'Vælg alle'\n  Select None: 'Vælg ingen'\n  Delete Selected: 'Slet valgte'\n  Add Selected To Profile: 'Føj valgte til profil'\n  No channel(s) have been selected: 'Der er ikke valgt nogen kanal(er)'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Dette er din primære profil. Er du sikker på, at du vil slette de valgte kanaler? De samme kanaler slettes i alle profiler, hvor de findes.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Er du sikker på, at du vil slette de valgte kanaler? Dette sletter ikke kanalen fra andre profiler.'\n#On Channel Page\n  Profile Filter: Profilfilter\n  Profile Settings: Profil\n  Create Profile Name: Opret profilnavn\n  Profile Name: Profilnavn\n  Edit Profile Name: Rediger profilnavn\n  Toggle Profile List: Vis/skjul profil-liste\n  Close Profile Dropdown: Luk profil-rullemenu\n  Open Profile Dropdown: Åbn profil-rullemenu\nChannel:\n  Subscribe: 'Abonnér'\n  Unsubscribe: 'Afmeld'\n  Channel has been removed from your subscriptions: 'Kanalen blev fjernet fra dine abonnementer'\n  Removed subscription from {count} other channel(s): 'Fjernede abonnement fra {count} andre kanaler'\n  Added channel to your subscriptions: 'Føjede kanal til dine abonnementer'\n  Search Channel: 'Kanalsøgning'\n  Your search results have returned 0 results: 'Dine søgeresultater gav 0 resultater'\n  Videos:\n    Videos: 'Videoer'\n    This channel does not currently have any videos: 'Denne kanal har i øjeblikket ingen videoer'\n    Sort Types:\n      Newest: 'Nyeste'\n      Oldest: 'Ældste'\n      Most Popular: 'Mest populære'\n  Playlists:\n    Playlists: 'Playlister'\n    This channel does not currently have any playlists: 'Denne kanal har i øjeblikket ingen playlister'\n    Sort Types:\n      Last Video Added: 'Sidste tilføjede video'\n      Newest: 'Nyeste'\n      Oldest: 'Ældste'\n  About:\n    About: 'Om'\n    Channel Description: 'Kanalbeskrivelse'\n    Featured Channels: 'Fremhævede kanaler'\n    Details: Detaljer\n    Tags:\n      Search for: Søg efter \"{tag}\"\n      Tags: Tags\n    Joined: Tilmeldt\n    Location: Placering\n  Posts:\n    Hide Answers: Skjul svar\n    This channel currently does not have any posts: Denne kanal har i øjeblikket ingen opslag\n    Video hidden by FreeTube: Video skjult af FreeTube\n    votes: '{votes} stemmer'\n    Reveal Answers: Vis svar\n    View Full Post: Se hele opslaget\n    Viewing Posts Only Supported By Invidious: Visning af opslag understøttes kun af Invidious. Gå til en kanals fællesskabsfane for at se indholdet uden Invidious.\n  This channel does not allow searching: Denne kanal tillader ikke søgning\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Denne kanal er aldersbegrænset og kan i øjeblikket ikke ses på FreeTube.\n  Live:\n    This channel does not currently have any live streams: Denne kanal har i øjeblikket ingen livestreams\n    Live: Live\n  Podcasts:\n    This channel does not currently have any podcasts: Denne kanal har i øjeblikket ingen podcasts\n    Podcasts: Podcasts\n  This channel does not exist: Denne kanal findes ikke\n  Releases:\n    Releases: Udgivelser\n    This channel does not currently have any releases: Denne kanal har i øjeblikket ingen udgivelser\n  Home:\n    Home: Hjem\n    View Playlist: Se playliste\n  Courses:\n    Courses: Kurser\n    This channel does not currently have any courses: Denne kanal har i øjeblikket ingen kurser\n  Shorts:\n    This channel does not currently have any shorts: Denne kanal har i øjeblikket ingen shorts\n  Channel Tabs: Kanal-faner\nVideo:\n  Mark As Watched: 'Markér som set'\n  Remove From History: 'Fjern fra historik'\n  Video has been marked as watched: 'Videoen blev markeret som set'\n  Video has been removed from your history: 'Videoen blev fjernet fra din historik'\n  Open in YouTube: 'Åbn i YouTube'\n  Copy YouTube Link: 'Kopiér YouTube-link'\n  Open YouTube Embedded Player: 'Åbn indlejret YouTube-afspiller'\n  Copy YouTube Embedded Player Link: 'Kopiér link til indlejret YouTube-afspiller'\n  Open in Invidious: 'Åbn i Invidious'\n  Copy Invidious Link: 'Kopiér Indvidious-link'\n  Views: 'Visninger'\n  Loop Playlist: 'Gentag playliste'\n  Shuffle Playlist: 'Bland playliste'\n  Reverse Playlist: 'Omvendt playliste'\n  Previous: 'Forrige'\n  Next: 'Næste'\n  Watched: 'Set'\n  Autoplay: 'Auto-afspil'\n  Starting soon, please refresh the page to check again: 'Begynder snart; opdater venligst siden for at tjekke igen'\n  # As in a Live Video\n  Live: 'Live'\n  Live Now: 'Live nu'\n  Live Chat: 'Live chat'\n  Enable Live Chat: 'Aktivér live chat'\n  Live Chat is currently not supported in this build.: 'Live chat understøttes i øjeblikket ikke i dette build.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Live chat er aktiveret. Chatbeskeder vises her, når de er sendt.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Live chat understøttes i øjeblikket ikke med Invidious-API''en. Direkte forbindelse til YouTube kræves.'\n  Published on: 'Udgivet'\n#& Videos\n  Copy Invidious Channel Link: Kopiér link til Invidious-kanal\n  Open Channel in Invidious: Åbn kanal i Invidious\n  Copy YouTube Channel Link: Kopiér link til YouTube-kanal\n  Open Channel in YouTube: Åbn kanal i YouTube\n  Video has been removed from your saved list: Videoen blev fjernet fra din gemte liste\n  Video has been saved: Videoen blev gemt\n  Save Video: Gem video\n  Started streaming on: Begyndte at sende\n  Streamed on: Sendt\n  Sponsor Block category:\n    intro: Intro\n    sponsor: Sponsor\n    recap: Opsummering\n    music offtopic: Musik Off-topic\n    outro: Outro\n    self-promotion: Selvpromovering\n    interaction: Interaktion\n    filler: Fyldstof\n  External Player:\n    Unsupported Actions:\n      opening playlists: åbner playlister\n      reversing playlists: vender playlister om\n      starting video at offset: starter video ved begyndelsen\n      opening specific video in a playlist (falling back to opening the video): åbner specifik video i en playliste (falder tilbage til at åbne videoen)\n      setting a playback rate: indstiller en afspilningshastighed\n      shuffling playlists: blander playlister\n      looping playlists: gentager playlister\n    OpeningTemplate: Åbner {videoOrPlaylist} i {externalPlayer}...\n    OpenInTemplate: Åbn i {externalPlayer}\n    video: video\n    playlist: playliste\n    UnsupportedActionTemplate: '{externalPlayer} understøtter ikke: {action}'\n  Hide Channel: Skjul kanal\n  Unhide Channel: Vis kanal\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Live chat er ikke tilgængelig for denne stream. Den er muligvis blevet deaktiveret af uploaderen.\n  Premieres: Premierer\n  Upcoming: Kommende\n  Scroll to Bottom: Rul til bunden\n  Player:\n    Stats:\n      Video ID: 'Video-ID: {videoId}'\n      Media Formats: 'Medieformater: {formats}'\n      Resolution: 'Opløsning: {width}x{height}{''@''}{frameRate}'\n      Bandwidth: 'Båndbredde: {bandwidth} kbps'\n      Stats: Statistik\n      Bitrate: 'Bitrate: {bitrate} kbps'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      Volume: 'Lydstyrke: {volumePercentage}%'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n      Dropped Frames / Total Frames: 'Tabte billeder: {droppedFrames} / Samlede billeder: {totalFrames}'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Player Dimensions: 'Afspillerens dimensioner: {width}x{height}'\n      Buffered: 'Bufret: {bufferedPercentage}%'\n    Skipped segment: Sprang {segmentCategory} segment over\n    Playback will resume automatically when your connection comes back: Afspilning genoptager automatisk, når din forbindelse vender tilbage.\n#& Playlists\n    Exit Full Window: Afslut fuldt vindue\n    Take Screenshot: Tag et skærmbillede\n    You appear to be offline: Du ser ud til at være offline.\n    TranslatedCaptionTemplate: '{language} (oversat fra \"{originalLanguage}\")'\n    Audio Tracks: Lydspor\n    Autoplay is off: Autoplay er slået fra\n    Autoplay is on: Autoplay er slået til\n    Theatre Mode: Teatertilstand\n    Full Window: Fuldt vindue\n    Show Stats: Vis statistik\n    Hide Stats: Skjul statistik\n    Exit Theatre Mode: Afslut teatertilstand\n  Unlisted: Ikke noteret\n  MembersOnly: Videoer kun for medlemmer kan ikke ses med FreeTube, da de kræver Google-login og betalt medlemskab af uploaderens kanal.\n  IP block: YouTube har blokeret din IP-adresse fra at se videoer. Prøv at skifte til en anden VPN eller proxy.\n  AgeRestricted: Aldersbegrænsede videoer kan ikke ses med FreeTube, da de kræver Google-login og brug af en aldersverificeret YouTube-konto.\n  DRMProtected: DRM-beskyttede videoer kan ikke afspilles i FreeTube, da de kræver proprietære komponenter med lukket kilde. Hvis du vil se denne video, skal du se den på det officielle YouTube-websted i en DRM-aktiveret webbrowser.\n  More Options: Flere muligheder\n  Show Super Chat Comment: Vis Super Chat-kommentar\n  DeArrow:\n    Show Modified Details: Vis ændrede detaljer\n    Show Original Details: Vis originale detaljer\n  Published:\n    In less than a minute: Mindre end et minut siden\n  Save Watched Progress: Gem set fremskridt\n  Watched Progress Saved: Set fremskridt gemt\nPlaylist:\n  #& About\n  View Full Playlist: 'Vis hele playliste'\n  Last Updated On: 'Sidst opdateret'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playliste\n  Sort By:\n    DateAddedNewest: Seneste tilføjet først\n    VideoTitleDescending: Titel (Å-A)\n    VideoTitleAscending: Titel (A-Å)\n    DateAddedOldest: Tidligst tilføjet først\n    Custom: Brugerdefineret\n    VideoDurationAscending: Varighed (korteste først)\n    AuthorAscending: Forfatter (A-Å)\n    AuthorDescending: Forfatter (Å-A)\n    PublishedNewest: Seneste udgivet først\n    PublishedOldest: Tidligst udgivet først\n    VideoDurationDescending: Varighed (længste først)\nChange Format:\n  Change Media Formats: 'Skift medieformater'\n  Use Dash Formats: 'Brug DASH-formater'\n  Use Legacy Formats: 'Brug ældre formater'\n  Use Audio Formats: 'Brug lydformater'\n  Dash formats are not available for this video: 'DASH-formater er ikke tilgængelige for denne video'\n  Audio formats are not available for this video: 'Lydformater er ikke tilgængelige for denne video'\n  Legacy formats are not available for this video: Ældre formater er ikke tilgængelige for denne video\nShare:\n  Share Video: 'Del video'\n  Share Playlist: 'Del playliste'\n  Include Timestamp: 'Inkluder tidsstempel'\n  Copy Link: 'Kopiér link'\n  Open Link: 'Åbn link'\n  Copy Embed: 'Kopiér indlejring'\n  Open Embed: 'Åbn indlejring'\n  # On Click\n  Invidious URL copied to clipboard: 'Indvidious-URL kopieret til udklipsholder'\n  Invidious Embed URL copied to clipboard: 'Invidious indlejrings-URL kopieret til udklipsholder'\n  YouTube URL copied to clipboard: 'YouTube-URL kopieret til udklipsholder'\n  YouTube Embed URL copied to clipboard: 'YouTube indlejrings-URL kopieret til udklipsholder'\n  YouTube Channel URL copied to clipboard: YouTube kanal-URL kopieret til udklipsholder\n  Invidious Channel URL copied to clipboard: Invidious kanal-URL kopieret til udklipsholder\n  Share Channel: Del kanal\nMini Player: 'Miniafspiller'\nComments:\n  Comments: 'Kommentarer'\n  Click to View Comments: 'Klik for at vise kommentarer'\n  Getting comment replies, please wait: 'Henter kommentarsvar; vent venligst'\n  There are no more comments for this video: 'Der er ikke flere kommentarer til denne video'\n  Hide Comments: 'Skjul kommentarer'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Der er ingen kommentarer tilgængelige til denne video'\n  Load More Comments: 'Indlæs flere kommentarer'\n  Newest first: Nyeste først\n  Top comments: Topkommentarer\n  Pinned by: Fastgjort af\n  Show More Replies: Vis flere svar\n  Member: Medlem\n  Subscribed: Abonneret\n  View {replyCount} replies: Se {replyCount} svar\n  Hearted: Hjerte\n  There are no comments available for this post: Der er ingen tilgængelige kommentarer til dette opslag\nUp Next: 'Næste'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Lokal API-fejl (Klik for at kopiere)'\nInvidious API Error (Click to copy): 'Invidious-API-fejl (Klik for at kopiere)'\nFalling back to Invidious API: 'Falder tilbage til Invidious-API'\nFalling back to Local API: 'Falder tilbage til den lokale API'\nLoop is now disabled: 'Gentagelse er nu deaktiveret'\nLoop is now enabled: 'Gentagelse er nu aktiveret'\nShuffle is now disabled: 'Bland er nu deaktiveret'\nShuffle is now enabled: 'Bland er nu aktiveret'\nThe playlist has been reversed: 'Playlisten blev vendt om'\nPlaying Next Video: 'Afspiller næste video'\nPlaying Previous Video: 'Afspiller forrige video'\nCanceled next video autoplay: 'Autoplay af næste video afbrudt'\n'The playlist has ended. Enable loop to continue playing': 'Playlisten er slut.  Aktivér gentagelse for at fortsætte afspilning'\n\nYes: 'Ja'\nNo: 'Nej'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Denne video er utilgængelig på grund af manglende formater. Dette kan ske ved landbaseret utilgængelighed.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Når aktiveret, bruger FreeTube RSS i stedet for standardmetoden til at hente dit abonnementsfeed. RSS er hurtigere og forhindrer IP-blokering, men giver ikke visse oplysninger som videovarighed, live-status eller opslag\n    Fetch Automatically: Når aktiveret, henter FreeTube automatisk dit abonnementsfeed ved opstart og hver gang et nyt vindue åbnes.\n  Player Settings:\n    Default Video Format: Vælg de formater, der bruges, når en video afspilles. DASH-formater kan afspille højere kvaliteter. Ældre formater er begrænset til maks. 360p, men bruger mindre båndbredde. Lydformater er kun lydstrømme.\n    Proxy Videos Through Invidious: Forbinder til Invidious for at vise videoer i stedet for at oprette en direkte forbindelse til YouTube.\n    Scroll Playback Rate Over Video Player: Mens markøren er over videoen, hold Ctrl-tasten (Command-tasten på Mac) nede, og rul musehjulet frem eller tilbage for at styre afspilningshastigheden. Hold Ctrl-tasten (Command-tasten på Mac) nede, og venstreklik for hurtigt at vende tilbage til standardafspilningshastigheden (1x, medmindre den er blevet ændret i indstillingerne).\n    Skip by Scrolling Over Video Player: Brug rullehjulet til at springe gennem videoen i bedste MPV-stil.\n  General Settings:\n    Region for Trending: Trendregionen lader dig vælge, hvilket lands trending videoer du vil have vist.\n    Preferred API Backend: Vælg den backend, FreeTube skal bruge til at hente data. Den lokale API er en indbygget udtrækker. Invidious-API'en kræver forbindelse til en Invidious-server.\n    Invidious Instance: Den Invidious-instans, som FreeTube forbinder til for API-opkald.\n    Thumbnail Preference: Alle miniaturebilleder på FreeTube erstattes med et billede af videoen, sløret eller skjult, i stedet for standardminiaturebilledet.\n    Fallback to Non-Preferred Backend on Failure: Når din foretrukne API har et problem, vil FreeTube automatisk forsøge at bruge din ikke-foretrukne API som en fallback-metode, hvis den er aktiveret.\n    External Link Handling: \"Vælg standardadfærd, når du klikker på et link, som ikke kan åbnes i FreeTube.\\nSom standard vil FreeTube åbne det klikkede link i din standardbrowser.\\n\"\n    Open Deep Links In New Window: URL'er, der sendes til FreeTube, f.eks. ved at omdirigere browserudvidelser eller kommandolinjeargumenter, åbnes i et nyt vindue.\n  External Player Settings:\n    Custom External Player Executable: Som standard antager FreeTube, at den valgte eksterne afspiller kan findes via PATH-miljøvariablen. Om nødvendigt kan en brugerdefineret sti angives her.\n    DefaultCustomArgumentsTemplate: \"(Standard: '{defaultCustomArguments}')\"\n    Custom External Player Arguments: Eventuelle brugerdefinerede kommandolinjeargumenter, du vil sende videre til den eksterne afspiller.\n    External Player: 'Vælger du en ekstern afspiller, vises et ikon for at åbne videoen (playlisten, hvis understøttet) på miniaturebilledet. Advarsel: Invidious-indstillinger påvirker ikke eksterne afspillere.'\n    Ignore Warnings: Undertryk advarsler, når den aktuelle eksterne afspiller ikke understøtter handlingen (f.eks. omvendt playliste osv.).\n    Ignore Default Arguments: Send ikke nogen standardargumenter til den eksterne afspiller ud over video-URL'en (f.eks. afspilningshastighed, playliste-URL osv.). Brugerdefinerede argumenter sendes stadig videre.\n  Distraction Free Settings:\n    Hide Channels: Indtast en kanal-ID for at skjule alle videoer, playlister og selve kanalen fra søgeresultater, trending, mest populære og anbefalinger. Den indtastede kanal-ID skal matche fuldstændigt og er versalfølsom.\n    Hide Subscriptions Live: Denne indstilling tilsidesættes af den app-dækkende \"{appWideSetting}\"-indstilling i sektionen \"{subsection}\" i \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Indtast et ord, ordfragment eller en sætning (ikke versalfølsom) for at skjule alle videoer og playlister, hvis originale titler indeholder det, overalt i FreeTube – undtagen historik, dine playlister og videoer inde i playlister.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Udskift videotitler med brugerindsendte titler fra DeArrow.\n    UseDeArrowThumbnails: Erstat videominiaturebilleder med miniaturebilleder fra DeArrow.\n  Experimental Settings:\n    Replace HTTP Cache: Deaktiverer Electrons diskbaserede HTTP-cache og aktiverer en brugerdefineret billedcache i hukommelsen. Vil føre til øget brug af RAM.\nNew Window: Nyt vindue\nMore: Mere\nOpen New Window: Åbn nyt vindue\nChannels:\n  Channels: Kanaler\n  Title: Kanalliste\n  Count: '{number} kanal(er) fundet.'\n  Unsubscribe Prompt: Er du sikker på, at du vil afmelde \"{channelName}\"?\n  Search bar placeholder: Søg efter kanaler\n  Empty: Din kanalliste er tom.\nDefault Invidious instance has been set to {instance}: Standard Invidious-instans blev indstillet til {instance}\nDefault Invidious instance has been cleared: Standard Invidious-instans blev ryddet\nAre you sure you want to open this link?: Er du sikker på, at du vil åbne dette link?\nSearch Bar:\n  Clear Input: Ryd input\n  Remove: Fjern\nUnknown YouTube url type, cannot be opened in app: Ukendt YouTube-URL-type; kan ikke åbnes i appen\nScreenshot Error: Skærmbillede mislykkedes. {error}\nExternal link opening has been disabled in the general settings: Åbning af eksterne links er slået fra i generelle indstillinger\nScreenshot Success: Gemt skærmbillede\nPlaying Next Video Interval: Afspiller næste video om lidt. Klik for at afbryde. | Afspiller næste video om {nextVideoInterval} sekund. Klik for at afbryde. | Afspiller næste video om {nextVideoInterval} sekunder. Klik for at afbryde.\nPreferences: Præferencer\nGo to page: Gå til {page}\nClose Banner: Luk banner\nClipboard:\n  Cannot access clipboard without a secure connection: Kan ikke tilgå udklipsholder uden en sikker forbindelse\n  Copy failed: Kopiering til udklipsholder mislykkedes\nChapters:\n  Chapters: Kapitler\n  Key Moments: Højdepunkter\nAge Restricted:\n  This video is age restricted: Denne video er aldersbegrænset\n  This channel is age restricted: Denne kanal er aldersbegrænset\nSearch Listing:\n  Label:\n    Subtitles: Undertekster\n    4K: 4K\n    3D: 3D\n    Closed Captions: Undertekster\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nye\nFeed:\n  Refresh Feed: Opdater {subscriptionName}\n  Feed Last Updated: '{feedName}-feed opdateret sidst: {date}'\nRight-click or hold to see history: Højreklik eller hold nede for at se historik\nSearch character limit: Søgningen overskrider tegngrænsen {searchCharacterLimit}\nKeys:\n  shift: Shift\n  arrowdown: Pil ned\n  arrowright: Højre pil\n  ctrl: Ctrl\n  alt: Alt\n  arrowleft: Venstre pil\n  arrowup: Pil op\n  plus: Plus\n  enter: Enter\nDescription:\n  Collapse Description: Vis mindre\n  Expand Description: '...mere'\nHashtag:\n  This hashtag does not currently have any videos: Dette hashtag har i øjeblikket ingen videoer\n  Hashtag: Hashtag\nChannel Unhidden: '{channel} fjernet fra kanalfilter'\nKeyboardShortcutPrompt:\n  Fullscreen: Skift til fuld skærm\n  Stats: Vis videostatistik\n  Picture in Picture: Skift til billede-i-billede-tilstand\n  Large Fast Forward: Spol 10 sekunder frem / Spol hurtigt frem i video baseret på den aktuelle videoafspilningshastighed\n  Mute: Slå lyden til/fra\n  Keyboard Shortcuts: Tastaturgenveje\n  Sections:\n    Video:\n      Playback: 'Video: Afspilning'\n      General: 'Video: Generelt'\n    App:\n      Situational: 'App: Situationsbestemt'\n      General: 'App: Generelt'\n  Show Keyboard Shortcuts: Vis tastaturgenveje\n  History Backward: Gå en side tilbage\n  History Forward: Gå en side frem\n  New Window: Opret et nyt vindue\n  Navigate to Settings: Gå til siden Indstillinger\n  Navigate to History: Gå til siden Historik\n  Refresh: Opdater feed med seneste indhold\n  Focus Secondary Search: Fokuser på det sekundære søgefelt (hvis der er et)\n  Captions: Slå undertekster til/fra\n  Large Rewind: Spol 10 sekunder tilbage / Spol videoen tilbage baseret på den aktuelle videoafspilningshastighed\n  Play: Skift mellem afspilning og pause\n  Decrease Video Speed: Sænk videohastigheden baseret på interval for videoafspilningshastighed\n  Minimize Window: Minimer vindue\n  Skip by Tenths: Spring gennem video efter procent (3 spring til 30 % af varigheden)\n  Increase Video Speed: Forøg videohastigheden baseret på interval for videoafspilningshastighed\n  Reset Zoom: Nulstil zoomniveau / UI-skala\n  Zoom In: Zoom ind\n  Next Frame: Næste billede (mens på pause)\n  Volume Up: Forøg lydstyrke\n  Volume Down: Sænk lydstyrke\n  Last Chapter: Sidste kapitel\n  Next Chapter: Næste kapitel\n  Zoom Out: Zoom ud\n  Small Fast Forward: Spol frem X sekunder baseret på spol frem-interval og aktuelle videoafspilningshastighed\n  Small Rewind: Spol X sekunder tilbage baseret på tilbagespolingsintervallet og den aktuelle videoafspilningshastighed\n  Search in New Window: Søg i et nyt vindue\n  Last Frame: Forrige billede (mens på pause)\n  Full Window: Skift fuldt vindue\n  Theatre Mode: Skift biograftilstand\n  Take Screenshot: Tag et skærmbillede\n  Close Window: Luk vindue\n  Toggle Developer Tools: Vis/skjul udviklerværktøjer\n  Focus Search: Fokuser på søgelinjen\n  Home: Spring til starten af videoen\n  End: Spring til slutningen af videoen\nChannel Hidden: '{channel} føjet til kanalfilter'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nMoments Ago: for et øjeblik siden\nYes, Delete: Ja, slet\nDisplay Label: '{label}: {value}'\nYes, Restart: Ja, genstart\nOk: OK\nshortcutJoinOperator: +\nTrimmed input must be at least N characters long: Trimmet input skal være mindst 1 tegn langt | Trimmet input skal være mindst {length} tegn langt\nYes, Open Link: Ja, åbn link\nTag already exists: '\"{tagName}\"-tagget findes allerede'\nCancel: Annuller\nAutoplay Interruption Timer: Autoplay afbrudt på grund af {autoplayInterruptionIntervalHours} timers inaktivitet\nshortcutLabelSeparator: ｜\ncheckmark: ✓\n"
  },
  {
    "path": "static/locales/de-DE.yaml",
    "content": "# Webkit Menu Bar\nFile: Datei\nQuit: Beenden\nEdit: Bearbeiten\nUndo: Rückgängig\nRedo: Wiederherstellen\nCut: Ausschneiden\nCopy: Kopieren\nPaste: Einfügen\nDelete: Löschen\nSelect all: Alles auswählen\nToggle Developer Tools: Entwicklerwerkzeuge umschalten\nActual size: Tatsächliche Größe\nZoom in: Vergrößern\nZoom out: Verkleinern\nToggle fullscreen: Vollbild umschalten\nWindow: Fenster\nMinimize: Minimieren\nClose: Schließen\nBack: Zurück\nForward: Vorwärts\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: Videos\n  Shorts: Shorts\n  Live: Live\n  Posts: Beiträge\n  Sort By: Sortieren nach\n\n# Search Bar\n  Counts:\n    Video Count: 1 Video | {count} Videos\n    Channel Count: 1 Kanal | {count} Kanäle\n    Subscriber Count: 1 Abonnent | {count} Abonnenten\n    View Count: 1 Aufruf | {count} Aufrufe\n    Watching Count: 1 Zuschauer | {count} Zuschauende\n    Comment Count: 1 Kommentar | {count} Kommentare\n    Like Count: 1 Gefällt mir | {count} Gefällt mir\nSearch / Go to URL: Suchen / URL öffnen\n  # In Filter Button\nSearch Filters:\n  Search Filters: Suchfilter\n  Sort By:\n    Most Relevant: Relevanz\n    Rating: Bewertung\n    Upload Date: Upload-Datum\n    View Count: Anzahl der Aufrufe\n  Time:\n    Time: Zeit\n    Any Time: Beliebige Zeit\n    Last Hour: Letzte Stunde\n    Today: Heute\n    This Week: Diese Woche\n    This Month: Dieser Monat\n    This Year: Dieses Jahr\n  Type:\n    Type: Typ\n    All Types: Alle Typen\n    Videos: Videos\n    Channels: Kanäle\n    #& Playlists\n    Movies: Filme\n  Duration:\n    Duration: Dauer\n    All Durations: Jede Dauer\n    Short (< 4 minutes): Kurz (< 4 Minuten)\n    Long (> 20 minutes): Lang (> 20 Minuten)\n  # On Search Page\n    Medium (4 - 20 minutes): Mittel (4–20 Minuten)\n  Search Results: Suchergebnisse\n  Fetching results. Please wait: Ergebnisse werden abgerufen. Bitte warten\n  Fetch more results: Weitere Ergebnisse abrufen\n# Sidebar\n  There are no more results for this search: Für diese Suche gibt es keine weiteren Ergebnisse\n  Features:\n    3D: 3D\n    Live: Live\n    4K: 4K\n    360 Video: 360°-Video\n    HDR: HDR\n    VR180: VR180\n    Features: Eigenschaften\n    HD: HD\n    Subtitles: Untertitel\n    Creative Commons: Creative-Commons\n    Location: Region\n  Clear Filters: Suchfilter zurücksetzen\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: Abos\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': Deine Aboliste ist derzeit leer. Wenn du deine Abos importieren möchtest, wähle in den Einstellungen unter dem Bereich „Daten“ „Abos importieren“. Alternativ kannst du nach einem Kanal suchen und diesen abonnieren.\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Dieses Profil hat eine große Anzahl von Abos.  RSS zur Vermeidung von Geschwindigkeitsbeschränkungen erzwingen\n  Load More Videos: Weitere Videos laden\n  Error Channels: Kanäle mit Fehlern\n  Disabled Automatic Fetching: Du hast den automatischen Abruf von Abos deaktiviert. Aktualisiere die Abos, um sie hier zu sehen.\n  Empty Channels: Deine abonnierten Kanäle haben derzeit keine Videos.\n  Subscriptions Tabs: Registerkarten für Abos\n  All Subscription Tabs Hidden: Alle Registerkarten für Abos sind ausgeblendet. Um den Inhalt hier zu sehen, blende bitte einige Registerkarten im Abschnitt „{subsection}“ in „{settingsSection}“ ein.\n  Load More Posts: Weitere Beiträge laden\n  Empty Posts: Deine abonnierten Kanäle haben derzeit keine Beiträge.\nTrending:\n  Trending: Trends\n  Trending Tabs: Trends-Tabs\n  Gaming: Gaming\n  Sports: Sport\nMost Popular: Am beliebtesten\nPlaylists: Playlists\nUser Playlists:\n  Your Playlists: Deine Playlists\n  Search bar placeholder: Nach Playlists suchen\n  Empty Search Message: Es gibt keine Videos in dieser Playlist, die deiner Suche entsprechen\n  This playlist currently has no videos.: Diese Playlist enthält derzeit keine Videos.\n  Add to Playlist: Zur Playlist hinzufügen\n  Move Video Up: Video nach oben verschieben\n  Move Video Down: Video nach unten verschieben\n  Playlist Name: Name der Playlist\n  You have no playlists. Click on the create new playlist button to create a new one.: Du hast keine Playlists. Klicke auf die Schaltfläche „Neue Playlist erstellen“, um eine neue zu erstellen.\n  Playlist Description: Beschreibung der Playlist\n  Save Changes: Änderungen speichern\n  Cancel: Abbrechen\n  Edit Playlist Info: Playlist-Infos bearbeiten\n  Copy Playlist: Playlist kopieren\n  Remove Watched Videos: Angesehene Videos entfernen\n  Delete Playlist: Playlist löschen\n  Are you sure you want to delete this playlist? This cannot be undone: Bist du sicher, dass du diese Playlist löschen möchtest? Dies kann nicht rückgängig gemacht werden.\n  Sort By:\n    NameAscending: A–Z\n    NameDescending: Z–A\n    LatestCreatedFirst: Erstellungsdatum (neueste)\n    EarliestCreatedFirst: Erstellungsdatum (älteste)\n    LatestUpdatedFirst: Aktualisierungsdatum (neueste)\n    EarliestUpdatedFirst: Aktualisierungsdatum (älteste)\n    LatestPlayedFirst: Abspieldatum (neueste)\n    EarliestPlayedFirst: Abspieldatum (älteste)\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: Dieses Video kann nicht nach oben verschoben werden.\n      This video cannot be moved down.: Dieses Video kann nicht nach unten verschoben werden.\n      Video has been removed: Video wurde entfernt\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Einige Videos in der Playlist sind noch nicht geladen. Klicke hier, um sie trotzdem zu kopieren.\n      Playlist name cannot be empty. Please input a name.: Der Name der Playlist darf nicht leer sein. Bitte gib einen Namen ein.\n      Playlist has been updated.: Playlist wurde aktualisiert.\n      There was an issue with updating this playlist.: Es gab ein Problem beim Aktualisieren dieser Playlist.\n      \"{videoCount} video(s) have been removed\": 1 Video wurde entfernt | {videoCount} Videos wurden entfernt\n      There were no videos to remove.: Es gab keine Videos zum Entfernen.\n      This playlist is protected and cannot be removed.: Diese Playlist ist geschützt und kann nicht entfernt werden.\n      There was a problem with removing this video: Es gab ein Problem beim Entfernen dieses Videos\n      Playlist {playlistName} has been deleted.: Playlist {playlistName} wurde gelöscht.\n      This playlist does not exist: Diese Playlist existiert nicht\n      This playlist is now used for quick bookmark: Diese Playlist wird jetzt für „Schnelle Lesezeichen“ genutzt\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Diese Playlist wird jetzt anstatt {oldPlaylistName} für „Schnelle Lesezeichen“ genutzt. Hier klicken, um dies rückgängig zu machen\n      Reverted to use {oldPlaylistName} for quick bookmark: '{oldPlaylistName} wird wieder für „Schnelle Lesezeichen“ genutzt'\n      This playlist is already being used for quick bookmark.: Diese Playlist wird bereits für „Schnelle Lesezeichen“ verwendet.\n      This playlist has a video with a duration error: Diese Playlist enthält mindestens ein Video ohne Dauer. Daher wird die Playlist so sortiert, als ob die Dauer null wäre.\n      Video has been removed. Click here to undo.: Video wurde entfernt. Klicke hier, um das Entfernen rückgängig zu machen.\n    Search for Videos: Nach Videos suchen\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} ausgewählt'\n    Search in Playlists: In Playlists suchen\n    Save: Speichern\n    Toast:\n      You haven't selected any playlist yet.: Du hast noch keine Playlist ausgewählt.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(s) wurden zu 1 Playlist hinzugefügt | Video(s) wurden zu {playlistCount} Playlists hinzugefügt\"\n    Select a playlist to add your N videos to: Wähle eine Playlist, der du dein Video hinzufügen möchtest | Wähle eine Playlist, der du deine {videoCount} Videos hinzufügen möchtest\n    Added {count} Times: 'Bereits hinzugefügt | {count} Mal hinzugefügt'\n    Allow Adding Duplicate Video(s): Hinzufügen doppelter Videos zulassen\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videos werden hinzugefügt'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} bereits hinzugefügte Videos'\n  CreatePlaylistPrompt:\n    New Playlist Name: Neuer Name der Playlist\n    Create: Erstellen\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Es existiert bereits eine Playlist mit diesem Namen. Bitte wähle einen anderen Namen.\n      There was an issue with creating the playlist.: Es gab ein Problem beim Erstellen der Playlist.\n      Playlist {playlistName} has been successfully created.: Playlist {playlistName} wurde erfolgreich erstellt.\n  Create New Playlist: Neue Playlist erstellen\n  Remove from Playlist: Aus der Playlist entfernen\n  Add to Favorites: Hinzufügen zu {playlistName}\n  Remove from Favorites: Löschen aus {playlistName}\n  Enable Quick Bookmark With This Playlist: Schnelle Lesezeichen für diese Playlist aktivieren\n  Playlists with Matching Videos: Playlists mit passenden Videos\n  Quick Bookmark Enabled: Schnelle Lesezeichen aktiviert\n  Cannot delete the quick bookmark target playlist.: Die Playlist, die für die Funktion „Schnelle Lesezeichen“ genutzt wird, kann nicht gelöscht werden.\n  Remove Duplicate Videos: Doppelte Videos entfernen\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Bist du sicher, dass du ein doppeltes Video aus dieser Playlist entfernen möchtest? Dies kann nicht rückgängig gemacht werden. | Bist du sicher, dass du {playlistItemCount} doppelte Videos aus dieser Playlist entfernen möchtest? Dies kann nicht rückgängig gemacht werden.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Bist du sicher, dass du ein angesehenes Video aus dieser Playlist entfernen möchtest? Dies kann nicht rückgängig gemacht werden. | Bist du sicher, dass du {playlistItemCount} angesehene Videos aus dieser Playlist entfernen möchtest? Dies kann nicht rückgängig gemacht werden.\n  Export Playlist: Diese Playlist exportieren\n  The playlist has been successfully exported: Die Playlist wurde erfolgreich exportiert\n  TotalTimePlaylist: 'Gesamtzeit: {duration}'\n  Export list of URLs: Liste der URLs exportieren\nHistory:\n  # On History Page\n  History: Verlauf\n  Watch History: Wiedergabeverlauf\n  Your history list is currently empty.: Dein Verlauf ist aktuell leer.\n  Search bar placeholder: Im Verlauf suchen\n  Empty Search Message: Es gibt keine Videos in deinem Verlauf, die deiner Suche entsprechen\n  Case Sensitive Search: Groß- und Kleinschreibung bei der Suche beachten\n  DateOldestHistory: Wiedergabedatum (älteste)\n  DateNewestHistory: Wiedergabedatum (neueste)\nSettings:\n  # On Settings Page\n  Settings: Einstellungen\n  General Settings:\n    General Settings: Allgemein\n    Fallback to Non-Preferred Backend on Failure: Bei Ausfall auf nicht bevorzugtes Backend zurückgreifen\n    Enable Search Suggestions: Suchvorschläge aktivieren\n    Default Landing Page: Standard-Startseite\n\n    Locale Preference: Sprache\n    Preferred API Backend:\n      Preferred API Backend: Bevorzugtes API-Backend\n      Local API: Lokale API\n      Invidious API: Invidious-API\n    Video View Type:\n      Video View Type: Videoübersicht\n      Grid: Raster\n      List: Liste\n    Thumbnail Preference:\n      Thumbnail Preference: Vorschaubilder\n      Default: Standard\n      Beginning: Anfang\n      Middle: Mitte\n      End: Ende\n      Hidden: Versteckt\n      Blur: Unschärfe\n    Region for Trending: Region für Trends\n        #! List countries\n    Check for Latest Blog Posts: Nach neuen Blogeinträgen suchen\n    Check for Updates: Auf Updates prüfen\n    View all Invidious instance information: Alle Informationen zur Invidious-Instanz anzeigen\n    System Default: Systemvorgabe\n    Current instance will be randomized on startup: Beim Start wird eine zufällige Instanz festgelegt\n    No default instance has been set: Es wurde keine Standardinstanz festgelegt\n    The currently set default instance is {instance}: Die aktuelle Standardinstanz ist {instance}\n    Current Invidious Instance: Aktuelle Invidious-Instanz\n    Clear Default Instance: Standardinstanz zurücksetzen\n    Set Current Instance as Default: Derzeitige Instanz als Standard festlegen\n    External Link Handling:\n      No Action: Keine Aktion\n      Ask Before Opening Link: Vor dem Öffnen des Links nachfragen\n      Open Link: Link öffnen\n      External Link Handling: Handhabung externer Links\n    Auto Load Next Page:\n      Label: Nächste Seite automatisch laden\n      Tooltip: Zusätzliche Seiten und Kommentare automatisch laden.\n    Open Deep Links In New Window: An FreeTube übergebene URLs in einem neuen Fenster öffnen\n    Minimize to system tray: In die Systemleiste minimieren\n  Theme Settings:\n    Theme Settings: Farbschema\n    Match Top Bar with Main Color: Obere Leiste an Hauptfarbe anpassen\n    Base Theme:\n      Base Theme: Grundlegendes Farbschema\n      Black: Schwarz\n      Dark: Dunkel\n      Light: Hell\n      Dracula: Dracula\n      System Default: Systemvorgabe\n      Catppuccin Mocha: Catppuccin-Mocha\n      Hot Pink: Pink\n      Pastel Pink: Pastellrosa\n      Nordic: Nordic\n      Solarized Dark: Solarisiert-Dunkel\n      Solarized Light: Solarisiert-Hell\n      Gruvbox Light: Gruvbox-Hell\n      Gruvbox Dark: Gruvbox-Dunkel\n      Catppuccin Frappe: Catppuccin-Frappe\n      Everforest Dark Hard: Everforest-Dunkel (harter Kontrast)\n      Everforest Dark Medium: Everforest-Dunkel (normaler Kontrast)\n      Everforest Dark Low: Everforest-Dunkel (geringer Kontrast)\n      Everforest Light Hard: Everforest-Hell (harter Kontrast)\n      Everforest Light Medium: Everforest-Hell (normaler Kontrast)\n      Everforest Light Low: Everforest-Hell (geringer Kontrast)\n      Catppuccin Latte: Catppuccin-Latte\n    Main Color Theme:\n      Main Color Theme: Hauptfarbe\n      Red: Rot\n      Pink: Rosa\n      Purple: Lila\n      Deep Purple: Dunkellila\n      Indigo: Indigo\n      Blue: Blau\n      Light Blue: Hellblau\n      Cyan: Türkis\n      Teal: Türkisblau\n      Green: Grün\n      Light Green: Hellgrün\n      Lime: Limette\n      Yellow: Gelb\n      Amber: Bernsteingelb\n      Orange: Orange\n      Deep Orange: Dunkelorange\n      Dracula Cyan: Dracula Türkis\n      Dracula Green: Dracula Grün\n      Dracula Orange: Dracula-Orange\n      Dracula Pink: Dracula-Rosa\n      Dracula Purple: Dracula-Lila\n      Dracula Red: Dracula-Rot\n      Dracula Yellow: Dracula-Gelb\n      Catppuccin Mocha Green: Catppuccin-Mocha-Grün\n      Catppuccin Mocha Blue: Catppuccin-Mocha-Blau\n      Catppuccin Mocha Peach: Catppuccin-Mocha-Pfirsich\n      Catppuccin Mocha Yellow: Catppuccin-Mocha-Gelb\n      Catppuccin Mocha Sky: Catppuccin-Mocha-Himmel\n      Catppuccin Mocha Sapphire: Catppuccin-Mocha-Saphir\n      Catppuccin Mocha Lavender: Catppuccin-Mocha-Lavendel\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosenwasser\n      Catppuccin Mocha Flamingo: Catppuccin-Mocha-Flamingo\n      Catppuccin Mocha Pink: Catppuccin-Mocha-Pink\n      Catppuccin Mocha Mauve: Catppuccin-Mocha-Malve\n      Catppuccin Mocha Red: Catppuccin-Mocha-Rot\n      Catppuccin Mocha Maroon: Catppuccin-Mocha-Kastanie\n      Catppuccin Mocha Teal: Catppuccin-Mokka-Blaugrün\n      Solarized Red: Solarisiertes Rot\n      Solarized Yellow: Solarisiertes Gelb\n      Solarized Orange: Solarisiertes Orange\n      Solarized Magenta: Solarisiertes Magenta\n      Solarized Blue: Solarisiertes Blau\n      Solarized Cyan: Solarisiertes Cyan\n      Solarized Violet: Solarisiertes Violett\n      Solarized Green: Solarisiertes Grün\n      Gruvbox Dark Green: Gruvbox-Dunkelgrün\n      Gruvbox Dark Yellow: Gruvbox-Dunkelgelb\n      Gruvbox Dark Purple: Gruvbox-Dunkellila\n      Gruvbox Light Red: Gruvbox-Hellrot\n      Gruvbox Light Blue: Gruvbox-Hellblau\n      Gruvbox Light Purple: Gruvbox-Helllila\n      Gruvbox Dark Orange: Gruvbox-Dunkelorange\n      Gruvbox Dark Aqua: Gruvbox „Dunkles Wasser“\n      Gruvbox Light Orange: Gruvbox-Hellorange\n      Gruvbox Dark Blue: Gruvbox-Dunkelblau\n      Catppuccin Frappe Yellow: Catppuccin-Frappe-Gelb\n      Catppuccin Frappe Sky: Catppuccin-Frappe-Himmel\n      Catppuccin Frappe Mauve: Catppuccin-Frappe-Malve\n      Catppuccin Frappe Blue: Catppuccin-Frappe-Blau\n      Catppuccin Frappe Flamingo: Catppuccin-Frappe-Flamingo\n      Catppuccin Frappe Red: Catppuccin-Frappe-Rot\n      Catppuccin Frappe Teal: Catppuccin-Frappe-Blaugrün\n      Catppuccin Frappe Peach: Catppuccin Frappe Pfirsich\n      Catppuccin Frappe Rosewater: Catppuccin-Frappe-Rosenwasser\n      Catppuccin Frappe Green: Catppuccin-Frappe-Grün\n      Catppuccin Frappe Sapphire: Catppuccin-Frappe-Saphir\n      Catppuccin Frappe Pink: Catppuccin-Frappe-Pink\n      Catppuccin Frappe Lavender: Catppuccin-Frappe-Lavendel\n      Catppuccin Frappe Maroon: Catppuccin-Frappe-Kastanie\n      Everforest Dark Red: Everforest-Dunkelrot\n      Everforest Dark Orange: Everforest-Dunkelorange\n      Everforest Dark Yellow: Everforest-Dunkelgelb\n      Everforest Dark Green: Everforest-Dunkelgrün\n      Everforest Dark Aqua: Everforest-Dunkeltürkis\n      Everforest Dark Blue: Everforest-Dunkelblau\n      Everforest Dark Purple: Everforest-Dunkellila\n      Everforest Light Red: Everforest-Hellrot\n      Everforest Light Orange: Everforest-Hellorange\n      Everforest Light Yellow: Everforest-Hellgelb\n      Everforest Light Green: Everforest-Hellgrün\n      Everforest Light Aqua: Everforest-Helltürkis\n      Everforest Light Blue: Everforest-Hellblau\n      Everforest Light Purple: Everforest-Helllilla\n      Catppuccin Latte Mauve: Catppuccin-Latte-Malve\n      Catppuccin Latte Red: Catppuccin-Latte-Rot\n    Secondary Color Theme: Sekundäre Farbe\n        #* Main Color Theme\n    UI Scale: Skalierung der Benutzeroberfläche\n    Disable Smooth Scrolling: Gleichmäßiges Scrollen deaktivieren\n    Expand Side Bar by Default: Seitenleiste standardmäßig erweitern\n    Hide Side Bar Labels: Seitenleisten-Beschriftungen ausblenden\n    Hide FreeTube Header Logo: FreeTube-Titellogo ausblenden\n  Player Settings:\n    Player Settings: Video-Player\n    Play Next Video: Empfohlene Videos automatisch abspielen\n    Turn on Subtitles by Default: Untertitel standardmäßig einschalten\n    Autoplay Videos: Videos automatisch starten\n    Proxy Videos Through Invidious: Videos durch Invidious leiten\n    Autoplay Playlists: Videos in Playlist automatisch abspielen\n    Enable Theatre Mode by Default: Kinomodus standardmäßig aktivieren\n    Default Volume: Standard-Lautstärke\n    Default Playback Rate: Standard-Wiedergabegeschwindigkeit\n    Default Video Format:\n      Default Video Format: Standard-Videoformat\n      Dash Formats: DASH-Formate\n      Legacy Formats: Veraltete Formate\n      Audio Formats: Audioformate\n    Default Quality:\n      Default Quality: Standardqualität\n      Auto: Automatisch\n      144p: 144p\n      240p: 240p\n      360p: 360p\n      480p: 480p\n      720p: 720p\n      1080p: 1080p\n      1440p: 1440p\n      4k: 4k\n      8k: 8k\n    Next Video Interval: Countdown für Automatische Wiedergabe\n    Display Play Button In Video Player: Wiedergabetaste im Video-Player anzeigen\n    Scroll Volume Over Video Player: Lautstärke durch Scrollen ändern\n    Fast-Forward / Rewind Interval: Intervall für Vor-/Zurückspulen\n    Scroll Playback Rate Over Video Player: Abspielgeschwindigkeit durch Scrollen ändern\n    Video Playback Rate Interval: Intervall für Geschwindigkeitseinstellung\n    Max Video Playback Rate: Maximale Wiedergabegeschwindigkeit\n    Screenshot:\n      Enable: Screenshots aktivieren\n      Format Label: Format von Screenshots\n      Quality Label: Qualität von Screenshots\n      Ask Path: Nach dem Ordner zum Speichern fragen\n      Folder Label: Ordner für Screenshots\n      Folder Button: Ordner auswählen\n      File Name Label: Dateinamen-Muster\n      Error:\n        Forbidden Characters: Unerlaubte Zeichen\n        Empty File Name: Leerer Dateiname\n      File Name Tooltip: Du kannst die folgenden Variablen verwenden. %Y Jahr 4-stellig. %M Monat 2 Ziffern. %D Tag 2 Ziffern. %H Stunde 2 Ziffern. %N Minute 2 Ziffern. %S Sekunde 2 Ziffern. %T Millisekunde 3 Ziffern. %s Video-Sekunde. %t Video Millisekunde 3 Ziffern. %i Video-ID.\n    Enter Fullscreen on Display Rotate: Beim Drehen des Bildschirms zu Vollbild wechseln\n    Skip by Scrolling Over Video Player: Überspringen durch Scrollen\n    Autoplay Interruption Timer: Abbruch-Timer für Automatische Wiedergabe\n    Default Viewing Mode:\n      Theater: Kinomodus\n      Picture in Picture: Bild im Bild\n      External Player: Externer Player ({externalPlayerName})\n      Full Screen: Vollbild\n      Default Viewing Mode: Standard-Ansichtsmodus\n  Subscription Settings:\n    Subscription Settings: Abo\n    Fetch Feeds from RSS: Abos via RSS abrufen\n    Fetch Automatically: Abos automatisch abrufen\n    Confirm Before Unsubscribing: Unbeabsichtigtes Deabonnieren verhindern\n\n    'Limit the number of videos displayed for each channel': Anzahl der für jeden Kanal angezeigten Videos begrenzen\n    To: Limitieren auf\n  Privacy Settings:\n    Watch history has been cleared: Wiedergabeverlauf wurde gelöscht\n    Are you sure you want to remove your entire watch history?: Bist du sicher, dass du deinen gesamten Wiedergabeverlauf löschen willst?\n    Remove Watch History: Wiedergabeverlauf löschen\n    Search cache has been cleared: Suchcache wurde gelöscht\n    Are you sure you want to clear out your search cache?: Bist du sicher, dass du deinen Suchcache löschen möchtest?\n    Clear Search Cache: Suchcache löschen\n    Save Watched Progress: Videofortschritt merken\n    Remember History: Wiedergabeverlauf merken\n    Privacy Settings: Datenschutz\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Bist du sicher, dass du alle Abos und Profile löschen möchtest?  Diese Aktion kann nicht rückgängig gemacht werden.\n    Remove All Subscriptions / Profiles: Alle Abos / Profile löschen\n    Save Watched Videos With Last Viewed Playlist: Angesehene Videos in der Playlist „Zuletzt angesehen“ speichern\n    Remove All Playlists: Alle Playlists entfernen\n    All playlists have been removed: Alle Playlists wurden entfernt\n    Are you sure you want to remove all your playlists?: Bist du sicher, dass du alle deine Playlists entfernen möchtest?\n    Remember Search History: Suchverlauf merken\n    Are you sure you want to clear out your search history and cache?: Bist du sicher, dass du deinen Suchverlauf und Cache löschen möchtest?\n    Clear Search History and Cache: Suchverlauf und Cache löschen\n    Search history and cache have been cleared: Suchverlauf und Cache wurden gelöscht\n    Watched Progress Saving Mode:\n      Tooltip: Automatisch = Beim Verlassen des Videos, nachdem das Video beendet wurde und wenn ein Fehler auftritt (z. B. bei einer Ratenbegrenzung oder wenn die Sitzung abgelaufen ist) speichern. Halbautomatisch = Wie automatisch, jedoch nur beim Verlassen des Videos, außerdem kann der Fortschritt manuell über einen Button namens „Videofortschritt speichern“, der sich unter dem Videoplayer befindet, gespeichert werden.\n      Modes:\n        Semi-auto: Halbautomatisch\n        Auto: Automatisch\n        Never: Nie\n  Data Settings:\n    How do I import my subscriptions?: Wie importiere ich meine Abos?\n    Unknown data key: Unbekannter Datenschlüssel\n    Unable to write file: Datei kann nicht geschrieben werden\n    Unable to read file: Datei kann nicht gelesen werden\n    All watched history has been successfully exported: Der gesamte Wiedergabeverlauf wurde erfolgreich exportiert\n    All watched history has been successfully imported: Der gesamte Wiedergabeverlauf wurde erfolgreich importiert\n    History object has insufficient data, skipping item: Verlaufsobjekt hat unzureichende Daten, Element wird übersprungen\n    Subscriptions have been successfully exported: Abos wurden erfolgreich exportiert\n    Invalid history file: Ungültige Verlaufsdatei\n    Invalid subscriptions file: Ungültige Abo-Datei\n    All subscriptions and profiles have been successfully imported: Alle Abos und Profile wurden erfolgreich importiert\n    All subscriptions have been successfully imported: Alle Abos wurden erfolgreich importiert\n    Profile object has insufficient data, skipping item: Profilobjekt hat unzureichende Daten, Element wird übersprungen\n    Export History: Verlauf exportieren\n    Import History: Verlauf importieren\n    Export NewPipe: NewPipe exportieren\n    Export YouTube: YouTube exportieren\n    Export FreeTube: FreeTube exportieren\n    Export Subscriptions: Abos exportieren\n    Import Subscriptions: Abos importieren\n    Select Export Type: Exporttyp auswählen\n    Data Settings: Daten\n    Manage Subscriptions: Abos verwalten\n    Export Playlists: Playlists exportieren\n    Import Playlists: Playlists importieren\n    Playlist insufficient data: Unzureichende Daten für die Playlist „{playlist}“, Element wird übersprungen\n    All playlists has been successfully imported: Alle Playlists wurden erfolgreich importiert\n    All playlists has been successfully exported: Alle Playlists wurden erfolgreich exportiert\n    Playlist File: Playlist-Datei\n    Subscription File: Abo-Datei\n    History File: Verlaufsdatei\n    Export Playlists For Older FreeTube Versions:\n      Label: Playlists für ältere FreeTube-Versionen exportieren\n      Tooltip: \"Diese Option exportiert Videos aus allen Playlists in eine Playlist namens „Favoriten“.\\nSo kannst du Playlists für eine ältere Version von FreeTube exportieren und importieren:\\n1. Exportiere deine Playlists, wenn diese Option aktiviert ist.\\n2. Lösche alle deine bestehenden Playlists mit der Option „Alle Playlists entfernen“ unter den Datenschutzeinstellungen.\\n3. Starte die ältere Version von FreeTube und importiere die exportierten Playlists.\\\"\"\n    Search history file: Suchverlaufsdatei\n    Search history: Suchverlauf\n    Import search history: Suchverlauf importieren\n    Export search history: Suchverlauf exportieren\n    All search history has been successfully imported: Der gesamte Suchverlauf wurde erfolgreich importiert\n    All search history has been successfully exported: Der gesamte Suchverlauf wurde erfolgreich exportiert\n  Distraction Free Settings:\n    Hide Live Chat: Live-Chat ausblenden\n    Hide Popular Videos: Beliebte Videos ausblenden\n    Hide Trending Videos: Trending-Videos ausblenden\n    Hide Recommended Videos: Empfohlene Videos ausblenden\n    Hide Channel Subscribers: Abozahl für Kanäle ausblenden\n    Hide Comment Likes: Likes bei Kommentaren ausblenden\n    Hide Video Likes And Dislikes: Likes und Dislikes ausblenden\n    Hide Video Views: Videoaufrufe ausblenden\n    Distraction Free Settings: Ablenkungsfreier Modus\n    Hide Active Subscriptions: Aktive Abos ausblenden\n    Hide Playlists: Playlists ausblenden\n    Hide Comments: Kommentare ausblenden\n    Hide Video Description: Videobeschreibung ausblenden\n    Hide Live Streams: Livestreams ausblenden\n    Hide Sharing Actions: Aktionen zum Teilen ausblenden\n    Hide Videos on Watch: Bereits angesehene Videos ausblenden\n    Hide Chapters: Kapitel ausblenden\n    Hide Upcoming Premieres: Anstehende Premieren ausblenden\n    Hide Channels: Videos aus Kanälen ausblenden\n    Hide Channels Placeholder: Kanal-ID\n    Display Titles Without Excessive Capitalisation: Titel ohne übermäßige Großschreibung und Zeichensetzung anzeigen\n    Hide Channel Playlists: 'Tab „Playlists“ im Kanal ausblenden'\n    Hide Channel Shorts: 'Tab „Shorts“ im Kanal ausblenden'\n    Hide Featured Channels: Hervorgehobene Kanäle ausblenden\n    Sections:\n      Side Bar: Seitenleiste\n      Channel Page: Kanäle\n      General: Allgemein\n      Watch Page: Während dem Anschauen\n      Subscriptions Page: Abos\n    Hide Channel Podcasts: 'Tab „Podcasts“ im Kanal ausblenden'\n    Hide Subscriptions Videos: Videos aus Abos ausblenden\n    Hide Subscriptions Shorts: Shorts aus Abos ausblenden\n    Hide Channel Releases: 'Tab „Veröffentlichungen“ im Kanal ausblenden'\n    Hide Subscriptions Live: Livestreams aus Abos ausblenden\n    Hide Profile Pictures in Comments: Profilbilder in den Kommentaren ausblenden\n    Hide Channels Invalid: Kanal-ID war ungültig\n    Hide Channels Disabled Message: Einige Kanäle wurden mit ID gesperrt und nicht verarbeitet. Die Funktion wird blockiert, während diese IDs aktualisieren\n    Hide Channels Already Exists: Kanal-ID bereits vorhanden\n    Hide Channels API Error: Fehler beim Abrufen des Kontos mit der bereitgestellten ID. Bitte überprüfe erneut, ob die ID korrekt ist.\n    Hide Videos, Playlists and Channels Containing Text: Videos und Playlists, die Text enthalten, ausblenden\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Wort, Wortfragment oder Phrase\n    Hide Channel Home: 'Tab „Startseite“ im Kanal ausblenden'\n    Show Added Items: Hinzugefügte Elemente anzeigen\n    Hide Channel Courses: Tab „Kurse“ im Kanal ausblenden\n    Hide Channel Posts: Tab „Beiträge“ im Kanal ausblenden\n    Hide Subscriptions Posts: Beiträge aus Abos ausblenden\n  The app needs to restart for changes to take effect. Restart and apply change?: Die App muss neu gestartet werden, damit die Änderungen wirksam werden. Neu starten und Änderung übernehmen?\n  Proxy Settings:\n    Ip: IP-Adresse\n    Error getting network information. Is your proxy configured properly?: Fehler beim Abrufen von Netzwerkinformationen. Ist dein Proxy richtig konfiguriert?\n    City: Stadt\n    Region: Region\n    Country: Land\n    Your Info: Deine Info\n    Test Proxy: Proxy testen\n    Clicking on Test Proxy will send a request to: Indem du auf „Proxy testen“ klickst, sendest du eine Anfrage an\n    Proxy Port Number: Proxy-Portnummer\n    Proxy Host: Proxy-Host\n    Proxy Protocol: Proxy-Protokoll\n    Enable Tor / Proxy: Tor / Proxy aktivieren\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube hat keinen eingebauten Proxy, kann aber mit einem externen Proxy verbunden werden, wie z. B. einem, der auf deinem Gerät läuft wie Tor, oder einem externen Proxy wie einem SOCKS5-Proxy, der von einigen VPNs bereitgestellt wird. Falls aktiviert, stelle sicher, dass dein Proxy/Tor richtig konfiguriert ist, da FreeTube ansonsten keine Daten abrufen kann.\n    Proxy Username: Proxy-Anmeldename\n    Proxy Password: Proxy-Passwort\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Benachrichtigen, wenn ein Abschnitt übersprungen wird\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock-API-URL (Standard ist https://sponsor.ajay.app)\n    Enable SponsorBlock: SponsorBlock aktivieren\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Option überspringen\n      Auto Skip: Automatisch überspringen\n      Show In Seek Bar: In Suchleiste anzeigen\n      Prompt To Skip: Zum Überspringen auffordern\n      Do Nothing: Nichts tun\n    Category Color: Kategoriefarbe\n    UseDeArrowTitles: DeArrow-Videotitel verwenden\n    UseDeArrowThumbnails: DeArrow für Miniaturansichten verwenden\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow-Thumbnail-Generator-API-URL (Standard ist https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Ignore Unsupported Action Warnings: Warnungen vor nicht unterstützten Aktionen ignorieren\n    External Player: Externer Video-Player\n    External Player Settings: Externe Video-Player\n    Custom External Player Executable: Benutzerdefinierte ausführbare Datei des Video-Players\n    Custom External Player Arguments: Benutzerdefinierte Argumente für externen Video-Player\n    Players:\n      None:\n        Name: Keine\n    Ignore Default Arguments: Standardargumente ignorieren\n  Parental Control Settings:\n    Parental Control Settings: Kindersicherung\n    Hide Unsubscribe Button: Schaltfläche „Deabonnieren“ ausblenden\n    Show Family Friendly Only: Nur familienfreundliche Inhalte anzeigen\n    Hide Search Bar: Suchleiste ausblenden\n    Hide Uploader on Watch page: Uploader auf der Videoseite ausblenden\n  Experimental Settings:\n    Experimental Settings: Experimentell\n    Warning: Diese Einstellungen sind experimentell und können zu Abstürzen führen, wenn sie aktiviert sind. Es wird dringend empfohlen, Backups zu erstellen. Verwendung auf eigene Gefahr!\n    Replace HTTP Cache: HTTP-Cache ersetzen\n  Password Dialog:\n    Password: Passwort\n    Enter Password To Unlock: Passwort eingeben, um die Einstellungen zu entsperren\n  Password Settings:\n    Remove Password: Passwort entfernen\n    Password Settings: Passwort\n    Set Password To Prevent Access: Passwort festlegen, um den Zugriff auf die Einstellungen zu verhindern\n    Set Password: Passwort festlegen\n  Sort Settings Sections (A-Z): Einstellungsabschnitte sortieren (A–Z)\n  Return to Settings Menu: Zurück zum Einstellungsmenü\nAbout:\n  #On About page\n  About: Über\n  #& About\n#On Channel Page\n  Website: Website\n  Blog: Blog\n  Credits: Danksagungen\n  FAQ: Häufig gestellte Fragen\n  Email: E-Mail\n  Beta: Beta\n  Donate: Spenden\n  Help: Hilfe\n  these people and projects: diesen Menschen und Projekten\n  Translate: Übersetzen\n  room rules: Raum-Regeln\n  Chat on Matrix: Auf Matrix chatten\n  Mastodon: Mastodon\n  Please check for duplicates before posting: Bitte überprüfe vor dem Erstellen, ob eine ähnliche Issue bereits existiert\n  GitHub issues: GitHub Issue-Tracker\n  Report a problem: Problem melden\n  FreeTube Wiki: FreeTube-Wiki\n  GitHub releases: GitHub-Veröffentlichungen\n  Downloads / Changelog: Downloads / Änderungsprotokoll\n  Source code: Quellcode\n  Discussions: Diskussionen\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Lizenziert unter der {licenseLink}\n  Please read the {roomRulesLink}: Bitte lies die {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube wird ermöglicht durch {creditsPageLink}\nChannel:\n  Subscribe: Abonnieren\n  Unsubscribe: Deabonnieren\n  Search Channel: Kanal durchsuchen\n  Your search results have returned 0 results: Deine Suche hat 0 Ergebnisse geliefert\n  Videos:\n    Videos: Videos\n    This channel does not currently have any videos: Dieser Kanal hat aktuell keine Videos\n    Sort Types:\n      Newest: Neueste\n      Oldest: Älteste\n      Most Popular: Beliebteste\n  Playlists:\n    Playlists: Playlists\n    This channel does not currently have any playlists: Dieser Kanal hat derzeit keine Playlists\n    Sort Types:\n      Last Video Added: Zuletzt hinzugefügtes Video\n      Newest: Neuestes\n      Oldest: Ältestes\n  About:\n    About: Über\n    Channel Description: Kanalbeschreibung\n    Featured Channels: Empfohlene Kanäle\n    Tags:\n      Search for: Nach „{tag}“ suchen\n      Tags: Schlagwörter\n    Details: Details\n    Location: Standort\n    Joined: Beigetreten\n  Added channel to your subscriptions: Der Kanal wurde deinen Abos hinzugefügt\n  Removed subscription from {count} other channel(s): Abo von {count} anderem Kanal / anderen Kanälen entfernt\n  Channel has been removed from your subscriptions: Der Kanal wurde von deinen Abos entfernt\n  Channel Tabs: Kanal-Registerkarten\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Dieser Kanal ist altersbeschränkt und kann derzeit nicht in FreeTube angesehen werden.\n  This channel does not allow searching: Dieser Kanal erlaubt keine Suche\n  This channel does not exist: Dieser Kanal existiert nicht\n  Posts:\n    This channel currently does not have any posts: Dieser Kanal hat derzeit keine Beiträge\n    votes: '{votes} Stimmen'\n    Reveal Answers: Antworten anzeigen\n    Hide Answers: Antworten verbergen\n    Video hidden by FreeTube: Video versteckt von FreeTube\n    View Full Post: Vollständigen Beitrag anzeigen\n    Viewing Posts Only Supported By Invidious: Das Anzeigen von Beiträgen wird nur von Invidious unterstützt. Gehe zum Tab „Beiträge“ eines Kanals, um dort Inhalte ohne Invidious anzuzeigen.\n  Live:\n    Live: Live\n    This channel does not currently have any live streams: Dieser Kanal hat derzeit keine Livestreams\n  Shorts:\n    This channel does not currently have any shorts: Dieser Kanal hat derzeit keine Shorts\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Dieser Kanal hat derzeit keine Podcasts\n  Releases:\n    Releases: Veröffentlichungen\n    This channel does not currently have any releases: Dieser Kanal hat derzeit keine Veröffentlichungen\n  Home:\n    Home: Startseite\n    View Playlist: Playlist anzeigen\n  Courses:\n    This channel does not currently have any courses: Dieser Kanal hat derzeit keine Kurse\n    Courses: Kurse\nVideo:\n  Open in YouTube: In YouTube öffnen\n  Copy YouTube Link: YouTube-Link kopieren\n  Open YouTube Embedded Player: Eingebetteten YouTube-Player öffnen\n  Copy YouTube Embedded Player Link: Link zum eingebetteten YouTube-Video kopieren\n  Open in Invidious: In Invidious öffnen\n  Copy Invidious Link: Invidious-Link kopieren\n  Views: Aufrufe\n  Watched: Angesehen\n  # As in a Live Video\n  Live: Livestream\n  Live Now: Jetzt live\n  Live Chat: Live-Chat\n  Enable Live Chat: Live-Chat aktivieren\n  Live Chat is currently not supported in this build.: Live-Chat wird in diesem Build derzeit nicht unterstützt.\n  Live chat is enabled. Chat messages will appear here once sent.: Live-Chat ist aktiviert. Chat-Nachrichten werden hier angezeigt, sobald sie gesendet wurden.\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': Live-Chat wird von der Invidious-API derzeit nicht unterstützt. Eine direkte Verbindung zu YouTube ist erforderlich.\n  Published:\n    In less than a minute: In weniger als einer Minute\n  Published on: Veröffentlicht am\n\n#& Videos\n  Video has been removed from your history: Video wurde aus deinem Verlauf entfernt\n  Video has been marked as watched: Video wurde als angesehen markiert\n  Remove From History: Aus dem Verlauf entfernen\n  Mark As Watched: Als angesehen markieren\n  Autoplay: Automatische Wiedergabe\n  Previous: Vorheriges\n  Next: Weiter\n  Reverse Playlist: Umgekehrte Reihenfolge\n  Shuffle Playlist: Zufällige Reihenfolge\n  Loop Playlist: Playlist wiederholen\n  Starting soon, please refresh the page to check again: Stream startet bald. Bitte aktualisiere die Seite, um erneut nachzusehen\n  Copy Invidious Channel Link: Invidious-Kanallink kopieren\n  Open Channel in Invidious: Kanal auf Invidious öffnen\n  Copy YouTube Channel Link: YouTube-Kanallink kopieren\n  Open Channel in YouTube: Kanal auf YouTube öffnen\n  Started streaming on: Streaming angefangen am\n  Streamed on: Gestreamt am\n  Video has been removed from your saved list: Video wurde aus deiner Liste der gespeicherten Videos entfernt\n  Video has been saved: Video wurde gespeichert\n  Save Video: Video speichern\n  Sponsor Block category:\n    music offtopic: Musik Offtopic\n    interaction: Interaktion\n    self-promotion: Eigenwerbung\n    outro: Abspann\n    intro: Intro\n    sponsor: Sponsor\n    recap: Vorschau/Rückblick\n    filler: Füller\n  External Player:\n    OpenInTemplate: In {externalPlayer} öffnen\n    Unsupported Actions:\n      setting a playback rate: Wiedergabegeschwindigkeit festlegen\n      starting video at offset: Video mit Versatz starten\n      looping playlists: Playlists wiederholen\n      shuffling playlists: Playlists durcheinander mischen\n      reversing playlists: Playlists umkehren\n      opening specific video in a playlist (falling back to opening the video): Bestimmtes Video aus einer Playlist öffnen (Rückgriff auf Öffnen des Videos)\n      opening playlists: Playlists öffnen\n    UnsupportedActionTemplate: '{externalPlayer} unterstützt nicht: {action}'\n    OpeningTemplate: '{videoOrPlaylist} wird in {externalPlayer} geöffnet ...'\n    playlist: Playlist\n    video: Video\n  Premieres: Premiere\n  Show Super Chat Comment: Super-Chat-Kommentar anzeigen\n  Scroll to Bottom: Nach unten scrollen\n  Upcoming: Demnächst\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Live-Chat ist für diesen Stream nicht verfügbar. Möglicherweise wurde er vom Uploader deaktiviert.\n  Unhide Channel: Kanal anzeigen\n  Hide Channel: Kanal ausblenden\n  More Options: Weitere Optionen\n  Player:\n    Audio Tracks: Audiospuren\n    Theatre Mode: Kinomodus\n    Exit Theatre Mode: Kinomodus beenden\n    Full Window: Vollständiges Fenster\n    Take Screenshot: Screenshot aufnehmen\n    Show Stats: Statistiken anzeigen\n    Stats:\n      Stats: Statistiken\n      Video ID: 'Videokennung (ID): {videoId}'\n      Media Formats: 'Medienformate: {formats}'\n      Resolution: 'Auflösung: {width}×{height}{''@''}{frameRate}'\n      Player Dimensions: 'Player-Größe: {width}×{height}'\n      Bitrate: 'Bitrate: {bitrate} kb/s'\n      Volume: 'Lautstärke: {volumePercentage} %'\n      Bandwidth: 'Bandbreite: {bandwidth} kb/s'\n      Buffered: 'Gepuffert: {bufferedPercentage} %'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Ausgelassene Einzelbilder: {droppedFrames} / Einzelbilder insgesamt: {totalFrames}'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n    You appear to be offline: Du scheinst offline zu sein.\n    Playback will resume automatically when your connection comes back: Die Wiedergabe wird automatisch fortgesetzt, wenn deine Verbindung wiederhergestellt ist.\n    Skipped segment: 'Segment {segmentCategory} übersprungen'\n    TranslatedCaptionTemplate: '{language} (übersetzt von {originalLanguage})'\n    Exit Full Window: Vollständiges Fenster beenden\n    Hide Stats: Statistiken ausblenden\n    Autoplay is off: Automatische Wiedergabe ist ausgeschaltet\n    Autoplay is on: Automatische Wiedergabe ist eingeschaltet\n  IP block: YouTube hat deine IP-Adresse für die Videowiedergabe gesperrt. Bitte versuche, einen anderen VPN oder Proxy zu nutzen.\n  Unlisted: Nicht gelistet\n  MembersOnly: Videos, die nur für Mitglieder bestimmt sind, können mit FreeTube nicht angesehen werden, da sie einen Google-Login und eine kostenpflichtige Kanalmitgliedschaft erfordern.\n  AgeRestricted: Videos mit Altersbeschränkung können mit FreeTube nicht angesehen werden, da sie eine Google-Anmeldung und die Verwendung eines altersgeprüften YouTube-Kontos erfordern.\n  DeArrow:\n    Show Modified Details: Geänderte Details anzeigen\n    Show Original Details: Originaldetails anzeigen\n  DRMProtected: DRM-geschützte Videos können in FreeTube nicht abgespielt werden, da sie proprietäre Closed-Source-Komponenten benötigen. Wenn du dieses Video ansehen möchtest, sieh es dir bitte auf der offiziellen YouTube-Website in einem DRM-fähigen Webbrowser an.\n#& Playlists\n  Save Watched Progress: Videofortschritt speichern\n  Watched Progress Saved: Videofortschritt gespeichert\n  Popout Live Chat: Öffnet ein neues Browserfenster mit dem aktuellen Video-Live-Chat\n  Watch:\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Verbleibende SABR Wartezeit: {remindingTimeSeconds}s'\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Verbleibende Werbezeit: {remindingTimeSeconds}s'\nPlaylist:\n  #& About\n  View Full Playlist: Vollständige Playlist ansehen\n  Last Updated On: Zuletzt aktualisiert am\n  Playlist: Playlist\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    VideoTitleDescending: Titel (Z–A)\n    DateAddedNewest: Hinzugefügt am (neueste)\n    DateAddedOldest: Hinzugefügt am (älteste)\n    AuthorAscending: Autor (A–Z)\n    AuthorDescending: Autor (Z–A)\n    VideoTitleAscending: Titel (A–Z)\n    Custom: Benutzerdefiniert\n    VideoDurationAscending: Dauer (kürzeste)\n    VideoDurationDescending: Dauer (längste)\n    PublishedNewest: Veröffentlichungsdatum (neueste)\n    PublishedOldest: Veröffentlichungsdatum (älteste)\nChange Format:\n  Change Media Formats: Medienformate ändern\n  Use Dash Formats: DASH-Formate verwenden\n  Use Legacy Formats: Veraltete Formate verwenden\n  Use Audio Formats: Audioformate verwenden\n  Audio formats are not available for this video: Audioformate sind für dieses Video nicht verfügbar\n  Dash formats are not available for this video: DASH-Formate sind für dieses Video nicht verfügbar\n  Legacy formats are not available for this video: Veraltete Formate sind für dieses Video nicht verfügbar\nShare:\n  Share Video: Video teilen\n  Share Playlist: Playlist teilen\n  Copy Link: Link kopieren\n  Open Link: Link öffnen\n  Copy Embed: Eingebettete Version kopieren\n  Open Embed: Eingebettete Version öffnen\n  # On Click\n  Invidious URL copied to clipboard: Invidious-URL in die Zwischenablage kopiert\n  Invidious Embed URL copied to clipboard: Invidious' eingebettete URL in die Zwischenablage kopiert\n  YouTube URL copied to clipboard: YouTube-URL in die Zwischenablage kopiert\n  YouTube Embed URL copied to clipboard: YouTubes eingebettete URL in die Zwischenablage kopiert\n  Include Timestamp: Zeitstempel miteinbeziehen\n  YouTube Channel URL copied to clipboard: YouTube-Kanal-URL in die Zwischenablage kopiert\n  Invidious Channel URL copied to clipboard: Invidious-Kanal-URL in die Zwischenablage kopiert\n  Share Channel: Kanal teilen\n  Share Post: Post teilen\nMini Player: Mini-Video-Player\nComments:\n  Comments: Kommentare\n  Click to View Comments: Kommentare anzeigen\n  Getting comment replies, please wait: Antworten auf Kommentare werden geladen, bitte warten\n  Hide Comments: Kommentare ausblenden\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: Keine Kommentare zu diesem Video vorhanden\n  Load More Comments: Weitere Kommentare laden\n  There are no more comments for this video: Es gibt keine weiteren Kommentare zu diesem Video\n  Newest first: Neueste zuerst\n  Top comments: Top-Kommentare\n  Show More Replies: Weitere Antworten anzeigen\n  Pinned by: Angeheftet von\n  Member: Mitglied\n  View {replyCount} replies: '1 Antwort ansehen | {replyCount} Antworten ansehen'\n  Hearted: Gefällt mir\n  Subscribed: Abonniert\n  There are no comments available for this post: Keine Kommentare für diesen Beitrag vorhanden\n  Hide {replyCount} replies: 1 Antwort ausblenden | {replyCount} Antworten ausblenden\n  View 1 reply from {channelName}: 1 Antwort von {channelName} ansehen\n  View {replyCount} replies from {channelName} and others: '{replyCount} Antworten von {channelName} und anderen ansehen'\nUp Next: Nächster Titel\n\n# Toast Messages\nLocal API Error (Click to copy): Lokaler API-Fehler (Zum Kopieren anklicken)\nInvidious API Error (Click to copy): Invidious-API-Fehler (Zum Kopieren anklicken)\nFalling back to Invidious API: Es wird auf die Invidious-API zurückgegriffen\nFalling back to Local API: Es wird auf die lokale API zurückgegriffen\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Dieses Video ist aufgrund fehlender Formate nicht verfügbar. Zugriffsbeschränkungen im Land kann dafür der Grund sein.\nLoop is now disabled: Wiederholung ist jetzt deaktiviert\nLoop is now enabled: Wiederholung ist jetzt aktiviert\nShuffle is now disabled: Zufallswiedergabe ist jetzt deaktiviert\nShuffle is now enabled: Zufallswiedergabe ist jetzt aktiviert\nPlaying Next Video: Nächstes Video wird abgespielt\nPlaying Previous Video: Vorheriges Video wird abgespielt\nCanceled next video autoplay: Automatische Wiedergabe des nächsten Videos abgebrochen\n'The playlist has ended. Enable loop to continue playing': 'Ende der Playlist erreicht. Aktiviere die Wiederholung, um die Wiedergabe fortzusetzen'\n\nYes: Ja\nNo: Nein\nLocale Name: Deutsch\nProfile:\n  '{profile} is now the active profile': '{profile} ist jetzt dein aktives Profil'\n  Your default profile has been changed to your primary profile: Dein Standardprofil wurde in dein Hauptprofil geändert\n  Removed {profile} from your profiles: '{profile} wurde aus deinen Profilen entfernt'\n  Your default profile has been set to {profile}: 'Dein Standardprofil wurde auf {profile} eingestellt'\n  Profile has been created: Profil wurde erstellt\n  Profile has been updated: Profil wurde aktualisiert\n  Your profile name cannot be empty: Dein Profilname darf nicht leer sein\n  All subscriptions will also be deleted.: Alle Abos werden ebenfalls gelöscht.\n  Are you sure you want to delete this profile?: Bist du sicher, dass du dieses Profil löschen willst?\n  Delete Profile: Profil löschen\n  Make Default Profile: Als Standardprofil festlegen\n  Update Profile: Profil aktualisieren\n  Create Profile: Profil erstellen\n  Profile Preview: Profilvorschau\n  Custom Color: Benutzerdefinierte Farbe\n  Color Picker: Farbauswahl\n  Edit Profile: Profil bearbeiten\n  Create New Profile: Neues Profil erstellen\n  Profile Manager: Profilverwaltung\n  All Channels: Alle Kanäle\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Bist du sicher, dass du die ausgewählten Kanäle löschen möchtest? Dadurch wird der Kanal nicht aus einem anderen Profil gelöscht.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Dies ist dein Hauptprofil. Bist du sicher, dass du die ausgewählten Kanäle löschen möchtest? Die gleichen Kanäle werden auch in allen anderen Profilen gelöscht.\n  No channel(s) have been selected: Es wurde kein Kanal/keine Kanäle ausgewählt\n  Add Selected To Profile: Ausgewählte zum Profil hinzufügen\n  Delete Selected: Ausgewählte löschen\n  Select None: Alles abwählen\n  Select All: Alles auswählen\n  '{number} selected': '{number} ausgewählt'\n  Other Channels: Andere Kanäle\n  Subscription List: Abo-Liste\n  Profile Select: Profilauswahl\n  Profile Filter: Profilfilter\n  Profile Settings: Profil\n  Toggle Profile List: Profilauswahl\n  Profile Name: Profilname\n  Edit Profile Name: Profilname bearbeiten\n  Create Profile Name: Profilname erstellen\n  Open Profile Dropdown: Profil-Klappliste öffnen\n  Close Profile Dropdown: Profil-Klappliste schließen\nThe playlist has been reversed: Die Playlist wurde umgedreht\nA new blog is now available, {blogTitle}. Click to view more: 'Ein neuer Blogeintrag ist verfügbar: „{blogTitle}“. Klicke, um mehr zu sehen'\nDownload From Site: Von der Website herunterladen\nVersion {versionNumber} is now available!  Click for more details: Version {versionNumber} ist jetzt verfügbar!  Für mehr Details klicken\nTooltips:\n  General Settings:\n    Thumbnail Preference: Alle Vorschaubilder in FreeTube werden verpixelt, versteckt oder durch ein Einzelbild aus dem Video ersetzt, anstatt das Standard-Vorschaubild anzuzeigen.\n    Invidious Instance: Die Invidious-Instanz, mit der sich FreeTube für API-Aufrufe verbinden wird.\n    Fallback to Non-Preferred Backend on Failure: Wenn deine bevorzugte API ein Problem hat, wird FreeTube automatisch versuchen, deine nicht-bevorzugte API als Ausweichmethode zu verwenden, wenn sie aktiviert ist.\n    Preferred API Backend: Wähle das Backend aus, welches FreeTube zum Laden der Daten nutzen soll. Die lokale API ist ein eingebauter Extrahierer. Die Invidious-API erfordert einen Invidious-Server, zu dem eine Verbindung hergestellt werden muss.\n    Region for Trending: Die Trendregion erlaubt es dir auszuwählen, aus welchem Land die Trends angezeigt werden sollen.\n    External Link Handling: \"Wähle das Standardverhalten, wenn ein Link angeklickt wird, der nicht in FreeTube geöffnet werden kann.\\nStandardmäßig wird FreeTube den angeklickten Link in deinem Standardbrowser öffnen.\\n\"\n    Open Deep Links In New Window: URLs, die an FreeTube übergeben werden, z. B. durch Redirect-Browser-Erweiterungen oder Befehlszeilenargumente, werden in einem neuen Fenster geöffnet.\n  Subscription Settings:\n    Fetch Feeds from RSS: Wenn aktiviert, verwendet FreeTube RSS anstelle der Standardmethode, um deinen Abo-Feed abzurufen. RSS ist schneller und verhindert die IP-Sperren, liefert aber bestimmte Informationen wie Videodauer, den Live-Status oder Beiträge nicht\n    Fetch Automatically: Wenn aktiviert, ruft FreeTube deine Abos automatisch beim Start und beim Öffnen eines neuen Fensters ab.\n  Player Settings:\n    Default Video Format: Lege die Formate fest, die bei der Wiedergabe eines Videos verwendet werden. DASH-Formate können höhere Auflösungen wiedergeben. Altformate sind auf maximal 360p beschränkt, verbrauchen aber weniger Bandbreite. Audioformate sind reine Audiostreams.\n    Proxy Videos Through Invidious: Stellt eine Verbindung mit Invidious her, um Videos bereitzustellen, anstatt eine direkte Verbindung mit YouTube herzustellen.\n    Scroll Playback Rate Over Video Player: Während sich der Cursor über dem Video befindet, halte die Strg-Taste (Befehlstaste auf dem Mac) gedrückt und bewege das Mausrad vorwärts oder rückwärts, um die Abspielgeschwindigkeit zu steuern. Halte die Strg-Taste (Befehlstaste auf dem Mac) gedrückt und klicke mit der linken Maustaste, um schnell zur Standard-Wiedergabegeschwindigkeit zurückzukehren (1x, sofern sie nicht in den Einstellungen geändert wurde).\n    Skip by Scrolling Over Video Player: Verwende das Scrollrad, um durch das Video zu springen, MPV-Stil.\n  External Player Settings:\n    Custom External Player Arguments: Alle benutzerdefinierten Befehlszeilenargumente, die an den externen Video-Player übergeben werden sollen.\n    Ignore Warnings: Warnungen unterdrücken, wenn der aktuelle externe Video-Player die aktuelle Aktion nicht unterstützt (z. B. das Umkehren von Playlists usw.).\n    Custom External Player Executable: Standardmäßig wird FreeTube annehmen, dass der gewählte externe Video-Player unter der PATH-Umgebungsvariable gefunden werden kann. Falls nötig, kann hier ein benutzerdefinierter Pfad festgelegt werden.\n    External Player: Wenn du einen externen Video-Player auswählst, wird auf dem Vorschaubild ein Symbol angezeigt, mit dem du das Video (die Playlist, falls unterstützt) im externen Video-Player öffnen kannst. Achtung, die Einstellungen von Invidious wirken sich nicht auf externe Video-Player aus.\n    DefaultCustomArgumentsTemplate: '(Standardwert: „{defaultCustomArguments}“)'\n    Ignore Default Arguments: Schicke keine Standardargumente an den externen Video-Player außer der Video-URL (z.B. Abspiel-Geschwindigkeit, Playlist-URL etc.). Besondere Argumente werden weiterhin weitergeleitet.\n  Experimental Settings:\n    Replace HTTP Cache: Deaktiviert den festplattenbasierten HTTP-Cache von Electron und aktiviert einen benutzerdefinierten In-Memory-Image-Cache. Dies führt zu einer erhöhten RAM-Auslastung.\n  Distraction Free Settings:\n    Hide Channels: Gib eine Kanal-ID ein, um zu verhindern, dass alle Videos, Playlists und der Kanal selbst in der Suche, den Trends, den beliebtesten und den empfohlenen Videos angezeigt werden. Die eingegebene Kanal-ID muss vollständig übereinstimmen, und es wird zwischen Groß- und Kleinschreibung unterschieden.\n    Hide Subscriptions Live: Diese Einstellung wird durch die App-weite Einstellung „{appWideSetting}“ im Abschnitt „{subsection}“ der „{settingsSection}“ außer Kraft gesetzt\n    Hide Videos, Playlists and Channels Containing Text: Gib ein Wort, einen Teil eines Wortes oder einen Satz ein (Groß-/Kleinschreibung wird ignoriert), um alle Videos und Playlists, welche es in ihren Originaltiteln enthalten, auf ganz FreeTube auszublenden. Dein Verlauf, deine eigenen Playlists und Videos innerhalb Playlists sind davon nicht betroffen.\n    Hide Videos on Watch: Blendet bereits angesehene Videos aus den Tabs „Videos“, „Shorts“ und „Live“ der Abo- und Kanalseiten aus. Beeinflusst nicht den „Home“-Tab der Kanalseiten\n  SponsorBlock Settings:\n    UseDeArrowTitles: Videotitel durch von der Community eingereichte Titel von DeArrow ersetzen.\n    UseDeArrowThumbnails: Video-Miniaturansichten durch Miniaturansichten von DeArrow ersetzen.\nPlaying Next Video Interval: Nächstes Video wird sofort abgespielt. Zum Abbrechen klicken. | Nächstes Video wird in {nextVideoInterval} Sekunden abgespielt. Zum Abbrechen klicken. | Nächstes Video wird in {nextVideoInterval} Sekunden abgespielt. Zum Abbrechen klicken.\nMore: Mehr\nUnknown YouTube url type, cannot be opened in app: Unbekannter YouTube-URL-Typ, kann in der App nicht geöffnet werden\nOpen New Window: Neues Fenster öffnen\nDefault Invidious instance has been cleared: Standardmäßige Invidious-Instanz wurde gelöscht\nDefault Invidious instance has been set to {instance}: Standardmäßige Invidious-Instanz wurde auf {instance} festgelegt\nSearch Bar:\n  Clear Input: Eingabe löschen\n  Remove: Entfernen\nAre you sure you want to open this link?: Bist du sicher, dass du diesen Link öffnen willst?\nExternal link opening has been disabled in the general settings: Das Öffnen externer Links wurde in den allgemeinen Einstellungen deaktiviert\nScreenshot Success: Screenshot wurde gespeichert\nScreenshot Error: Screenshot fehlgeschlagen. {error}\nNew Window: Neues Fenster\nChannels:\n  Channels: Kanäle\n  Title: Kanal-Liste\n  Search bar placeholder: Kanäle durchsuchen\n  Count: '{number} Kanal/Kanäle gefunden.'\n  Empty: Deine Kanalliste ist derzeit leer.\n  Unsubscribe Prompt: Bist du sicher, dass du dein Abo für „{channelName}“ entfernen willst?\nClipboard:\n  Copy failed: Kopieren in die Zwischenablage fehlgeschlagen\n  Cannot access clipboard without a secure connection: Zugriff auf die Zwischenablage ist ohne sichere Verbindung nicht möglich\nChapters:\n  Chapters: Kapitel\n  Key Moments: Highlights\nPreferences: Einstellungen\nOk: OK\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Dieser Hashtag enthält derzeit keine Videos\nChannel Hidden: '{channel} wurde zum Kanalfilter hinzugefügt'\nGo to page: Zu {page} gehen\nChannel Unhidden: '{channel} wurde aus dem Kanalfilter entfernt'\nTrimmed input must be at least N characters long: Gekürzte Eingaben müssen mindestens 1 Zeichen lang sein | Gekürzte Eingaben müssen mindestens {length} Zeichen lang sein\nTag already exists: Das Schlagwort „{tagName}“ existiert bereits\nClose Banner: Banner schließen\nAge Restricted:\n  This channel is age restricted: Dieser Kanal ist altersbeschränkt\n  This video is age restricted: Dieses Video ist altersbeschränkt\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nMoments Ago: vor wenigen Augenblicken\nFeed:\n  Refresh Feed: '{subscriptionName} neu laden'\n  Feed Last Updated: '{feedName} zuletzt aktualisiert: {date}'\nYes, Delete: Ja, löschen\nCancel: Abbrechen\nSearch character limit: Die Suche ist länger als das {searchCharacterLimit}-Zeichen-Limit\nYes, Restart: Ja, neu starten\nYes, Open Link: Ja, Link öffnen\nSearch Listing:\n  Label:\n    4K: 4K\n    Closed Captions: Untertitel\n    Subtitles: Untertitel\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Neu\n    3D: 3D\nKeys:\n  arrowdown: Pfeil nach unten\n  arrowleft: Pfeil nach links\n  arrowup: Pfeil nach oben\n  ctrl: Strg\n  alt: Alt\n  arrowright: Pfeil nach rechts\n  plus: Plus\n  enter: Enter\n  shift: Shift\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: Mit der rechten Maustaste klicken oder halten, um den Verlauf zu sehen\nAutoplay Interruption Timer: Automatische Wiedergabe wurde aufgrund von {autoplayInterruptionIntervalHours} Stunden Inaktivität abgebrochen\nDescription:\n  Collapse Description: Weniger anzeigen\n  Expand Description: '...mehr'\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Tastenkombinationen\n  Sections:\n    Video:\n      Playback: 'Video: Wiedergabe'\n      General: 'Video: Allgemein'\n    App:\n      Situational: 'App: situationsbezogen'\n      General: 'App: allgemein'\n  History Backward: Eine Seite zurückgehen\n  New Window: Ein neues Fenster öffnen\n  Navigate to Settings: Zur Einstellungsseite navigieren\n  Navigate to History: Zur Verlaufsseite navigieren\n  Stats: Video-Statistiken anzeigen\n  Fullscreen: Vollbildmodus umschalten\n  Decrease Video Speed: Verringern der Videogeschwindigkeit basierend auf dem Intervall der Videowiedergaberate\n  Take Screenshot: Screenshot erstellen\n  Minimize Window: Fenster minimieren\n  Close Window: Fenster schließen\n  Reset Zoom: Zoomstufe / UI-Skalierung zurücksetzen\n  Zoom In: Vergrößern\n  Zoom Out: Verkleinern\n  Focus Search: Suchleiste fokussieren\n  Search in New Window: In einem neuen Fenster suchen\n  Refresh: Feed mit aktuellen Inhalten aktualisieren\n  Large Fast Forward: 10 Sekunden vorspulen / Vorspulen basierend auf der aktuellen Wiedergabegeschwindigkeit\n  Mute: Stummschaltung\n  Volume Up: Lautstärke erhöhen\n  Volume Down: Lautstärke verringern\n  Next Chapter: Nächstes Kapitel\n  Last Chapter: Letztes Kapitel\n  Show Keyboard Shortcuts: Tastaturkürzel anzeigen\n  History Forward: Eine Seite nach vorne gehen\n  Increase Video Speed: Erhöhen der Videogeschwindigkeit basierend auf dem Intervall der Videowiedergaberate\n  Large Rewind: 10 Sekunden zurückspulen / Zurückspulen basierend auf der aktuellen Wiedergabegeschwindigkeit\n  Full Window: Ganzes Fenster umschalten\n  Theatre Mode: Kinomodus umschalten\n  Toggle Developer Tools: Entwicklungswerkzeuge umschalten\n  Play: Wiedergabe/Pause umschalten\n  Focus Secondary Search: Fokus auf die sekundäre Suchleiste (falls eine vorhanden ist)\n  Captions: Untertitel ein-/ausschalten\n  Picture in Picture: Bild-in-Bild-Modus umschalten\n  Last Frame: Vorheriges Bild (bei pausierter Wiedergabe)\n  Small Fast Forward: X Sekunden vorspulen, basierend auf dem Vorspulintervall und der aktuellen Wiedergabegeschwindigkeit\n  Skip by Tenths: Prozentuales Überspringen des Videos (3 Sprünge bis 30% der Dauer)\n  Next Frame: Nächstes Bild (bei pausierter Wiedergabe)\n  Small Rewind: X Sekunden zurückspulen, basierend auf dem Rückspulintervall und der aktuellen Wiedergabegeschwindigkeit\n  End: Zum Ende des Videos springen\n  Home: Zum Anfang des Videos springen\n  Skip to Next Video: Zum nächsten Video in der Playlist bzw. nächsten empfohlenen Video springen\n  Skip to Previous Video: Zum vorherigen Video in der Playlist springen\nshortcutLabelSeparator: ｜\nCompact side navigation: Seitenleiste minimieren\nExpand side navigation: Seitenleiste erweitern\n"
  },
  {
    "path": "static/locales/el.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Ελληνικά'\n\n# Webkit Menu Bar\nFile: 'Αρχείο'\nQuit: 'Έξοδος'\nEdit: 'Επεξεργασία'\nUndo: 'Αναίρεση'\nRedo: 'Επανεκτέλεση'\nCut: 'Αποκοπή'\nCopy: 'Αντιγραφή'\nPaste: 'Επικόλληση'\nDelete: 'Διαγραφή'\nSelect all: 'Επιλογή όλων'\nToggle Developer Tools: 'Εναλλαγή Εργαλείων Προγραμματιστών'\nActual size: 'Πραγματικό μέγεθος'\nZoom in: 'Μεγέθυνση'\nZoom out: 'Σμίκρυνση'\nToggle fullscreen: 'Εναλλαγή Πλήρους οθόνης'\nWindow: 'Παράθυρο'\nMinimize: 'Ελαχιστοποίηση'\nClose: 'Κλείσιμο'\nBack: 'Μετάβαση πίσω'\nForward: 'Μετάβαση μπροστά'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Βίντεο'\n  Shorts: Σύντομα Βίντεο\n  Live: Ζωντανά\n  Posts: Αναρτήσεις\n  Sort By: 'Ταξινόμηση κατά'\n\n# Search Bar\n  Counts:\n    Video Count: 1 βίντεο | {count} βίντεο\n    Channel Count: 1 κανάλι | {count} κανάλια\n    Subscriber Count: 1 συνδρομητής | {count} συνδρομητές\n    View Count: 1 προβολή | {count} προβολές\n    Watching Count: 1 παρακολούθηση | {count} παρακολουθούν\n    Comment Count: 1 σχόλιο | {count} σχόλια\n    Like Count: 1 Μου αρρέσει | {count} Μου αρρέσει\nSearch / Go to URL: 'Αναζήτηση/Μετάβαση σε URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Φίλτρα αναζήτησης'\n  Sort By:\n    Most Relevant: 'Πιο σχετικά'\n    Rating: 'Αξιολόγηση'\n    Upload Date: 'Ημερομηνία μεταφόρτωσης'\n    View Count: 'Πλήθος Προβολών'\n  Time:\n    Time: 'Ώρα'\n    Any Time: 'Οποτεδήποτε'\n    Last Hour: 'Τελευταίας ώρας'\n    Today: 'Σήμερα'\n    This Week: 'Τρέχουσα Εβδομάδα'\n    This Month: 'Τρέχων μήνα'\n    This Year: 'Τρέχων έτος'\n  Type:\n    Type: 'Είδος'\n    All Types: 'Όλα τα είδη'\n    Videos: 'Βίντεο'\n    Channels: 'Κανάλια'\n    #& Playlists\n    Movies: Ταινίες\n  Duration:\n    Duration: 'Διάρκεια'\n    All Durations: 'Οποιασδήποτε Διάρκειας'\n    Short (< 4 minutes): 'Μικρό(<4 λεπτών)'\n    Long (> 20 minutes): 'Μεγάλο (>20 λεπτών)'\n  # On Search Page\n    Medium (4 - 20 minutes): Μεσαίο (4 - 20 λεπτά)\n  Search Results: 'Αποτελέσματα αναζήτησης'\n  Fetching results. Please wait: 'Aνάκτηση αποτελεσμάτων. Παρακαλώ περιμένετε'\n  Fetch more results: 'Λήψη περισσότερων αποτελεσμάτων'\n# Sidebar\n  There are no more results for this search: Δεν υπάρχουν άλλα αποτελέσματα για αυτήν την αναζήτηση\n  Features:\n    Live: Ζωντανά\n    4K: 4K\n    Subtitles: Υπότιτλοι\n    3D: 3D\n    Location: Τοποθεσία\n    360 Video: 360 Βίντεο\n    HDR: HDR\n    VR180: VR180\n    Features: Χαρακτηριστικά\n    HD: HD\n    Creative Commons: Κοινά Δημιουργήματα\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'συνδρομές'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Η λίστα Συνδρομών σας είναι προς το παρόν κενή. Αν θέλετε να εισάγετε τις συνδρομές σας μπορείτε να μεταβείτε στις Ρυθμίσεις Δεδομένων και να επιλέξετε Εισαγωγή Συνδρομών ή μπορείτε να αναζητήσετε ένα κανάλι και να εγγραφείτε σε αυτό.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Αυτό το προφίλ διαθέτει ήδη ένα μεγάλο αριθμό Συνδρομών. Εξαναγκασμένη εναλλαγή σε λειτουργία RSS για αποφυγή περιορισμού των κλήσεων\n  Load More Videos: Φόρτωση περισσότερων Βίντεο\n  Error Channels: Κανάλια με προβλήματα\n  Disabled Automatic Fetching: Έχετε απενεργοποιήσει την αυτόματη ανάκτηση Συνδρομών. Ανανεώστε τις Συνδρομές για να τις δείτε εδώ.\n  Empty Channels: Τα εγγεγραμμένα κανάλια σας προς το παρόν δεν έχουν βίντεο.\n  Subscriptions Tabs: Καρτέλες Συνδρομών\n  All Subscription Tabs Hidden: Όλες οι καρτέλες Συνδρομών είναι κρυμμένες. Για να δείτε περιεχόμενο εδώ, εμφανίστε ορισμένες καρτέλες στην ενότητα \"{subsection}\" στο \"{settingsSection}\".\n  Load More Posts: Φόρτωση Περισσότερων Αναρτήσεων\n  Empty Posts: Τα εγγεγραμμένα κανάλια σας προς το παρόν δεν έχουν αναρτήσεις.\nTrending:\n  Trending: 'Τάσεις'\n  Gaming: Παιχνίδια\n  Trending Tabs: Καρτέλες Τάσεων\n  Sports: Αθλητικά\nMost Popular: 'Δημοφιλέστερα'\nPlaylists: 'Λίστες αναπαραγωγής'\nUser Playlists:\n  Your Playlists: 'Προσωπικές Λίστες αναπαραγωγής'\n  Search bar placeholder: Αναζήτηση λίστες αναπαραγωγής\n  Empty Search Message: Δεν υπάρχουν βίντεο σε αυτή τη λίστα αναπαραγωγής που να ταιριάζουν με την αναζήτησή σας\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Δεν υπήρχαν βίντεο για αφαίρεση.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Αυτή η λίστα αναπαραγωγής χρησιμοποιεί τώρα γρήγορο σελιδοδείκτη αντί για {oldPlaylistName}. Κάντε κλικ εδώ για αναίρεση\n      This playlist does not exist: Αυτή η λίστα αναπαραγωγής δεν υπάρχει\n      This playlist is already being used for quick bookmark.: Αυτή η λίστα αναπαραγωγής χρησιμοποιεί ήδη για γρήγορο σελιδοδείκτη.\n      This video cannot be moved down.: Αυτό το βίντεο δεν μπορεί να μετακινηθεί κάτω.\n      Playlist {playlistName} has been deleted.: Η λίστα αναπαραγωγής {playlistName} έχει διαγραφεί.\n      There was an issue with updating this playlist.: Υπήρχε ένα θέμα με την ενημέρωση της λίστας αναπαραγωγής.\n      Video has been removed. Click here to undo.: Το βίντεο έχει αφαιρεθεί. Κάντε κλικ εδώ για να αναιρέσετε.\n      This video cannot be moved up.: Αυτό το βίντεο δεν μπορεί να μετακινηθεί πάνω.\n      Video has been removed: Το βίντεο έχει αφαιρεθεί\n      There was a problem with removing this video: Υπήρχε ένα πρόβλημα με την αφαίρεση αυτού του βίντεο\n      This playlist is now used for quick bookmark: Αυτή η λίστα αναπαραγωγής χρησιμοποιείται τώρα με γρήγορο σελιδοδείκτη\n      Reverted to use {oldPlaylistName} for quick bookmark: Επαναφορά χρήσης {oldPlaylistName} για γρήγορο σελιδοδείκτη\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Μερικά βίντεο στη λίστα αναπαραγωγής δεν έχουν φορτωθεί ακόμα. Κάντε κλικ εδώ για να αντιγράψετε ούτως ή άλλως.\n      Playlist name cannot be empty. Please input a name.: Το όνομα λίστας αναπαραγωγής δεν μπορεί να είναι κενό. Παρακαλώ εισάγετε ένα όνομα.\n      Playlist has been updated.: Η λίστα αναπαραγωγής ενημερώθηκε.\n      \"{videoCount} video(s) have been removed\": 1 βίντεο έχει αφαιρεθεί | {videoCount} Τα βίντεο έχουν αφαιρεθεί\n      This playlist is protected and cannot be removed.: Αυτή η λίστα αναπαραγωγής προστατεύεται και δεν μπορεί να αφαιρεθεί.\n      This playlist has a video with a duration error: Αυτή η λίστα περιέχει τουλάχιστον ένα βίντεο το οποίο δεν έχει διάρκεια, θα ταξινομηθεί σαν η διάρκεια του να είναι μηδενική.\n    Search for Videos: Αναζήτηση για βίντεο\n  Playlists with Matching Videos: Λίστες αναπαραγωγής με βίντεο που ταιριάζουν\n  Sort By:\n    NameAscending: Α-Ζ\n    NameDescending: Ζ-Α\n    EarliestCreatedFirst: Δημιουργήθηκε Νωρίτερα\n    LatestCreatedFirst: Δημιουργήθηκε Πρόσφατα\n    LatestPlayedFirst: Πρόσφατα Παίχτηκε\n    EarliestUpdatedFirst: Ενημερώθηκε Νωρίτερα\n    EarliestPlayedFirst: Νωρίτερα Παίχτηκε\n    LatestUpdatedFirst: Πρόσφατα Ενημερώθηκε\n  Are you sure you want to delete this playlist? This cannot be undone: Σίγουρα θέλετε να διαγράψετε αυτή τη λίστα αναπαραγωγής; Αυτό δεν μπορεί να αναιρεθεί.\n  AddVideoPrompt:\n    Search in Playlists: Αναζήτηση σε λίστες αναπαραγωγής\n    Toast:\n      You haven't selected any playlist yet.: Δεν έχετε επιλέξει καμία λίστα αναπαραγωγής ακόμα.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Allow Adding Duplicate Video(s): Επίτρεψε την προσθήκη διπλών βίντεο( ών)\n    Added {count} Times: Προστέθηκε ήδη | Προστέθηκε {count} Φορές\n    Save: Αποθήκευση\n    Select a playlist to add your N videos to: Επιλέξτε μια λίστα αναπαραγωγής για να | Επιλέξτε μια λίστα για να προσθέσετε το {videoCount} βίντεο για\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Τα βίντεο έχουν ήδη προστεθεί'\n    N playlists selected: '{playlistCount}Επιλεγμένα'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Θα προστεθούν βίντεο'\n  Export Playlist: Εξαγωγή αυτής της λίστας αναπαραγωγής\n  The playlist has been successfully exported: Η λίστα αναπαραγωγής έχει εξαχθεί επιτυχώς\n  Delete Playlist: Διαγραφή λίστας αναπαραγωγής\n  Playlist Description: Περιγραφή λίστας αναπαραγωγής\n  Cancel: Ακύρωση\n  Move Video Down: Μετακίνηση βίντεο κάτω\n  Remove from Favorites: Αφαίρεση από {playlistName}\n  Add to Playlist: Προσθήκη στη λίστα αναπαραγωγής\n  Add to Favorites: Προσθήκη στην{playlistName}\n  Save Changes: Αποθήκευση αλλαγών\n  Cannot delete the quick bookmark target playlist.: Αδυναμία διαγραφής γρήγορης λίστας αναπαραγωγής σελιδοδεικτών.\n  Quick Bookmark Enabled: Γρηγορός σελιδοδείκτης ενεργός\n  Playlist Name: Όνομα λίστας αναπαραγωγής\n  Remove Watched Videos: Αφαίρεση Παρακολουθημένων Βίντεο\n  Move Video Up: Μετακίνηση βίντεο πάνω\n  Remove Duplicate Videos: Αφαίρεση διπλών βίντεο\n  Edit Playlist Info: Επεξεργασία πληροφοριών λίστας αναπαραγωγής\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Είστε σίγουροι ότι θέλετε να αφαιρέσετε 1 παρακολουθημένο βίντεο από αυτή τη λίστα αναπαραγωγής; Αυτό δεν μπορεί να αναιρεθεί. Είστε σίγουροι ότι θέλετε να αφαιρέσετε τα βίντεο από αυτή τη λίστα; Αυτό δεν μπορεί να αναιρεθεί.\n  Remove from Playlist: Αφαίρεση από τη λίστα αναπαραγωγής\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Είστε σίγουροι ότι θέλετε να αφαιρέσετε 1 διπλό βίντεο από αυτή τη λίστα αναπαραγωγής; Αυτό δεν μπορεί να αναιρεθεί. Είστε σίγουροι ότι θέλετε να αφαιρέσετε {playlistItemCount} διπλά βίντεο από αυτή τη λίστα; Αυτό δεν μπορεί να αναιρεθεί.\n  This playlist currently has no videos.: Αυτή η λίστα αναπαραγωγής προς το παρόν δεν έχει βίντεο.\n  Create New Playlist: Δημιουργία νέας λίστας αναπαραγωγής\n  TotalTimePlaylist: 'Συνολικός χρόνος: {duration}'\n  Enable Quick Bookmark With This Playlist: Ενεργοποίηση γρήγορου σελιδοδείκτη με αυτή τη λίστα αναπαραγωγής\n  You have no playlists. Click on the create new playlist button to create a new one.: Δεν έχεις λίστες αναπαραγωγής. Κάντε κλικ στο κουμπί Δημιουργία νέας λίστας αναπαραγωγής για να δημιουργήσετε μία νέα.\n  Copy Playlist: Αντιγραφή λίστας αναπαραγωγής\n  CreatePlaylistPrompt:\n    New Playlist Name: Νέο όνομα λίστας αναπαραγωγής\n    Toast:\n      Playlist {playlistName} has been successfully created.: Η λίστα αναπαραγωγής {playlistName} δημιουργήθηκε με επιτυχία.\n      There is already a playlist with this name. Please pick a different name.: Υπάρχει ήδη μια λίστα με αυτό το όνομα. Παρακαλώ επιλέξτε ένα διαφορετικό όνομα.\n      There was an issue with creating the playlist.: Υπήρχε ένα πρόβλημα με τη δημιουργία της λίστας αναπαραγωγής.\n    Create: Δημιουργία\nHistory:\n  # On History Page\n  History: 'Ιστορικό'\n  Watch History: 'Προβολή Ιστορικού'\n  Your history list is currently empty.: 'Η λίστα του ιστορικού σας είναι προς το παρόν κενή.'\n  Search bar placeholder: Αναζήτηση στο Ιστορικό\n  Empty Search Message: Δεν υπάρχουν βίντεο στο ιστορικό σας που να ταιριάζουν με την αναζήτησή σας\n  Case Sensitive Search: Ευαίσθητη αναζήτηση περίπτωσης\nSettings:\n  # On Settings Page\n  Settings: 'Ρυθμίσεις'\n  General Settings:\n    General Settings: 'Γενικά'\n    Fallback to Non-Preferred Backend on Failure: 'Εναλλαγή σε μη προτιμώμενο σύστημα υποστήριξης σε περίπτωση αποτυχίας'\n    Enable Search Suggestions: 'Ενεργοποίηση προτάσεων αναζήτησης'\n    Default Landing Page: 'Προεπιλεγμένη σελίδα προορισμού'\n    Locale Preference: 'Προτιμήσεις γλώσσας'\n    Preferred API Backend:\n      Preferred API Backend: 'Προτιμώμενο σύστημα (API)'\n      Local API: 'Τοπική διεπαφή προγραμματισμού εφαρμογών (API)'\n      Invidious API: 'Διεπαφή προγραμματισμού εφαρμογής Invidious (*API)'\n    Video View Type:\n      Video View Type: 'Τύπος προβολής βίντεο'\n      Grid: 'Πλέγμα'\n      List: 'Λίστα'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Προτίμηση μικρογραφιών'\n      Default: 'Προεπιλογή'\n      Beginning: 'Αρχή'\n      Middle: 'Μέση'\n      End: 'Τέλος'\n      Hidden: Κρυμμένο\n      Blur: 'Θάμπωμα'\n    Region for Trending: 'Περιοχή που καθορίζει την καρτέλα των τάσεων'\n        #! List countries\n    Check for Latest Blog Posts: Ελέγξτε για τις τελευταίες δημοσιεύσεις ιστολογίου (Blogposts)\n    Check for Updates: Έλεγχος για ενημερώσεις\n    View all Invidious instance information: Δείτε όλες τις πληροφορίες προσβλητικών περιπτώσεων\n    System Default: Προεπιλογή συστήματος\n    Current Invidious Instance: Τρέχων στιγμιότυπο Invidious\n    The currently set default instance is {instance}: 'Το τρέχον προεπιλεγμένο στιγμιότυπο είναι {instance}'\n    No default instance has been set: Δεν έχει οριστεί κανένα προεπιλεγμένο στιγμιότυπο\n    External Link Handling:\n      External Link Handling: Χειρισμός εξωτερικών συνδέσμων\n      Open Link: Άνοιγμα συνδέσμου\n      Ask Before Opening Link: Ερώτηση πριν από το άνοιγμα του συνδέσμου\n      No Action: Καμία ενέργεια\n    Current instance will be randomized on startup: Η τρέχων διακομιστής θα τυχαιοποιηθεί κατά την εκκίνηση\n    Set Current Instance as Default: Ορίστε τον τρέχων διακομιστή ως προεπιλεγμένο\n    Clear Default Instance: Εκκαθάριση Προεπιλεγμένου διακομιστή\n    Auto Load Next Page:\n      Label: Αυτόματη φόρτωση επόμενης σελίδας\n      Tooltip: Φόρτωση πρόσθετων σελίδων και σχολίων αυτόματα.\n    Open Deep Links In New Window: Άνοιγμα URL που πέρασαν στο FreeTube σε ένα νέο παράθυρο\n  Theme Settings:\n    Theme Settings: 'Θέματα'\n    Match Top Bar with Main Color: 'Αντιστοίχηση Κύριου Χρώματος με την Μπάρα Κορυφής'\n    Base Theme:\n      Base Theme: 'Βασικό Θέμα'\n      Black: 'Μαύρο'\n      Dark: 'Σκοτεινό'\n      Light: 'Φωτεινό'\n      Dracula: 'Δράκουλας'\n      System Default: Προεπιλογή Συστήματος\n      Catppuccin Mocha: Κατπουτσίνο Μόκα\n      Pastel Pink: Παστέλ Ρόζ\n      Hot Pink: Ζεστό Ρόζ\n      Gruvbox Dark: Gruvbox Σκοτεινό\n      Gruvbox Light: Gruvbox Φωτεινό\n      Solarized Light: Ηλιακό φως\n      Catppuccin Frappe: Κατπουτσίν Φραππέ\n      Nordic: Νορδικό\n      Solarized Dark: Ηλιακό σκοτάδι\n      Everforest Dark Hard: Everforest Σκοτεινό σκληρό\n      Everforest Dark Medium: Everforest Σκοτεινό μεσαίο\n      Everforest Dark Low: Everforest Σκοτεινό Χαμηλό\n      Everforest Light Hard: Everforest φως σκληρό\n      Everforest Light Medium: Everforest φως Μεσαίο\n      Everforest Light Low: Everforest φως Χαμηλό\n    Main Color Theme:\n      Main Color Theme: 'Κύριο Χρώμα Θέματος'\n      Red: 'Κόκκινο'\n      Pink: 'Ροζ'\n      Purple: 'Μωβ'\n      Deep Purple: 'Βαθύ/Σκούρο Μωβ'\n      Indigo: 'Μωβ-μπλε (Indigo)'\n      Blue: 'Μπλε'\n      Light Blue: 'Γαλάζιο'\n      Cyan: 'Κυανό'\n      Teal: 'Βαθύ Κυανό'\n      Green: 'Πράσινο'\n      Light Green: 'Ανοιχτό Πράσινο'\n      Lime: 'Λαχανί'\n      Yellow: 'Κίτρινο'\n      Amber: 'Χρυσοκίτρινο'\n      Orange: 'Πορτοκαλί'\n      Deep Orange: 'Βαθύ Πορτοκαλί'\n      Dracula Cyan: 'Δράκουλας Κυανό'\n      Dracula Green: 'Δράκουλας Πράσινο'\n      Dracula Orange: 'Δράκουλας Πορτοκαλί'\n      Dracula Pink: 'Δράκουλας Ροζ'\n      Dracula Purple: 'Δράκουλας Μωβ'\n      Dracula Red: 'Δράκουλας Κόκκινο'\n      Dracula Yellow: 'Δράκουλας Κίτρινο'\n      Catppuccin Mocha Teal: Κατπουτσίν Μόκα Teal\n      Catppuccin Mocha Green: Κατπουτσίν Μόκα Πράσινο\n      Catppuccin Mocha Sky: Κατπουτσίν Μόκα του Ουρανού\n      Catppuccin Mocha Blue: Κατπουτσίν Μόκα μπλε\n      Catppuccin Mocha Sapphire: Κατπουτσίν Μόκα του Ζαφειριού\n      Catppuccin Mocha Lavender: Κατπουτσίν Μόκα Λεβάντα\n      Catppuccin Mocha Rosewater: Κατπουτσίνο Μόκα Ροδόνερο\n      Catppuccin Mocha Flamingo: Κατπουτσίνο Μόκα Φλαμίνγκο\n      Catppuccin Mocha Pink: Κατπουτσίνο Μόκα Ροζ\n      Catppuccin Mocha Mauve: Κατπουτσίν Μόκα Μωβ\n      Catppuccin Mocha Red: Κατπουτσίν Μόκα Κόκκινο\n      Catppuccin Mocha Maroon: Κατπουτσίν Μόκα Μαρούν\n      Catppuccin Mocha Peach: Κατπουτσίν Μόκα Ροδάκινο\n      Catppuccin Mocha Yellow: Κατπουτσίν Μόκα Κίτρινο\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Ροδόνερο\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Φλαμίνγκο\n      Catppuccin Frappe Pink: Catppuccin Frappe Ροζ\n      Catppuccin Frappe Lavender: Catppuccin Frappe Λεβάντα\n      Gruvbox Light Purple: Gruvbox Ανοιχτό Μοβ\n      Gruvbox Dark Green: Gruvbox Σκούρο Πράσινο\n      Catppuccin Frappe Peach: Catppuccin Frappe Ροδάκινο\n      Catppuccin Frappe Blue: Catppuccin Frappe Μπλε\n      Catppuccin Frappe Red: Catppuccin Frappe Κόκκινο\n      Catppuccin Frappe Maroon: Catppuccin Frappe καφέ\n      Catppuccin Frappe Yellow: Catppuccin Frappe Κίτρινο\n      Catppuccin Frappe Teal: Catppuccin Frappe Γαλαζοπράσινο\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Ζαφείρι\n      Gruvbox Dark Yellow: Gruvbox Σκούρο Κίτρινο\n      Gruvbox Dark Blue: Gruvbox Σκούρο Μπλε\n      Gruvbox Dark Purple: Gruvbox Σκούρο Μοβ\n      Gruvbox Dark Aqua: Gruvbox Σκούρο Aqua\n      Gruvbox Dark Orange: Gruvbox Σκούρο Πορτοκαλί\n      Gruvbox Light Red: Gruvbox Ανοιχτό Κόκκινο\n      Gruvbox Light Blue: Gruvbox Ανοιχτό Μπλε\n      Gruvbox Light Orange: Gruvbox Ανοιχτό Πορτοκαλί\n      Catppuccin Frappe Green: Catppuccin Frappe Πράσινο\n      Catppuccin Frappe Sky: Catppuccin Frappe Ουρανός\n      Catppuccin Frappe Mauve: Catppuccin Frappe Μωβ\n      Solarized Green: Ηλιακό Πράσινο\n      Solarized Yellow: Ηλιακό Κίτρινο\n      Solarized Orange: Ηλιακό Πορτοκαλί\n      Solarized Cyan: Ηλιακό Κυανό\n      Solarized Red: Ηλιακό Κόκκινο\n      Solarized Magenta: Ηλιακό Μωβ\n      Solarized Blue: Ηλιακό Μπλε\n      Everforest Dark Yellow: Everforest Σκούρο Κίτρινο\n      Everforest Dark Green: Everforest Σκούρο Πράσινο\n      Everforest Dark Aqua: Everforest Σκούρο Ακουα\n      Everforest Dark Blue: Everforest Σκούρο Μπλε\n      Solarized Violet: Ηλιακό Βιολετί\n      Everforest Dark Red: Everforest Σκούρο Κόκκινο\n      Everforest Dark Orange: Everforest Σκούρο Πορτοκαλί\n      Everforest Dark Purple: Everforest Σκούρο Μωβ\n      Everforest Light Red: Everforest Ανοιχτό Κόκκινο\n      Everforest Light Orange: Everforest Ανοιχτό Πορτοκαλί\n      Everforest Light Yellow: Everforest Ανοιχτό Κίτρινο\n      Everforest Light Green: Everforest Ανοιχτό Πράσινο\n      Everforest Light Aqua: Everforest Ανοιχτό Γαλαζοπράσινο\n      Everforest Light Blue: Everforest Ανοιχτό Μπλε\n      Everforest Light Purple: Everforest Ανοιχτό Μωβ\n    Secondary Color Theme: 'Δευτερεύων Χρώμα Θέματος'\n        #* Main Color Theme\n    UI Scale: Μέγεθος κλίμακας διεπαφής χρήστη\n    Expand Side Bar by Default: Λειτουργία προεπιλογής πλάγιας Μπάρας\n    Disable Smooth Scrolling: Απενεργοποίηση ομαλής κύλισης\n    Hide Side Bar Labels: Απόκρυψη ετικετών πλευρικής γραμμής\n    Hide FreeTube Header Logo: Απόκρυψη Λογότυπου Κεφαλίδας FreeTube\n  Player Settings:\n    Player Settings: 'Πρόγραμμα αναπαραγωγής'\n    Play Next Video: 'Αναπαραγωγή Προτεινόμενου Βίντεο'\n    Turn on Subtitles by Default: 'Ενεργοποίηση υπότιτλων από προεπιλογή'\n    Autoplay Videos: 'Εκκίνηση Αυτόματης αναπαραγωγής βίντεο'\n    Proxy Videos Through Invidious: 'Βίντεο μέσω του διακομιστή μεσολάβησης Invidious'\n    Autoplay Playlists: 'Αυτόματη αναπαραγωγή Βίντεο λίστας αναπαραγωγής'\n    Enable Theatre Mode by Default: 'Ενεργοποίηση λειτουργίας κινηματογράφου από προεπιλογή'\n    Default Volume: 'Προεπιλεγμένο επίπεδο έντασης'\n    Default Playback Rate: 'Προεπιλεγμένη ταχύτητα αναπαραγωγής'\n    Default Video Format:\n      Default Video Format: 'Προεπιλεγμένη μορφή βίντεο'\n      Dash Formats: 'Dash Μορφή'\n      Legacy Formats: 'Παλαιότερες Μορφές Αναπαρωγής'\n      Audio Formats: 'Μορφές Ήχου'\n    Default Quality:\n      Default Quality: 'Προεπιλεγμένη ποιότητα ήχου'\n      Auto: 'Αυτόματα'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Αντίστροφη μέτρηση αυτόματης αναπαραγωγής\n    Scroll Volume Over Video Player: Αυξομείωση έντασης ήχου με κύλιση πάνω στο πρόγραμμα αναπαραγωγής βίντεο\n    Display Play Button In Video Player: Εμφάνιση του κουμπιού αναπαραγωγής στο πρόγραμμα αναπαραγωγής βίντεο\n    Scroll Playback Rate Over Video Player: Ποσοστό Αναπαραγωγής Κύλισης Πάνω Από Το Πρόγραμμα Αναπαραγωγής Βίντεο\n    Fast-Forward / Rewind Interval: Διάστημα Γρήγορης προώθησης / Επανατύλιξης\n    Max Video Playback Rate: Μέγιστος ρυθμός αναπαραγωγής βίντεο\n    Video Playback Rate Interval: Διάστημα ρυθμού αναπαραγωγής βίντεο\n    Screenshot:\n      Error:\n        Forbidden Characters: Απαγορευμένοι Χαρακτήρες\n        Empty File Name: Κενό Όνομα Αρχείου\n      Enable: Ενεργοποίηση Στιγμιότυπου οθόνης\n      Quality Label: Ποιότητα Στιγμιότυπου Οθόνης\n      Ask Path: Ερώτηση για Αποθήκευση Φακέλου\n      Folder Button: Επιλέξτε φάκελο\n      Folder Label: Φάκελος Στιγμιότυπου Οθόνης\n      File Name Label: Μοτίβο ονόματος αρχείου\n      File Name Tooltip: Μπορείτε να χρησιμοποιήσετε μεταβλητές παρακάτω. %Y Έτος 4 ψηφία. %M Μήνας 2 ψηφία. %D ψηφία ημέρας 2. %H Ώρα 2 ψηφία. %N Λεπτά 2 ψηφία. %S Δεύτερα 2 ψηφία. %T χιλιοστού του δευτερολέπτου 3 ψηφία. %s Βίντεο δεύτερο. %t Βίντεο χιλιοστού του δευτερολέπτου 3 ψηφία. %i Αναγνωριστικό Βίντεο.\n      Format Label: Μορφή Στιγμιότυπου Οθόνης\n    Skip by Scrolling Over Video Player: Παράλειψη με Κύλιση στο Πρόγραμμα Αναπαραγωγής Βίντεο\n    Enter Fullscreen on Display Rotate: Μετάβαση στην Πλήρη Οθόνη κατά την Περιστροφή Οθόνης\n    Default Viewing Mode:\n      Full Screen: Πλήρης Οθόνη\n      Picture in Picture: Εικόνα σε εικόνα\n      Theater: Θέατρο\n      Default Viewing Mode: Προεπιλεγμένη λειτουργία προβολής\n      External Player: Εξωτερικός αναπαραγωγέας ({externalPlayerName})\n    Autoplay Interruption Timer: Χρονοδιακόπτης διακοπής αυτόματης αναπαραγωγής\n  Privacy Settings:\n    Privacy Settings: 'Ιδιωτικότητα'\n    Remember History: 'Διατήρηση Ιστορικού Παρακολούθησης'\n    Save Watched Progress: 'Αποθήκευση προόδου βίντεο'\n    Clear Search Cache: 'Εκκαθάριση της προσωρινής μνήμης αναζήτησης'\n    Are you sure you want to clear out your search cache?: 'Είστε βέβαιοι ότι θέλετε να εκκαθαρίσετε την προσωρινή μνήμη αναζήτησης;'\n    Search cache has been cleared: 'Η προσωρινή μνήμη αναζήτησης είναι πλέον κενή'\n    Remove Watch History: 'Διαγραφή ιστορικού παρακολούθησης'\n    Are you sure you want to remove your entire watch history?: 'Είστε βέβαιοι ότι θέλετε να διαγράψετε όλο το ιστορικό σας;'\n    Watch history has been cleared: 'Το ιστορικό παρακολούθησης είναι πλέον κενό'\n    Remove All Subscriptions / Profiles: 'Διαγράψτε όλες τις συνδρομές/Προφίλ'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Είστε βέβαιοι ότι θέλετε να καταργήσετε όλες τις συνδρομές και τα προφίλ; Αυτό δεν μπορεί να αναιρεθεί.'\n    Save Watched Videos With Last Viewed Playlist: Αποθήκευση Βίντεο που Παρακολουθήσατε Με τη Λίστα Αναπαραγωγής Τελευταίας Προβολής\n    Are you sure you want to remove all your playlists?: Είστε σίγουροι ότι θέλετε να αφαιρέσετε όλες τις λίστες αναπαραγωγής σας;\n    Remove All Playlists: Κατάργηση όλων των λιστών αναπαραγωγής\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Αυτόματο\n        Never: Ποτέ\n        Semi-auto: Ημι-αυτόματο\n      Tooltip: Αυτόματη = Αποθήκευση σε κάθε έξοδο από τη σελίδα βίντεο, όταν το βίντεο τελειώνει και παρουσιαστεί σφάλμα (π.χ. λήξη ratelimited και λήξη περιόδου παρακολούθησης). Ημιαυτόματο = Όπως το Αυτόματο, εκτός από την έξοδο από τη σελίδα βίντεο και δυνατότητα αποθήκευσης της προόδου με μη αυτόματο τρόπο μέσω ενός κουμπιού που ονομάζεται Αποθήκευση προόδου παρακολούθησης, το οποίο βρίσκεται κάτω από το πρόγραμμα αναπαραγωγής βίντεο.\n    All playlists have been removed: Όλες οι λίστες αναπαραγωγής έχουν αφαιρεθεί\n    Clear Search History and Cache: Εκκαθάριση ιστορικού αναζήτησης και μνήμης\n    Are you sure you want to clear out your search history and cache?: Είστε σίγουροι ότι θέλετε να διαγράψετε το ιστορικό αναζήτησης και την προσωρινή μνήμη cache;\n    Search history and cache have been cleared: Το ιστορικό αναζήτησης και η προσωρινή μνήμη έχουν εκκαθαριστεί\n    Remember Search History: Διατήρηση Ιστορικού Αναζήτησης\n  Subscription Settings:\n    Subscription Settings: 'Συνδρομές'\n    Fetch Feeds from RSS: 'Φόρτωση τροφοδοσίας RSS'\n    Fetch Automatically: Αυτόματη Λήψη Τροφοδοσίας\n    'Limit the number of videos displayed for each channel': Περιορίστε τον αριθμό των βίντεο που εμφανίζονται για κάθε κανάλι\n    Confirm Before Unsubscribing: Επιβεβαίωση πριν από τη Απεγραφή\n    To: Προς\n  Data Settings:\n    Data Settings: 'Δεδομένα'\n    Select Export Type: 'Επιλογή Τρόπου Εξαγωγής'\n    Import Subscriptions: 'Εισαγωγή Συνδρομών'\n    Export Subscriptions: 'Εξαγωγή Συνδρομών'\n    Export FreeTube: 'Εξαγωγή για FreeTube'\n    Export YouTube: 'Εξαγωγή για Youtube'\n    Export NewPipe: 'Εξαγωγή για NewPipe'\n    Import History: 'Εισαγωγή Ιστορικού'\n    Export History: 'Εξαγωγή Ιστορικού'\n    Profile object has insufficient data, skipping item: 'Ένα αντικείμενο προφίλ έχει λανθασμένα δεδομένα, παράληψη του εξής αντικειμένου'\n    All subscriptions and profiles have been successfully imported: 'Η εισαγωγή όλων των συνδρομών και των προφίλ έχει γίνει με επιτυχία'\n    All subscriptions have been successfully imported: 'Η εισαγωγή των συνδρομών έχει γίνει με επιτυχία'\n    Invalid subscriptions file: 'Μη συμβατό/έγκυρο αρχείο συνδρομών'\n    Invalid history file: 'Μη συμβατό/έγκυρο αρχείο Ιστορικού'\n    Subscriptions have been successfully exported: 'Η εξαγωγή των συνδρομών έχει γίνει με επιτυχία'\n    History object has insufficient data, skipping item: 'Ένα αντικείμενο ιστορικού έχει εσφαλμένα δεδομένα, παράληψη του εξής στοιχείου'\n    All watched history has been successfully imported: 'Το ιστορικό σας έχει εισαχθεί με επιτυχία'\n    All watched history has been successfully exported: 'Το ιστορικό σας έχει εξαχθεί με επιτυχία'\n    Unable to read file: 'Αδύνατη η προσπέλαση του αρχείου'\n    Unable to write file: 'Αδύνατη εγγραφή του αρχείου'\n    Unknown data key: 'Άγνωστο κλειδί δεδομένων'\n    How do I import my subscriptions?: 'Πως γίνεται η εισαγωγή των συνδρομών μου;'\n    Manage Subscriptions: Διαχείριση συνδρομών\n    Import Playlists: Εισαγωγή λιστών αναπαραγωγής\n    Export Playlists: Εξαγωγή Λιστών Αναπαραγωγής\n    Playlist insufficient data: Ανεπαρκή δεδομένα για τη λίστα αναπαραγωγής \"{playlist}\", γίνεται παράκαμψη του αντικειμένου\n    All playlists has been successfully imported: Όλες οι λίστες αναπαραγωγής έχουν εισαχθεί με επιτυχία\n    All playlists has been successfully exported: Όλες οι λίστες αναπαραγωγής έχουν εξαχθεί με επιτυχία\n    Subscription File: Αρχείο Συνδρομής\n    History File: Αρχείο Ιστορικού\n    Playlist File: Αρχείο Λίστας Αναπαραγωγής\n\n    Export Playlists For Older FreeTube Versions:\n      Label: Εξαγωγή λιστών αναπαραγωγής για παλαιότερες εκδόσεις FreeTube\n      Tooltip: \"Αυτή η επιλογή εξάγει βίντεο από όλες τις λίστες αναπαραγωγής σε μία λίστα αναπαραγωγής με το όνομα “Αγαπημένα”.\\nΠώς να εξάγετε & να εισάγετε βίντεο σε λίστες αναπαραγωγής για μια παλαιότερη έκδοση του FreeTube:\\n1. Εξάγετε τις λίστες αναπαραγωγής σας με ενεργοποιημένη αυτή την επιλογή.\\n 2. Διαγράψτε όλες τις υπάρχουσες λίστες αναπαραγωγής σας χρησιμοποιώντας την επιλογή Κατάργηση όλων των λιστών αναπαραγωγής στις Ρυθμίσεις απορρήτου.\\n 3. Εκκινήστε την παλαιότερη έκδοση του FreeTube και εισαγάγετε τις εξαχθείσες λίστες αναπαραγωγής.\\\"\"\n  Distraction Free Settings:\n    Distraction Free Settings: Χωρίς απόσπαση\n    Hide Live Chat: Απόκρυψη Ζωντανής συνομιλίας\n    Hide Popular Videos: Απόκρυψη δημοφιλών βίντεο\n    Hide Trending Videos: Απόκρυψη των βίντεο Τάσεις\n    Hide Recommended Videos: Απόκρυψη προτεινόμενων Βίντεο\n    Hide Comment Likes: Απόκρυψη των \"μου αρέσει\" από τα σχόλια\n    Hide Video Likes And Dislikes: Απόκρυψη μπάρας \"μου αρέσει/δεν μου αρέσει\"\n    Hide Channel Subscribers: Απόκρυψη συνδρομών καναλιού\n    Hide Video Views: Απόκρυψη προβολών βίντεο\n    Hide Active Subscriptions: Απόκρυψη ενεργών συνδρομών\n    Hide Playlists: Απόκρυψη λιστών αναπαραγωγής\n    Hide Live Streams: Απόκρυψη Ζωντανών Ροών\n    Hide Sharing Actions: Απόκρυψη Ενεργειών Κοινής Χρήσης\n    Hide Videos on Watch: 'Απόκρυψη των βίντεο κατά την αναπαραγωγή'\n    Hide Channels: Απόκρυψη Βίντεο Από Κανάλια\n    Hide Upcoming Premieres: Απόκρυψη Επερχόμενων Πρεμιέρων\n    Hide Channels Placeholder: Αναγνωριστικό καναλιού\n    Hide Comments: Απόκρυψη Σχολίων\n    Hide Chapters: Απόκρυψη Κεφαλαίων\n    Hide Video Description: Απόκρυψη Περιγραφής Βίντεο\n    Display Titles Without Excessive Capitalisation: Εμφάνιση τίτλων χωρίς υπερβολική κεφαλαιοποίηση και στίξη\n    Sections:\n      Side Bar: Πλαϊνή Μπάρα\n      Channel Page: Σελίδα Καναλιού\n      Watch Page: Σελίδα Παρακολούθησης\n      General: Γενικά\n      Subscriptions Page: Σελίδα Συνδρομών\n    Hide Featured Channels: Απόκρυψη Προτεινόμενων Καναλιών\n    Hide Channel Playlists: Απόκρυψη καναλιών \" λίστες αναπαραγωγής\" καρτέλα\n    Hide Channel Shorts: Απόκρυψη καναλιού \" Σύντομες\" καρτέλα\n    Hide Channel Releases: Απόκρυψη καναλιού \" Kυκλοφοριών\" καρτέλα\n    Hide Channel Podcasts: Απόκρυψη καναλιού \" Πόντκαστ\" καρτέλα\n    Hide Subscriptions Videos: Απόκρυψη Βίντεο Συνδρομών\n    Hide Subscriptions Shorts: Απόκρυψη Shorts Συνδρομών\n    Hide Subscriptions Live: Απόκρυψη Live Συνδρομών\n    Hide Profile Pictures in Comments: Απόκρυψη Εικόνων Προφίλ στα Σχόλια\n    Hide Channels Invalid: Το αναγνωριστικό καναλιού που δόθηκε δεν ήταν έγκυρο\n    Hide Channels Disabled Message: Ορισμένα κανάλια αποκλείστηκαν με χρήση αναγνωριστικού και δεν υποβλήθηκαν σε επεξεργασία. Η λειτουργία μπλοκάρεται κατά την ενημέρωση αυτών των αναγνωριστικών\n    Hide Channels Already Exists: Το αναγνωριστικό καναλιού υπάρχει ήδη\n    Hide Channels API Error: Σφάλμα κατά την ανάκτηση χρήστη με το παρεχόμενο αναγνωριστικό. Ελέγξτε ξανά εάν το αναγνωριστικό είναι σωστό.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Λέξη, τμήμα λέξης ή φράση\n    Hide Videos, Playlists and Channels Containing Text: Απόκρυψη βίντεο και λιστών αναπαραγωγής που περιέχουν κείμενο\n    Hide Channel Courses: Απόκρυψη της καρτέλας «Μαθήματα» του καναλιού\n    Hide Channel Home: Απόκρυψη της καρτέλας «Αρχική σελίδα» του καναλιού\n    Show Added Items: Εμφάνιση προστιθέμενων στοιχείων\n    Hide Subscriptions Posts: Απόκρυψη αναρτήσεων συνδρομών\n    Hide Channel Posts: Απόκρυψη καρτέλας \"Αναρτήσεις\" καναλιού\n  The app needs to restart for changes to take effect. Restart and apply change?: Η εφαρμογή πρέπει να κάνει επανεκκίνηση για να εφαρμοστούν οι αλλαγές. Επανεκκίνηση και εφαρμογή αλλαγών;\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Σφάλμα κατά τη λήψη πληροφοριών δικτύου. Ο διακομιστής μεσολάβησης έχει ρυθμιστεί σωστά;\n    City: Πόλη\n    Region: Περιοχή\n    Country: Χώρα\n    Ip: Πρωτόκολλο Διαδικτύου (Ip)\n    Your Info: Τα στοιχεία σας\n    Test Proxy: Έλεγχος Διακομιστή Μεσολάβησης\n    Clicking on Test Proxy will send a request to: Κάνοντας κλικ στο Έλεγχος Διακομιστή Μεσολάβησης θα στείλετε ένα αίτημα στο\n    Proxy Port Number: Αριθμός θύρας διακομιστή μεσολάβησης\n    Proxy Host: Κεντρικός υπολογιστής μεσολάβησης\n    Proxy Protocol: Πρωτόκολλο μεσολάβησης\n    Enable Tor / Proxy: Ενεργοποίηση Tor / Proxy\n    Proxy Settings: Διακομιστής μεσολάβησης\n    Proxy Warning: Το FreeTube δεν διαθέτει ενσωματωμένο διακομιστή μεσολάβησης, αλλά μπορεί να συνδεθεί σε έναν εξωτερικό διακομιστή μεσολάβησης, όπως έναν που εκτελείται στο μηχάνημά σας, όπως το Tor, ή έναν εξωτερικό διακομιστή μεσολάβησης, όπως ένας διακομιστής μεσολάβησης SOCKS5 που παρέχεται από ορισμένα VPN. Εάν είναι ενεργοποιημένο, βεβαιωθείτε ότι ο διακομιστής μεσολάβησης/το Tor έχει ρυθμιστεί σωστά, αλλιώς το FreeTube δεν θα μπορεί να αντλήσει δεδομένα.\n  External Player Settings:\n    External Player Settings: Εξωτερικό πρόγραμμα αναπαραγωγής\n    External Player: Εξωτερικό πρόγραμμα αναπαραγωγής\n    Ignore Unsupported Action Warnings: Παράβλεψη προειδοποιήσεων μη υποστηριζόμενων ενεργειών\n    Custom External Player Executable: Εκτελέσιμο εξωτερικού προγράμματος αναπαραγωγής\n    Custom External Player Arguments: Προσαρμοσμένα ορίσματα εξωτερικού προγράμματος αναπαραγωγής\n    Players:\n      None:\n        Name: Κανένα\n    Ignore Default Arguments: Αγνοήστε τα προεπιλεγμένα επιχειρήματα\n  SponsorBlock Settings:\n    Enable SponsorBlock: Ενεργοποίηση του SponsorBlock\n    Notify when sponsor segment is skipped: Ειδοποίηση όταν παραλείπεται το τμήμα χορηγού\n    SponsorBlock Settings: 'SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Διεύθυνση URL του API του SponsorBlock (Η προεπιλογή είναι https://sponsor.ajay.app)\n    Skip Options:\n      Skip Option: Επιλογή Παράλειψης\n      Do Nothing: Να Μην Γίνει Τίποτα\n      Auto Skip: Αυτόματη Παράλειψη\n      Show In Seek Bar: Εμφάνιση Στη Γραμμή Αναζήτησης\n      Prompt To Skip: Προτροπή Για Παράλειψη\n    Category Color: Χρώμα Κατηγορίας\n    UseDeArrowTitles: Χρήση Τίτλων Βίντεο DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Μικρογραφία Generator API Url (Η προεπιλογή είναι https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Χρήση DeArrow για μικρογραφίες\n  Password Dialog:\n    Enter Password To Unlock: Εισαγάγετε τον κωδικό πρόσβασης για να ξεκλειδώσετε τις ρυθμίσεις\n    Password: Κωδικός πρόσβασης\n  Password Settings:\n    Password Settings: Κωδικού πρόσβασης\n    Set Password: Ορίστε Κωδικό πρόσβασης\n    Set Password To Prevent Access: Ορίστε έναν κωδικό πρόσβασης για να αποτρέψετε την πρόσβαση στις ρυθμίσεις\n    Remove Password: Κατάργηση Κωδικού πρόσβασης\n  Experimental Settings:\n    Replace HTTP Cache: Αντικατάσταση HTTP Cache\n    Warning: Αυτές οι ρυθμίσεις είναι πειραματικές, ενδέχεται να προκαλέσουν σφάλματα όταν είναι ενεργοποιημένες. Συνιστάται ιδιαίτερα η δημιουργία αντιγράφων ασφαλείας. Χρησιμοποιήστε το με δική σας ευθύνη!\n    Experimental Settings: Πειραματικές Ρυθμίσεις\n  Parental Control Settings:\n    Parental Control Settings: Γονικός Έλεγχος\n    Show Family Friendly Only: Εμφάνιση Μόνο Για Οικογένειες\n    Hide Unsubscribe Button: Απόκρυψη Κουμπιού Απεγγραφής\n    Hide Search Bar: Απόκρυψη Μπάρας Αναζήτησης\n  Return to Settings Menu: Επιστροφή στο μενού ρυθμίσεων\n  Sort Settings Sections (A-Z): Ταξινόμηση τμημάτων ρυθμίσεων (A-Z)\nAbout:\n  #On About page\n  About: 'Σχετικά με'\n  #& About\n  Donate: Δωρεά\n  these people and projects: αυτούς τους ανθρώπους και τα έργα\n  Credits: Μνείες\n  Translate: Μεταφράστε\n  room rules: κανόνες δωματίου\n  Chat on Matrix: Συνομιλία στο Matrix\n  Mastodon: Μάστοντον\n  Email: Ηλεκτρονικό ταχυδρομείο\n  Blog: Ιστολόγιο\n  Website: Ιστότοπος\n  Please check for duplicates before posting: Παρακαλώ ελέγξτε για διπλότυπα πριν δημοσιεύσετε\n  GitHub issues: Προβλήματα GitHub\n  Report a problem: Αναφορά προβλήματος\n  FAQ: Συχνές ερωτήσεις\n  FreeTube Wiki: FreeTube βίκι\n  Help: Βοήθεια\n  GitHub releases: Κυκλοφορίες GitHub\n  Downloads / Changelog: Λήψεις / Αρχείο καταγραφής αλλαγών\n  Source code: Πηγαίος κώδικας\n  Beta: Βήτα\n  Discussions: Συζητήσεις\n  AGPLv3: 'AGPLv3'\nProfile:\n  Profile Select: 'Επιλογή Προφίλ'\n  All Channels: 'Όλα τα κανάλια'\n  Profile Manager: 'Διαχειριστής Προφίλ'\n  Create New Profile: 'Δημιουργία νέου Προφίλ'\n  Edit Profile: 'Επεξεργασία προφίλ'\n  Color Picker: 'Επιλογέας χρώματος'\n  Custom Color: 'Προσαρμοσμένο Χρώμα'\n  Profile Preview: 'Προεπισκόπηση προφίλ'\n  Create Profile: 'Δημιουργία Προφίλ'\n  Update Profile: 'Ενημέρωση προφίλ'\n  Make Default Profile: 'Επιλογή προεπιλεγμένου προφίλ'\n  Delete Profile: 'Διαγραφή προφίλ'\n  Are you sure you want to delete this profile?: 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το προφίλ;'\n  All subscriptions will also be deleted.: 'Επίσης θα διαγραφούν και όλες οι συνδρομές.'\n  Your profile name cannot be empty: 'Το όνομα του προφίλ σας δεν μπορεί να είναι άδειο'\n  Profile has been created: 'Το προφίλ σας έχει δημιουργηθεί'\n  Profile has been updated: 'Το προφίλ σας έχει ενημερωθεί'\n  Your default profile has been set to {profile}: 'Το {profile} έχει οριστεί ως το προεπιλεγμένο σας προφίλ'\n  Removed {profile} from your profiles: 'Το {profile} έχει αφαιρεθεί από τα προφίλ σας'\n  Your default profile has been changed to your primary profile: 'Το κύριο προφίλ σας έχει οριστεί ως το προεπιλεγμένο'\n  '{profile} is now the active profile': 'Το {profile} είναι τώρα το ενεργό προφίλ'\n  Subscription List: 'Λίστα Συνδρομών/Εγγραφών'\n  Other Channels: 'Άλλα κανάλια'\n  '{number} selected': '{number} επιλεγμένο'\n  Select All: 'Επιλογή όλων'\n  Select None: 'Επιλογή κανενός'\n  Delete Selected: 'Διαγραφή επιλεγμένου στοιχείου'\n  Add Selected To Profile: 'Προσθήκη επιλεγμένου στοιχείου στο προφίλ'\n  No channel(s) have been selected: 'Δεν έχει γίνει επιλογή κάποιου καναλιού'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Αυτό είναι το κύριο προφίλ σας. Είστε βέβαιοι ότι θέλετε να διαγράψετε τα επιλεγμένα κανάλια; Αυτά τα κανάλια θα διαγραφούν και από τα υπόλοιπα προφίλ σας.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Είστε βέβαιοι ότι θέλετε να διαγράψετε τα επιλεγμένα κανάλια;  Αυτό δε θα διαγράψει το κανάλι από οποιοδήποτε άλλο προφίλ.'\n#On Channel Page\n  Profile Filter: Φίλτρο προφίλ\n  Profile Settings: Προφίλ\n  Toggle Profile List: Εναλλαγή Λίστας Προφίλ\n  Profile Name: Όνομα προφίλ\n  Edit Profile Name: Επεξεργασία ονόματος προφίλ\n  Create Profile Name: Δημιουργία ονόματος προφίλ\n  Open Profile Dropdown: Ανοίξτε το αναπτυσσόμενο μενού προφίλ\n  Close Profile Dropdown: Κλείστε το αναπτυσσόμενο μενού προφίλ\nChannel:\n  Subscribe: 'Εγγραφή'\n  Unsubscribe: 'Απεγγραφή'\n  Channel has been removed from your subscriptions: 'Το κανάλι έχει καταργηθεί από τις Συνδρομές/Εγγραφές σας'\n  Removed subscription from {count} other channel(s): 'Αφαιρέθηκε η συνδρομή από {count} άλλα κανάλια'\n  Added channel to your subscriptions: 'Προστέθηκε κανάλι στις συνδρομές/εγγραφές σας'\n  Search Channel: 'Αναζήτηση στο κανάλι'\n  Your search results have returned 0 results: 'Τα αποτελέσματα της αναζήτησής σας έχουν επιστρέψει 0 αποτελέσματα'\n  Videos:\n    Videos: 'Βίντεο'\n    This channel does not currently have any videos: 'Αυτό το κανάλι δε διαθέτει προς το παρόν κάποιο βίντεο'\n    Sort Types:\n      Newest: 'Νεότερο'\n      Oldest: 'Παλαιότερο'\n      Most Popular: 'Τα πιο δημοφιλή'\n  Playlists:\n    Playlists: 'Λίστες αναπαραγωγής'\n    This channel does not currently have any playlists: 'Αυτό το κανάλι δε διαθέτει προς το παρόν κάποια λίστα αναπαραγωγής'\n    Sort Types:\n      Last Video Added: 'Τελευταίο βίντεο που προστέθηκε'\n      Newest: 'Νεότερο'\n      Oldest: 'Παλαιότερο'\n  About:\n    About: 'Σχετικά με'\n    Channel Description: 'Περιγραφή καναλιού'\n    Featured Channels: 'Προτεινόμενα κανάλια'\n    Tags:\n      Tags: Ετικέτες\n      Search for: Αναζήτηση για «{tag}»\n    Details: Λεπτομέριες\n    Location: Τοποθεσία\n    Joined: Εγγράφηκαν\n  This channel does not allow searching: Αυτό το κανάλι δεν επιτρέπει την αναζήτηση\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Αυτό το κανάλι έχει περιορισμό ηλικίας και προς το παρόν δεν μπορεί να προβληθεί στο FreeTube.\n  Channel Tabs: Καρτέλες Καναλιών\n  This channel does not exist: Αυτό το κανάλι δεν υπάρχει\n  Posts:\n    This channel currently does not have any posts: Αυτό το κανάλι προς το παρόν δεν έχει αναρτήσεις\n    Reveal Answers: Εμφάνιση Απαντήσεων\n    Hide Answers: Απόκρυψη Απαντήσεων\n    votes: '{votes} ψήφοι'\n    View Full Post: Προβολή πλήρους δημοσίευσης\n    Video hidden by FreeTube: Βίντεο κρυμμένο από FreeTube\n    Viewing Posts Only Supported By Invidious: Η προβολή αναρτήσεων υποστηρίζεται μόνο από το Invidious. Μεταβείτε στην καρτέλα της κοινότητας ενός καναλιού για να δείτε το περιεχόμενο εκεί χωρίς το Invidious.\n  Live:\n    Live: Ζωντανά\n    This channel does not currently have any live streams: Αυτό το κανάλι δεν έχει προς το παρόν ζωντανές ροές\n  Shorts:\n    This channel does not currently have any shorts: Αυτό το κανάλι δεν έχει προς το παρόν κανένα shorts\n  Releases:\n    Releases: Κυκλοφορίες\n    This channel does not currently have any releases: Αυτό το κανάλι δεν έχει προς το παρόν κυκλοφορίες\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Αυτό το κανάλι δεν έχει αυτήν τη στιγμή podcasts\n  Courses:\n    This channel does not currently have any courses: Αυτό το κανάλι δεν έχει προς το παρόν μαθήματα\n    Courses: Μαθήματα\n  Home:\n    View Playlist: Προβολή λίστας αναπαραγωγής\n    Home: Αρχική σελίδα\nVideo:\n  Mark As Watched: 'Επισήμανση ως παρακολουθημένο'\n  Remove From History: 'Κατάργηση από το ιστορικό'\n  Video has been marked as watched: 'Το βίντεο έχει επισημανθεί ως παρακολουθημένο'\n  Video has been removed from your history: 'Το βίντεο έχει καταργηθεί από το ιστορικό σας'\n  Open in YouTube: 'Άνοιγμα στο YouTube'\n  Copy YouTube Link: 'Αντιγραφή συνδέσμου YouTube'\n  Open YouTube Embedded Player: 'Άνοιγμα ενσωματωμένου προγράμματος αναπαραγωγής YouTube'\n  Copy YouTube Embedded Player Link: 'Αντιγραφή συνδέσμου του ενσωματωμένου προγράμματος αναπαραγωγής από το YouTube'\n  Open in Invidious: 'Άνοιγμα στο Invidious'\n  Copy Invidious Link: 'Αντιγραφή συνδέσμου Invidious'\n  Views: 'Προβολές'\n  Loop Playlist: 'Επανάληψη λίστας αναπαραγωγής'\n  Shuffle Playlist: 'Τυχαία σειρά στη λίστα αναπαραγωγής'\n  Reverse Playlist: 'Αντιστροφή της λίστας αναπαραγωγής'\n  Previous: 'Προηγούμενο'\n  Next: 'Επόμενο'\n  Watched: 'Παρακολουθήθηκε'\n  Autoplay: 'Αυτόματη αναπαραγωγή'\n  # As in a Live Video\n  Live: 'Ζωντανά'\n  Live Now: 'Ζωντανά τώρα'\n  Live Chat: 'Ζωντανή συνομιλία'\n  Enable Live Chat: 'Ενεργοποίηση Ζωντανής συνομιλίας'\n  Live Chat is currently not supported in this build.: 'Η ζωντανή συνομιλία δεν υποστηρίζεται προς το παρόν σε αυτήν την έκδοση.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Η ζωντανή συνομιλία είναι ενεργοποιημένη.  Τα μηνύματα συνομιλίας θα εμφανίζονται εδώ μόλις σταλούν.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Η ζωντανή συνομιλία δεν υποστηρίζεται προς το παρόν με το Invidious API. Απαιτείται άμεση σύνδεση με το YouTube.'\n  Published:\n    In less than a minute: Σε λιγότερο από ένα λεπτό\n  Published on: 'Δημοσιεύθηκε στις'\n#& Videos\n  Starting soon, please refresh the page to check again: Έναρξη σύντομα, παρακαλούμε κάντε ανανέωση της σελίδας για επανέλεγχο\n  Copy Invidious Channel Link: Αντιγραφή συνδέσμου καναλιού Invidious\n  Copy YouTube Channel Link: Αντιγραφή συνδέσμου καναλιού YouTube\n  Started streaming on: Ξεκίνησε να μεταδίδει ζωντανά την\n  Streamed on: Μεταδίδεται ζωντανά σε\n  Open Channel in Invidious: Άνοιγμα καναλιού στο Invidious\n  Open Channel in YouTube: Άνοιγμα καναλιού στο YouTube\n  Video has been removed from your saved list: Το βίντεο καταργήθηκε από την αποθηκευμένη λίστα σας\n  Video has been saved: Το βίντεο έχει αποθηκευτεί\n  Save Video: Αποθήκευση βίντεο\n  Sponsor Block category:\n    intro: Εισαγωγή\n    interaction: Αλληλεπίδραση\n    sponsor: Χορηγός\n    outro: Επίλογος\n    self-promotion: Αυτοπροβολή\n    music offtopic: Μουσική Εκτός θέματος\n    recap: Ανακεφαλαίωση\n    filler: Γεμιστικό\n  External Player:\n    video: βίντεο\n    OpenInTemplate: Άνοιγμα σε {externalPlayer}\n    Unsupported Actions:\n      looping playlists: επανάληψη των λιστών αναπαραγωγής\n      starting video at offset: εκκίνηση βίντεο στη μετατόπιση\n      setting a playback rate: ρύθμιση ρυθμού αναπαραγωγής\n      opening playlists: άνοιγμα λιστών αναπαραγωγής\n      shuffling playlists: ανακάτεμα των λιστών αναπαραγωγής\n      opening specific video in a playlist (falling back to opening the video): άνοιγμα συγκεκριμένου βίντεο σε μια λίστα αναπαραγωγής (επιστροφή στο άνοιγμα του βίντεο)\n      reversing playlists: αντιστροφή λιστών αναπαραγωγής\n    playlist: λίστα αναπαραγωγής\n    OpeningTemplate: Άνοιγμα {videoOrPlaylist} σε {externalPlayer}...\n    UnsupportedActionTemplate: 'Το {externalPlayer} δεν υποστηρίζει: {action}'\n  Show Super Chat Comment: Εμφάνιση Σχολίου Super Chat\n  Scroll to Bottom: Κύλιση προς τα Κάτω\n  Premieres: Πρεμιέρες\n  Upcoming: Επερχόμενο\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': \"Η Zωντανή συνομιλία δεν είναι διαθέσιμη για αυτήν τη ροή. Μπορεί να έχει απενεργοποιηθεί από τον χρήστη.\"\n  Unhide Channel: Εμφάνιση καναλιού\n  Hide Channel: Απόκρυψη καναλιού\n#& Playlists\n  Unlisted: Μη καταχωρημένο\n  Player:\n    Autoplay is off: Η αυτόματη αναπαραγωγή είναι απενεργοποιημένη\n    Autoplay is on: Η αυτόματη αναπαραγωγή είναι ενεργοποιημένη\n    Exit Full Window: Έξοδος πλήρους παραθύρου\n    Stats:\n      Video ID: 'Αναγνωριστικό βίντεο: {videoId}'\n      Player Dimensions: 'Διαστάσεις Αναπαραγωγέα: {width}x{height}'\n      CodecsVideoAudio: 'Κωδικοποιητές: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Bandwidth: 'Εύρος ζώνης: {bandwidth} kbps'\n      Dropped Frames / Total Frames: 'Πεσμένα καρέ: {droppedFrames} / Σύνολο καρέ: {totalFrames}'\n      Stats: Στατιστικά στοιχεία\n      Media Formats: 'Μορφές πολυμέσων: {formats}'\n      Volume: 'Ήχος: {volumePercentage}%'\n      CodecsVideoAudioNoItags: 'Κωδικοποιητές: {videoCodec} / {audioCodec}'\n      CodecAudio: 'Κωδικοποιητής: {audioCodec} ({audioItag})'\n      Bitrate: 'Ρυθμός μετάδοσης δεδομένων: {bitrate} kbps'\n      Resolution: 'Διαστάσεις: {width}x{height}{''@''}{frameRate}'\n      Buffered: 'Αποθηκευμένη: {bufferedPercentage}%'\n    Theatre Mode: Λειτουργία Θεάτρου\n    Full Window: Πλήρες Παράθυρο\n    Take Screenshot: Πάρτε στιγμιότυπο οθόνης\n    TranslatedCaptionTemplate: '{language} (μεταφρασμένο από «{originalLanguage}»)'\n    Exit Theatre Mode: Έξοδος από λειτουργία θεάτρου\n    Show Stats: Εμφάνιση στατιστικών στοιχείων\n    Hide Stats: Απόκρυψη στατιστικών\n    Audio Tracks: Κομμάτια ήχου\n    Skipped segment: Παραλείφθηκε το τμήμα {segmentCategory}\n    Playback will resume automatically when your connection comes back: Η αναπαραγωγή θα συνεχιστεί αυτόματα όταν επανέλθει η σύνδεσή σας.\n    You appear to be offline: Φαίνεται ότι είστε εκτός σύνδεσης.\n  MembersOnly: Τα βίντεο μόνο για μέλη δεν μπορούν να παρακολουθηθούν με το FreeTube, καθώς απαιτούν σύνδεση στο Google και συνδρομή επί πληρωμή στο κανάλι του μεταφορτωτή.\n  Save Watched Progress: Αποθήκευση παρακολουθούμενης προόδου\n  Watched Progress Saved: Παρακολουθούμενη πρόοδος Αποθηκευμένη\n  IP block: Το YouTube έχει αποκλείσει τη διεύθυνση IP σας από την παρακολούθηση βίντεο. Προσπαθήστε να αλλάξετε VPN ή proxy.\n  AgeRestricted: Τα βίντεο με περιορισμούς ηλικίας δεν μπορούν να παρακολουθηθούν με το FreeTube, καθώς απαιτούν σύνδεση στο Google και χρήση ενός λογαριασμού YouTube που έχει επαληθευτεί ως προς την ηλικία.\n  DeArrow:\n    Show Original Details: Εμφάνιση αρχικών λεπτομερειών\n    Show Modified Details: Εμφάνιση τροποποιημένων λεπτομερειών\n  More Options: Περισσότερες Επιλογές\n  DRMProtected: Τα βίντεο που προστατεύονται με DRM δεν μπορούν να αναπαραχθούν στο FreeTube, καθώς απαιτούν ιδιόκτητα εξαρτήματα κλειστού κώδικα. Αν θέλετε να παρακολουθήσετε αυτό το βίντεο, παρακαλούμε να το παρακολουθήσετε στον επίσημο ιστότοπο του YouTube σε ένα πρόγραμμα περιήγησης ιστού με δυνατότητα DRM.\nPlaylist:\n  #& About\n  View Full Playlist: 'Προβολή πλήρους λίστας αναπαραγωγής'\n  Last Updated On: 'Τελευταία ενημέρωση στις'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Λίστα αναπαραγωγής\n  Sort By:\n    DateAddedOldest: Το νωρίτερο προστέθηκε πρώτο\n    DateAddedNewest: Τα τελευταία προστέθηκαν πρώτα\n    AuthorDescending: Συγγραφέας (Ω-Α)\n    AuthorAscending: Συγγραφέας (Α-Ω)\n    VideoTitleAscending: Τίτλος (Α-Ω)\n    VideoTitleDescending: Τίτλος (Ω-Α)\n    VideoDurationAscending: Διάρκεια (συντομότερο πρώτο)\n    VideoDurationDescending: Διάρκεια (μεγαλύτερο πρώτο)\n    Custom: Προσαρμοσμένη\n    PublishedOldest: Το νωρίτερο δημοσιεύτηκε πρώτο\n    PublishedNewest: Το παλαιώτερο προστέθηκε πρώτο\nChange Format:\n  Change Media Formats: 'Αλλαγή μορφής του βίντεο'\n  Use Dash Formats: 'Χρησιμοποίηση μορφών Dash'\n  Use Legacy Formats: 'Χρησιμοποίηση παλαιότερων μορφών'\n  Use Audio Formats: 'Χρησιμοποίηση Μορφών Ήχου'\n  Dash formats are not available for this video: 'Οι μορφές Dash δεν είναι διαθέσιμες για αυτό το βίντεο'\n  Audio formats are not available for this video: 'Δε διατίθενται μορφές ήχου για αυτό το βίντεο'\n  Legacy formats are not available for this video: Οι παλαιές μορφές δεν είναι διαθέσιμες για αυτό το βίντεο\nShare:\n  Share Video: 'Κοινοποίηση βίντεο'\n  Share Playlist: 'Κοινοποίηση λίστας αναπαραγωγής'\n  Include Timestamp: 'Συμπερίληψη χρονικής σήμανσης/στιγμής'\n  Copy Link: 'Αντιγραφή συνδέσμου'\n  Open Link: 'Άνοιγμα Συνδέσμου'\n  Copy Embed: 'Αντιγραφή ενσωματωμένης έκδοσης'\n  Open Embed: 'Άνοιγμα ενσωματωμένης έκδοσης'\n  # On Click\n  Invidious URL copied to clipboard: 'Η διεύθυνση Invidious αντιγράφηκε στο πρόχειρο'\n  Invidious Embed URL copied to clipboard: 'Η ενσωματωμένη διεύθυνση Invidious αντιγράφηκε στο πρόχειρο'\n  YouTube URL copied to clipboard: 'Η διεύθυνση YouTube αντιγράφηκε στο πρόχειρο'\n  YouTube Embed URL copied to clipboard: 'Η ενσωματωμένη διεύθυνση Youtube αντιγράφηκε στο πρόχειρο'\n  YouTube Channel URL copied to clipboard: Ο σύνδεσμος καναλιού Youtube αντιγράφηκε στο πρόχειρο\n  Invidious Channel URL copied to clipboard: Ο σύνδεσμος καναλιού Invidious αντιγράφηκε στο πρόχειρο\n  Share Channel: Κοινή χρήση Καναλιού\nMini Player: 'Μικρή πλατφόρμα αναπαραγωγής'\nComments:\n  Comments: 'Σχόλια'\n  Click to View Comments: 'Κάντε κλικ για να δείτε σχόλια'\n  Getting comment replies, please wait: 'Λήψη απαντήσεων σε σχόλια, παρακαλώ περιμένετε'\n  Hide Comments: 'Απόκρυψη σχολίων'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Δεν υπάρχουν διαθέσιμα σχόλια γι αυτό το βίντεο'\n  Load More Comments: 'Φόρτωση περισσότερων σχολίων'\n  Newest first: Νεότερο πρώτα\n  Top comments: Κορυφαία σχόλια\n  There are no more comments for this video: Δεν υπάρχουν άλλα σχόλια για αυτό το βίντεο\n  Show More Replies: Εμφάνιση περισσότερων απαντήσεων\n  Pinned by: Καρφώθηκε από\n  Member: Μέλος\n  Hearted: Αγαπημένο\n  View {replyCount} replies: Προβολή {replyCount} απαντήσεων\n  Subscribed: Εγγεγραμμένος\n  There are no comments available for this post: Δεν υπάρχουν διαθέσιμα σχόλια για αυτή τη ανάρτηση\nUp Next: 'Επόμενο'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Τοπικό σφάλμα Διεπαφής προγραμματισμού εφαρμογής (*API) (Κάντε κλικ για αντιγραφή)'\nInvidious API Error (Click to copy): 'Σφάλμα Διεπαφής προγραμματισμού εφαρμογής Invidious(*API) (Κάντε κλικ για αντιγραφή)'\nFalling back to Invidious API: 'Επιστροφή στο Invidious API'\nFalling back to Local API: 'Επιστροφή στη τοπική Διεπαφή προγραμματισμού εφαρμογής (API)'\nLoop is now disabled: 'Η επανάληψη είναι πλέον απενεργοποιημένη'\nLoop is now enabled: 'Η επανάληψη έχει ενεργοποιηθεί'\nShuffle is now disabled: 'Η τυχαία αναπαραγωγή είναι πλέον απενεργοποιημένη'\nShuffle is now enabled: 'Η τυχαία αναπαραγωγή ενεργοποιήθηκε'\nThe playlist has been reversed: 'Η λίστα αναπαραγωγής έχει αντιστραφεί'\nPlaying Next Video: 'Αναπαραγωγή του επόμενου βίντεο'\nPlaying Previous Video: 'Αναπαραγωγή προηγούμενου βίντεο'\nCanceled next video autoplay: 'Η αναπαραγωγή του επόμενου βίντεο έχει ακυρωθεί'\n'The playlist has ended. Enable loop to continue playing': 'Η λίστα αναπαραγωγής έχει τελειώσει. Ενεργοποιήστε τη λειτουργία επανάληψης για συνέχιση της αναπαραγωγής'\n\nYes: 'Ναι'\nNo: 'Όχι'\nA new blog is now available, {blogTitle}. Click to view more: Ένα καινούριο ιστολόγιο είναι πλέον διαθέσιμο, {blogTitle}. Για περισσότερες λεπτομέρειες κάντε κλικ εδώ\nDownload From Site: Κάντε λήψη από την Ιστοσελίδα\nVersion {versionNumber} is now available!  Click for more details: Η έκδοση {versionNumber} είναι πλέον διαθέσιμη. Κάντε κλικ για περισσότερες λεπτομέρειες\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Αυτό το βίντεο δεν είναι διαθέσιμο λόγω έλλειψης μορφών. Αυτό μπορεί να συμβαίνει λόγω μη διαθεσιμότητας του βίντεο στη χώρα σας.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Όταν ενεργοποιηθεί, το FreeTube θα χρησιμοποιήσει RSS αντί για την προεπιλεγμένη μέθοδο για να αρπάξει τη ροή συνδρομής σας. Το RSS είναι ταχύτερο και αποτρέπει τον αποκλεισμό IP, αλλά δεν παρέχει ορισμένες πληροφορίες, όπως διάρκεια βίντεο, ζωντανή κατάσταση ή αναρτήσεις\n    Fetch Automatically: Όταν ενεργοποιηθεί, το FreeTube θα ανακτήσει αυτόματα τη ροή συνδρομής σας κατά την εκκίνηση και όταν ανοίξει ένα νέο παράθυρο.\n  Player Settings:\n    Default Video Format: Ορίστε τις μορφές που χρησιμοποιούνται κατά την αναπαραγωγή ενός βίντεο. Οι μορφές DASH μπορούν να αναπαράγουν υψηλότερες ποιότητες. Οι μορφές παλαιού τύπου περιορίζονται σε μέγιστο 360p, αλλά χρησιμοποιούν μικρότερο εύρος ζώνης. Οι μορφές ήχου είναι ροές μόνο ήχου.\n    Proxy Videos Through Invidious: Θα συνδεθεί με το Invidious για να εξυπηρετήσει τα βίντεο αντί να κάνει μια άμεση σύνδεση με το YouTube.\n    Scroll Playback Rate Over Video Player: Ενώ ο δρομέας βρίσκεται πάνω από το βίντεο, πατήστε και κρατήστε πατημένο το πλήκτρο Control (Command Key σε Mac) και μετακινηθείτε με τον τροχό του ποντικιού προς τα εμπρός ή προς τα πίσω για να ελέγξετε το ρυθμό αναπαραγωγής. Πατήστε παρατεταμένα το πλήκτρο Control (Command Key σε Mac) και κάντε αριστερό κλικ στο ποντίκι για να επιστρέψετε γρήγορα στον προεπιλεγμένο ρυθμό αναπαραγωγής (1x εκτός αν έχει αλλάξει στις ρυθμίσεις).\n    Skip by Scrolling Over Video Player: Χρησιμοποιήστε τον τροχό κύλισης για να παρακάμψετε το βίντεο, στυλ MPV.\n  General Settings:\n    Region for Trending: Η περιοχή των τάσεων σας επιτρέπει να επιλέξετε τα δημοφιλή βίντεο της χώρας που θέλετε να εμφανίζονται.\n    Thumbnail Preference: Όλες οι μικρογραφίες σε όλο το FreeTube θα αντικατασταθούν με ένα πλαίσιο του βίντεο, θολό ή κρυφό αντί για την προεπιλεγμένη μικρογραφία.\n    Fallback to Non-Preferred Backend on Failure: Όταν το προτιμώμενο API αντιμετωπίζει πρόβλημα, το FreeTube θα προσπαθήσει να χρησιμοποιήσει το μη προτιμώμενο API ως εναλλακτική μέθοδο όταν ενεργοποιηθεί.\n    Preferred API Backend: Επέλεξε το σύστημα με το οποίο το Freetube θα συλλέγει δεδομένα. Το τοπικό API είναι ένα ενσωματωμένο εργαλείο. Ενώ το Invidious API απαιτεί έναν Invidious server για να συνδεθεί.\n    Invidious Instance: Το στιγμιότυπο Invidious στο οποίο το FreeTube θα συνδεθεί για κλήσεις διεπαφής.\n    External Link Handling: \"Επιλέξτε την προεπιλεγμένη συμπεριφορά όταν κάνετε κλικ σε έναν σύνδεσμο, ο οποίος δεν μπορεί να ανοίξει στο FreeTube.\\nΑπό προεπιλογή, το FreeTube θα ανοίξει τον σύνδεσμο που έχει πατηθεί στο προεπιλεγμένο πρόγραμμα περιήγησης.\\n\"\n    Open Deep Links In New Window: Οι διευθύνσεις URL που μεταβιβάζονται στο FreeTube, όπως από επεκτάσεις του προγράμματος περιήγησης redirect ή από ορίσματα της γραμμής εντολών, ανοίγουν σε ένα νέο παράθυρο.\n  External Player Settings:\n    Custom External Player Executable: Από προεπιλογή, το FreeTube θα υποθέσει ότι το επιλεγμένο εξωτερικό πρόγραμμα αναπαραγωγής μπορεί να βρεθεί μέσω της μεταβλητής περιβάλλοντος PATH. Εάν χρειάζεται, μπορείτε να ορίσετε μια προσαρμοσμένη διαδρομή εδώ.\n    Ignore Warnings: Απόκρυψη προειδοποιήσεων για όταν το τρέχον εξωτερικό πρόγραμμα αναπαραγωγής δεν υποστηρίζει την τρέχουσα ενέργεια (π.χ. αντιστροφή λιστών αναπαραγωγής κ.λπ.).\n    External Player: Η επιλογή ενός εξωτερικού προγράμματος αναπαραγωγής θα εμφανίσει ένα εικονίδιο, για το άνοιγμα του βίντεο (λίστα αναπαραγωγής, εάν υποστηρίζεται) στο εξωτερικό πρόγραμμα αναπαραγωγής, στη μικρογραφία. Προειδοποίηση, Οι ακατάλληλες ρυθμίσεις δεν επηρεάζουν τις εξωτερικές συσκευές αναπαραγωγής.\n    DefaultCustomArgumentsTemplate: \"(Προεπιλογή: '{defaultCustomArguments}')\"\n    Custom External Player Arguments: Τυχόν προσαρμοσμένα ορίσματα γραμμής εντολών, που θέλετε να μεταβιβαστούν στο εξωτερικό πρόγραμμα αναπαραγωγής.\n    Ignore Default Arguments: Μην στέλνετε προεπιλεγμένα ορίσματα στην εξωτερική συσκευή αναπαραγωγής εκτός από τη διεύθυνση URL του βίντεο (π.χ. ρυθμός αναπαραγωγής, διεύθυνση URL λίστας αναπαραγωγής κ.λπ.). Τα προσαρμοσμένα ορίσματα θα εξακολουθήσουν να διαβιβάζονται.\n  Experimental Settings:\n    Replace HTTP Cache: Απενεργοποιεί το Electron's disk-based HTTP cache και ενεργοποιεί μια προσαρμοσμένη προσωρινή μνήμη εικόνων στη μνήμη. Θα οδηγήσει σε αυξημένη χρήση RAM.\n  Distraction Free Settings:\n    Hide Channels: Εισαγάγετε ένα αναγνωριστικό καναλιού για να αποκρύψετε όλα τα βίντεο, τις λίστες αναπαραγωγής και το ίδιο το κανάλι, ώστε να μην εμφανίζονται στην αναζήτηση, τα ανερχόμενα, τα πιο δημοφιλή και προτεινόμενα. Το αναγνωριστικό καναλιού που καταχωρίσατε πρέπει να αντιστοιχεί πλήρως και να κάνει διάκριση πεζών-κεφαλαίων.\n    Hide Subscriptions Live: Αυτή η ρύθμιση παρακάμπτεται από τη ρύθμιση \"{appWideSetting}\" σε όλη την εφαρμογή, στην ενότητα \"{subsection}\" του \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Εισάγετε μια λέξη, ένα τμήμα λέξης ή μια φράση (χωρίς ευαισθησία στην πεζότητα) για να αποκρύψετε όλα τα βίντεο και τις λίστες αναπαραγωγής των οποίων οι αρχικοί τίτλοι την περιέχουν σε όλο το FreeTube, εξαιρώντας μόνο το Ιστορικό, τις Λίστες αναπαραγωγής σας και τα βίντεο μέσα σε λίστες αναπαραγωγής.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Αντικαταστήστε τους τίτλους βίντεο με τίτλους που υποβλήθηκαν από τους χρήστες από το DeArrow.\n    UseDeArrowThumbnails: Αντικαταστήστε τις μικρογραφίες βίντεο με μικρογραφίες από το DeArrow.\nPlaying Next Video Interval: Αναπαραγωγή επόμενου βίντεο άμεσα. Κάντε κλικ για ακύρωση. | Αναπαραγωγή επόμενου βίντεο σε {nextVideoInterval} δευτερόλεπτο. Κάντε κλικ για ακύρωση. | Αναπαραγωγή επόμενου βίντεο σε {nextVideoInterval} δευτερόλεπτα. Κάντε κλικ για ακύρωση.\nMore: Περισσότερα\nUnknown YouTube url type, cannot be opened in app: Άγνωστος τύπος διεύθυνσης URL YouTube, δεν είναι δυνατό να ανοίξει στην εφαρμογή\nSearch Bar:\n  Clear Input: Εκκαθάριση εισαγωγής\n  Remove: Αφαίρεση\nOpen New Window: Άνοιγμα Νέου παραθύρου\nDefault Invidious instance has been set to {instance}: Το προεπιλεγμένο στιγμιότυπο Invidious έχει οριστεί σε {instance}\nDefault Invidious instance has been cleared: Το προεπιλεγμένο στιγμιότυπο Invidious έχει διαγραφεί\nExternal link opening has been disabled in the general settings: Το άνοιγμα εξωτερικών συνδέσμων έχει απενεργοποιηθεί στις γενικές ρυθμίσεις\nAre you sure you want to open this link?: Θέλετε σίγουρα να ανοίξετε αυτόν το σύνδεσμο;\nChannels:\n  Channels: Κανάλια\n  Title: Λίστα Καναλιών\n  Search bar placeholder: Αναζήτηση Καναλιών\n  Count: '{number} κανάλι(α) βρέθηκαν.'\n  Empty: Η λίστα καναλιών σας είναι άδεια.\n  Unsubscribe Prompt: Θέλετε σίγουρα να απεγγραφείτε από το \"{channelName}\"?\nNew Window: Νέο Παράθυρο\nScreenshot Error: 'Λήψη στιγμιότυπου απέτυχε. {error}'\nClipboard:\n  Copy failed: Η αντιγραφή στο πρόχειρο απέτυχε\n  Cannot access clipboard without a secure connection: Δεν είναι δυνατή η πρόσβαση στο πρόχειρο χωρίς ασφαλή σύνδεση\nChapters:\n  Chapters: Κεφάλαια\n  Key Moments: Στιγμές κλειδιά\nOk: Εντάξει\nPreferences: Προτιμήσεις\nScreenshot Success: Αποθηκευμένο στιγμιότυπο\nHashtag:\n  Hashtag: Χαστάγκ\n  This hashtag does not currently have any videos: Αυτό το hashtag δεν έχει προς το παρόν κανένα βίντεο\nChannel Hidden: Το {channel} προστέθηκε στο φίλτρο καναλιού\nGo to page: Μετάβαση σε {page}\nChannel Unhidden: Το {channel} καταργήθηκε από το φίλτρο καναλιού\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Υπότιτλοι\n    Closed Captions: Κλειστές λεζάντες\n    360 Video: 360°\n    8K: 8Κ\n    VR180: VR180\n    New: Νέα\n    3D: 3D\nSearch character limit: Το ερώτημα αναζήτησης είναι πάνω από το αναζητήσημο όριο χαρακτήρα\nRight-click or hold to see history: Δεξί κλικ ή κράτηστε για να δείτε το ιστορικό\nClose Banner: Κλείσιμο Βanner\nFeed:\n  Refresh Feed: Ανανέωση {subscriptionName}\n  Feed Last Updated: '{feedName}Η τροφοδοσίας ενημερώθηκε τελευταία : {date}'\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Εναλλαγή εργαλείων προγραμματιστή\n  Focus Search: Επικεντρωθείτε στη γραμμή αναζήτησης\n  Search in New Window: Αναζήτηση σε νέο παράθυρο\n  Minimize Window: Ελαχιστοποίηση παραθύρου\n  Close Window: Κλείσιμο παραθύρου\n  Skip by Tenths: Μεταπήδηση στο βίντεο ανά ποσοστό (3 μεταπηδήσεις στο 30% της διάρκειας)\n  Sections:\n    Video:\n      General: 'Βίντεο: Γενικά'\n      Playback: 'Βίντεο: Αναπαραγωγή'\n    App:\n      General: 'App: Γενικά'\n      Situational: 'Εφαρμογή: Καταστασιακή'\n  History Backward: Πήγαινε μια σελίδα πίσω\n  Large Rewind: Επανάληψη 10 δευτερολέπτων / Επανάληψη βίντεο με βάση τον τρέχοντα ρυθμό αναπαραγωγής βίντεο\n  Mute: Εναλλαγή σίγασης\n  Decrease Video Speed: Μείωση της ταχύτητας βίντεο βάσει του διαστήματος ρυθμού αναπαραγωγής βίντεο\n  Reset Zoom: Επαναφορά επιπέδου ζουμ / κλίμακας UI\n  Zoom In: Μεγέθυνση\n  Small Fast Forward: Γρήγορη προώθηση X δευτερόλεπτα βάσει του διαστήματος γρήγορης προώθησης και του τρέχοντος ρυθμού αναπαραγωγής βίντεο\n  Next Frame: Επόμενο καρέ (σε παύση)\n  History Forward: Πήγαινε μια σελίδα μπροστά\n  Volume Down: Μείωση έντασης\n  Next Chapter: Επόμενο κεφάλαιο\n  Large Fast Forward: Προώθηση 10 δευτερολέπτων / Γρήγορη προώθηση βίντεο με βάση τον τρέχοντα ρυθμό αναπαραγωγής βίντεο\n  Captions: Εναλλαγή των λεζάντων ON/OFF\n  New Window: Δημιουργία νέου παραθύρου\n  Navigate to History: Πλοηγηθείτε στη σελίδα Ιστορικό\n  Last Frame: Προηγούμενο καρέ (σε παύση)\n  Keyboard Shortcuts: Συντομεύσεις πληκτρολογίου\n  Navigate to Settings: Πλοηγηθείτε στη σελίδα Ρυθμίσεις\n  Small Rewind: Αναδίπλωση X δευτερολέπτων βάσει του διαστήματος αναδίπλωσης και του τρέχοντος ρυθμού αναπαραγωγής βίντεο\n  Refresh: Ανανέωση της τροφοδοσίας με το πιο πρόσφατο περιεχόμενο\n  Play: Εναλλαγή αναπαραγωγής/παύσης\n  Fullscreen: Εναλλαγή πλήρους οθόνης\n  Full Window: Εναλλαγή πλήρους παραθύρου\n  Theatre Mode: Εναλλαγή λειτουργίας θεάτρου\n  Show Keyboard Shortcuts: Εμφάνιση συντομεύσεων πληκτρολογίου\n  Focus Secondary Search: Επικεντρωθείτε στη δευτερεύουσα γραμμή αναζήτησης (αν υπάρχει)\n  Take Screenshot: Τράβηξε στιγμιότυπο οθόνης\n  Stats: Εμφάνιση στατιστικών βίντεο\n  Picture in Picture: Εναλλαγή της λειτουργίας Εικόνα-σε-Εικόνα\n  Increase Video Speed: Αύξηση της ταχύτητας βίντεο βάσει του διαστήματος ρυθμού αναπαραγωγής βίντεο\n  Zoom Out: Σμίκρυνση\n  Volume Up: Αύξηση έντασης\n  Last Chapter: Τελευταίο κεφάλαιο\nYes, Open Link: Ναι, Άνοιγμα συνδέσμου\nDescription:\n  Expand Description: '...περισσότερα'\n  Collapse Description: Εμφάνιση λιγότερων\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nAge Restricted:\n  This channel is age restricted: Αυτό το κανάλι είναι περιορισμένης ηλικίας\n  This video is age restricted: Αυτό το βίντεο είναι περιορισμένης ηλικίας\nCancel: Ακύρωση\nYes, Delete: Ναι, Διαγράψτε\nKeys:\n  arrowleft: Αριστερό βέλος\n  plus: Plus\n  alt: Alt\n  arrowdown: Κάτω βέλος\n  ctrl: Ctrl\n  enter: Enter\n  arrowright: Δεξί βέλος\n  arrowup: Πάνω βέλος\n  shift: Shift\nTrimmed input must be at least N characters long: Η περικομμένη είσοδος πρέπει να έχει μήκος τουλάχιστον 1 χαρακτήρα | Η περικομμένη είσοδος πρέπει να έχει μήκος τουλάχιστον {length} χαρακτήρες\nAutoplay Interruption Timer: Η αυτόματη αναπαραγωγή ακυρώθηκε λόγω {autoplayInterruptionIntervalHours} ωρών αδράνειας\nTag already exists: Η ετικέτα «{tagName}» υπάρχει ήδη\nMoments Ago: στιγμές πριν\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nYes, Restart: Ναι, Επανεκκίνηση\nshortcutLabelSeparator: ｜\n"
  },
  {
    "path": "static/locales/en-GB.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'English (UK)'\n\n# Webkit Menu Bar\nFile: 'File'\nQuit: 'Quit'\nEdit: 'Edit'\nUndo: 'Undo'\nRedo: 'Redo'\nCut: 'Cut'\nCopy: 'Copy'\nPaste: 'Paste'\nDelete: 'Delete'\nSelect all: 'Select all'\nToggle Developer Tools: 'Toggle Developer Tools'\nActual size: 'Actual size'\nZoom in: 'Zoom in'\nZoom out: 'Zoom out'\nToggle fullscreen: 'Toggle full-screen'\nWindow: 'Window'\nMinimize: 'Minimise'\nClose: 'Close'\nBack: 'Back'\nForward: 'Forward'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: Videos\n  Shorts: Shorts\n  Live: Live\n  Posts: Posts\n  Sort By: Sort by\n\n  Counts:\n    Video Count: 1 video | {count} videos\n    Subscriber Count: 1 subscriber | {count} subscribers\n    View Count: 1 view | {count} views\n    Watching Count: 1 watching | {count} watching\n    Channel Count: 1 channel | {count} channels\n    Like Count: 1 like | {count} likes\n    Comment Count: 1 comment | {count} comments\nVersion {versionNumber} is now available!  Click for more details: 'Version {versionNumber} is now available!  Click for more details'\nDownload From Site: 'Download from site'\nA new blog is now available, {blogTitle}. Click to view more: 'A new blog is now available, {blogTitle}. Click to view more'\n\n# Search Bar\nSearch / Go to URL: 'Search / Go to URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Search filters'\n  Sort By:\n    Most Relevant: 'Most relevant'\n    Rating: 'Rating'\n    Upload Date: 'Upload date'\n    View Count: 'View count'\n  Time:\n    Time: 'Time'\n    Any Time: 'Any time'\n    Last Hour: 'Last hour'\n    Today: 'Today'\n    This Week: 'This week'\n    This Month: 'This month'\n    This Year: 'This year'\n  Type:\n    Type: 'Type'\n    All Types: 'All types'\n    Videos: 'Videos'\n    Channels: 'Channels'\n    #& Playlists\n    Movies: Films\n  Duration:\n    Duration: 'Duration'\n    All Durations: 'All durations'\n    Short (< 4 minutes): 'Short (< 4 minutes)'\n    Long (> 20 minutes): 'Long (> 20 minutes)'\n  # On Search Page\n    Medium (4 - 20 minutes): Medium (4 - 20 minutes)\n  Search Results: 'Search results'\n  Fetching results. Please wait: 'Fetching results. Please wait'\n  Fetch more results: 'Fetch more results'\n# Sidebar\n  There are no more results for this search: There are no more results for this search\n  Features:\n    Features: Features\n    HD: HD\n    Subtitles: Subtitles\n    VR180: VR180\n    Creative Commons: Creative Commons\n    HDR: HDR\n    360 Video: 360 Video\n    Live: Live\n    4K: 4K\n    3D: 3D\n    Location: Location\n  Clear Filters: Clear Filters\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subscriptions'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Your Subscription list is currently empty. If you want to import your subscriptions you can go to Data Settings and select Import Subscriptions or you can search for a channel and subscribe to them.'\n  Load More Videos: Load more videos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: This profile has a large number of subscriptions.  Forcing RSS to avoid rate limiting\n  Error Channels: Channels with errors\n  Disabled Automatic Fetching: You have disabled automatic subscription fetching. Refresh subscriptions to see them here.\n  Empty Channels: Your subscribed channels currently does not have any videos.\n  Subscriptions Tabs: Subscriptions tabs\n  All Subscription Tabs Hidden: All subscription tabs are hidden. To see content here, please unhide some tabs in the ‘{subsection}’ section in ‘{settingsSection}’.\n  Empty Posts: Your subscribed channels currently do not have any posts.\n  Load More Posts: Load more posts\nTrending:\n  Trending: 'Trending'\n  Trending Tabs: Trending Tabs\n  Gaming: Gaming\n  Sports: Sports\nMost Popular: 'Most Popular'\nPlaylists: 'Playlists'\nUser Playlists:\n  Your Playlists: 'Your playlists'\n  Search bar placeholder: Search for playlists\n  Empty Search Message: There are no videos in this playlist that match your search\n  Create New Playlist: Create new Playlist\n  Add to Playlist: Add to playlist\n  This playlist currently has no videos.: This playlist currently has no videos.\n  Move Video Down: Move video down\n  Playlist Name: Playlist name\n  Playlist Description: Playlist description\n  Save Changes: Save changes\n  Edit Playlist Info: Edit playlist info\n  Delete Playlist: Delete playlist\n  Sort By:\n    NameAscending: A-Z\n    NameDescending: Z-A\n    EarliestCreatedFirst: Date Created (Oldest)\n    LatestUpdatedFirst: Date Updated (Newest)\n    EarliestUpdatedFirst: Date Updated (Oldest)\n    LatestPlayedFirst: Date Played (Newest)\n    EarliestPlayedFirst: Date Played (Oldest)\n    LatestCreatedFirst: Date Created (Newest)\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: This video cannot be moved up.\n      This video cannot be moved down.: This video cannot be moved down.\n      There was a problem with removing this video: There was a problem with removing this video\n      Playlist name cannot be empty. Please input a name.: Playlist name cannot be empty. Please input a name.\n      Playlist has been updated.: Playlist has been updated.\n      \"{videoCount} video(s) have been removed\": 1 video has been removed | {videoCount} videos have been removed\n      This playlist is protected and cannot be removed.: This playlist is protected and cannot be removed.\n      This playlist does not exist: This playlist does not exist\n\n      This playlist has a video with a duration error: This playlist contains at least one video that doesn't have a duration, it will be sorted as if their duration is zero.\n      Playlist {playlistName} has been deleted.: Playlist {playlistName} has been deleted.\n      Video has been removed: Video has been removed\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Some videos in the playlist are not loaded yet. Click here to copy anyway.\n      There was an issue with updating this playlist.: There was an issue with updating this playlist.\n      There were no videos to remove.: There were no videos to remove.\n      Reverted to use {oldPlaylistName} for quick bookmark: Reverted to use {oldPlaylistName} for quick bookmark\n      This playlist is now used for quick bookmark: This playlist is now used for quick bookmark\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo\n      This playlist is already being used for quick bookmark.: This playlist is already being used for quick bookmark.\n      Video has been removed. Click here to undo.: Video has been removed. Click here to undo.\n    Search for Videos: Search for videos\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} selected'\n    Search in Playlists: Search in playlists\n    Save: Save\n    Toast:\n      You haven't selected any playlist yet.: You haven't selected any playlist yet.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(s) added to 1 playlist | Video(s) added to {playlistCount} playlists\"\n    Select a playlist to add your N videos to: Select a playlist to add your video to | Select a playlist to add your {videoCount} videos to\n    Added {count} Times: Already Added | Added {count} times\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} videos will be added'\n    Allow Adding Duplicate Video(s): Allow adding duplicate video(s)\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videos already added'\n  CreatePlaylistPrompt:\n    New Playlist Name: New Playlist name\n    Create: Create\n    Toast:\n      Playlist {playlistName} has been successfully created.: Playlist {playlistName} has been successfully created.\n      There was an issue with creating the playlist.: There was an problem when creating the playlist.\n      There is already a playlist with this name. Please pick a different name.: There is already a Playlist with this name. Please pick a different name.\n  You have no playlists. Click on the create new playlist button to create a new one.: You have no playlists. Click on the create new playlist button to create a new one.\n  Move Video Up: Move video up\n  Cancel: Cancel\n  Remove from Playlist: Remove from playlist\n  Copy Playlist: Copy playlist\n  Remove Watched Videos: Remove watched videos\n  Are you sure you want to delete this playlist? This cannot be undone: Are you sure you want to delete this playlist? This cannot be undone.\n  Add to Favorites: Add to {playlistName}\n  Remove from Favorites: Remove from {playlistName}\n  Enable Quick Bookmark With This Playlist: Enable quick bookmark with this playlist\n  Playlists with Matching Videos: Playlists with matching videos\n  Quick Bookmark Enabled: Quick bookmark enabled\n  Cannot delete the quick bookmark target playlist.: Cannot delete the quick bookmark target playlist.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Are you sure you want to remove 1 duplicate video from this playlist? This cannot be undone. | Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone.\n  Remove Duplicate Videos: Remove Duplicate Videos\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Are you sure you want to remove 1 watched video from this playlist? This cannot be undone. | Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone.\n  Export Playlist: Export This Playlist\n  The playlist has been successfully exported: The playlist has been successfully exported\n  TotalTimePlaylist: 'Total time: {duration}'\n  Export list of URLs: Export list of URLs\nHistory:\n  # On History Page\n  History: 'History'\n  Watch History: 'Watch History'\n  Your history list is currently empty.: 'Your history list is currently empty.'\n  Search bar placeholder: Search in History\n  Empty Search Message: There are no videos in your history that match your search\n  Case Sensitive Search: Case Sensitive Search\n  DateOldestHistory: Date Watched (Oldest)\n  DateNewestHistory: Date Watched (Newest)\nSettings:\n  # On Settings Page\n  Settings: 'Settings'\n  General Settings:\n    General Settings: 'General'\n    Check for Updates: 'Check for updates'\n    Check for Latest Blog Posts: 'Check for latest blog posts'\n    Fallback to Non-Preferred Backend on Failure: 'Revert to non-preferred backend on failure'\n    Enable Search Suggestions: 'Enable search suggestions'\n    Default Landing Page: 'Default landing page'\n    Locale Preference: 'Language preference'\n    Preferred API Backend:\n      Preferred API Backend: 'Preferred API backend'\n      Local API: 'Local API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Video View Type'\n      Grid: 'Grid'\n      List: 'List'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Thumbnail Preference'\n      Default: 'Default'\n      Beginning: 'Beginning'\n      Middle: 'Middle'\n      End: 'End'\n      Blur: Blur\n      Hidden: Hidden\n    Region for Trending: 'Region for trending'\n        #! List countries\n    View all Invidious instance information: View all Invidious instance information\n    System Default: System default\n    Clear Default Instance: Clear default instance\n    Set Current Instance as Default: Set current instance as default\n    Current instance will be randomized on startup: Current instance will be randomised on Startup\n    No default instance has been set: No default instance has been set\n    The currently set default instance is {instance}: The currently set default instance is {instance}\n    Current Invidious Instance: Current Invidious Instance\n    External Link Handling:\n      No Action: No action\n      Ask Before Opening Link: Ask before opening link\n      Open Link: Open link\n      External Link Handling: External link handling\n    Auto Load Next Page:\n      Label: Auto load next page\n      Tooltip: Load additional pages and comments automatically.\n    Open Deep Links In New Window: Open URLs Passed to FreeTube in a New Window\n    Minimize to system tray: Minimise to system tray\n  Theme Settings:\n    Theme Settings: 'Theme'\n    Match Top Bar with Main Color: 'Match top bar with main colour'\n    Base Theme:\n      Base Theme: 'Base theme'\n      Black: 'Black'\n      Dark: 'Dark'\n      System Default: 'System default'\n      Light: 'Light'\n      Dracula: 'Dracula'\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastel pink\n      Hot Pink: Hot pink\n      Nordic: Nordic\n      Solarized Dark: Solarised Dark\n      Solarized Light: Solarised Light\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Light\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Medium: Everforest Dark Medium\n      Everforest Dark Low: Everforest Dark Low\n      Everforest Dark Hard: Everforest Dark Hard\n      Everforest Light Hard: Everforest Light Hard\n      Everforest Light Medium: Everforest Light Medium\n      Everforest Light Low: Everforest Light Low\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Main colour theme'\n      Red: 'Red'\n      Pink: 'Pink'\n      Purple: 'Purple'\n      Deep Purple: 'Deep Purple'\n      Indigo: 'Indigo'\n      Blue: 'Blue'\n      Light Blue: 'Light Blue'\n      Cyan: 'Cyan'\n      Teal: 'Teal'\n      Green: 'Green'\n      Light Green: 'Light Green'\n      Lime: 'Lime'\n      Yellow: 'Yellow'\n      Amber: 'Amber'\n      Orange: 'Orange'\n      Deep Orange: 'Deep Orange'\n      Dracula Cyan: 'Dracula Cyan'\n      Dracula Green: 'Dracula Green'\n      Dracula Orange: 'Dracula Orange'\n      Dracula Pink: 'Dracula Pink'\n      Dracula Purple: 'Dracula Purple'\n      Dracula Red: 'Dracula Red'\n      Dracula Yellow: 'Dracula Yellow'\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach\n      Catppuccin Mocha Red: Catppuccin Mocha Red\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Green: Catppuccin Mocha Green\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow\n      Solarized Yellow: Solarised Yellow\n      Solarized Magenta: Solarised Magenta\n      Solarized Cyan: Solarised Cyan\n      Solarized Violet: Solarised Violet\n      Solarized Red: Solarised Red\n      Solarized Orange: Solarised Orange\n      Solarized Blue: Solarised Blue\n      Solarized Green: Solarised Green\n      Gruvbox Dark Green: Gruvbox Dark Green\n      Gruvbox Dark Yellow: Gruvbox Dark Yellow\n      Gruvbox Dark Blue: Gruvbox Dark Blue\n      Gruvbox Light Red: Gruvbox Light Red\n      Gruvbox Light Blue: Gruvbox Light Blue\n      Gruvbox Light Purple: Gruvbox Light Purple\n      Gruvbox Dark Purple: Gruvbox Dark Purple\n      Gruvbox Dark Aqua: Gruvbox Dark Aqua\n      Gruvbox Light Orange: Gruvbox Light Orange\n      Gruvbox Dark Orange: Gruvbox Dark Orange\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maroon\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Red\n      Catppuccin Frappe Sky: Catppuccin Frappe Sky\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Sapphire\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Green: Catppuccin Frappe Green\n      Everforest Dark Red: Everforest Dark Red\n      Everforest Dark Yellow: Everforest Dark Yellow\n      Everforest Light Orange: Everforest Light Orange\n      Everforest Light Blue: Everforest Light Blue\n      Everforest Light Purple: Everforest Light Purple\n      Everforest Light Green: Everforest Light Green\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Dark Blue\n      Everforest Dark Purple: Everforest Dark Purple\n      Everforest Light Yellow: Everforest Light Yellow\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Dark Green: Everforest Dark Green\n      Everforest Dark Orange: Everforest Dark Orange\n      Everforest Light Red: Everforest Light Red\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n    Secondary Color Theme: 'Secondary colour theme'\n        #* Main Color Theme\n    UI Scale: UI Scale\n    Disable Smooth Scrolling: Disable smooth scrolling\n    Expand Side Bar by Default: Expand side bar by default\n    Hide Side Bar Labels: Hide side bar labels\n    Hide FreeTube Header Logo: Hide FreeTube header logo\n  Player Settings:\n    Player Settings: 'Player'\n    Play Next Video: 'Autoplay Recommended Videos'\n    Turn on Subtitles by Default: 'Enable Subtitles by Default'\n    Autoplay Videos: 'Start Videos Automatically'\n    Proxy Videos Through Invidious: 'Proxy Videos Through Invidious'\n    Autoplay Playlists: 'Autoplay Playlist Videos'\n    Enable Theatre Mode by Default: 'Enable Theatre Mode by Default'\n    Scroll Volume Over Video Player: 'Scroll Volume Over Video Player'\n    Default Volume: 'Default volume'\n    Default Playback Rate: 'Default playback rate'\n    Default Video Format:\n      Default Video Format: 'Default video format'\n      Dash Formats: 'DASH formats'\n      Legacy Formats: 'Legacy formats'\n      Audio Formats: 'Audio formats'\n    Default Quality:\n      Default Quality: 'Default quality'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Autoplay Countdown Timer\n    Display Play Button In Video Player: Display play button in video player\n    Enter Fullscreen on Display Rotate: Enter fullscreen on display rotate\n    Fast-Forward / Rewind Interval: Fast-forward / rewind interval\n    Scroll Playback Rate Over Video Player: Scroll playback rate over video player\n    Video Playback Rate Interval: Video playback rate interval\n    Max Video Playback Rate: Max video playback rate\n    Screenshot:\n      File Name Tooltip: You can use variables below. %Y Year 4 digits. %M Month 2 digits. %D Day 2 digits. %H Hour 2 digits. %N Minute 2 digits. %S Second 2 digits. %T Millisecond 3 digits. %s Video Second. %t Video Millisecond 3 digits. %i Video ID.\n      Error:\n        Forbidden Characters: Forbidden characters\n        Empty File Name: Empty file name\n      Folder Button: Select folder\n      Enable: Enable screenshot\n      Quality Label: Screenshot quality\n      Folder Label: Screenshot folder\n      Format Label: Screenshot format\n      Ask Path: Ask for Save Folder\n      File Name Label: Filename pattern\n    Skip by Scrolling Over Video Player: Skip by scrolling over video player\n    Autoplay Interruption Timer: Autoplay Interruption Timer\n    Default Viewing Mode:\n      Default Viewing Mode: Default Viewing Mode\n      Full Screen: Full Screen\n      Picture in Picture: Picture in Picture\n      External Player: External Player ({externalPlayerName})\n      Theater: Cinema\n  External Player Settings:\n    External Player Settings: External Player\n    External Player: External Player\n    Ignore Unsupported Action Warnings: Ignore Unsupported Action Warnings\n    Ignore Default Arguments: Ignore Default Arguments\n    Custom External Player Executable: Custom External Player Executable\n    Custom External Player Arguments: Custom External Player Arguments\n    Players:\n      None:\n        Name: None\n  Privacy Settings:\n    Privacy Settings: 'Privacy'\n    Remember History: 'Remember Watch History'\n    Remember Search History: 'Remember Search History'\n    Save Watched Progress: 'Save Watched Progress'\n    Clear Search Cache: 'Clear Search Cache'\n    Are you sure you want to clear out your search cache?: 'Are you sure you want to clear out your search cache?'\n    Search cache has been cleared: 'Search cache has been cleared'\n    Remove Watch History: 'Remove Watch History'\n    Are you sure you want to remove your entire watch history?: 'Are you sure you want to remove your entire watch history?'\n    Watch history has been cleared: 'Watch history has been cleared'\n    Remove All Subscriptions / Profiles: 'Remove All Subscriptions / Profiles'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.'\n    Save Watched Videos With Last Viewed Playlist: Save Watched Videos With Last Viewed Playlist\n    Remove All Playlists: Remove all playlists\n    All playlists have been removed: All playlists have been removed\n    Are you sure you want to remove all your playlists?: Are you sure you want to remove all your playlists?\n    Are you sure you want to clear out your search history and cache?: Are you sure you want to clear out your search history and cache?\n    Clear Search History and Cache: Clear Search History and Cache\n    Search history and cache have been cleared: Search history and cache have been cleared\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Auto\n        Never: Never\n        Semi-auto: Semi-auto\n      Tooltip: Auto = Save on every video page exit, when video ended and error encountered (e.g. ratelimited and watch session expired). Semi-auto = Like Auto except on video page exit and can save progress manually via a button called Save Watched Progress, located beneath the video player.\n  Subscription Settings:\n    Subscription Settings: 'Subscription'\n    Fetch Feeds from RSS: 'Fetch feeds from RSS'\n    Fetch Automatically: Fetch feed automatically\n    Confirm Before Unsubscribing: Confirm before unsubscribing\n    'Limit the number of videos displayed for each channel': Limit the number of videos displayed for each channel\n    To: To\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Select export type'\n    Import Subscriptions: 'Import subscriptions'\n    Export Subscriptions: 'Export Subscriptions'\n    Export FreeTube: 'Export FreeTube'\n    Export YouTube: 'Export YouTube'\n    Export NewPipe: 'Export NewPipe'\n    Import History: 'Import history'\n    Export History: 'Export history'\n    Profile object has insufficient data, skipping item: 'Profile object has insufficient data, skipping item'\n    All subscriptions and profiles have been successfully imported: 'All subscriptions and profiles have been successfully imported'\n    All subscriptions have been successfully imported: 'All subscriptions have been successfully imported'\n    Invalid subscriptions file: 'Invalid subscriptions file'\n    Invalid history file: 'Invalid history file'\n    Subscriptions have been successfully exported: 'Subscriptions have been successfully exported'\n    History object has insufficient data, skipping item: 'History object has insufficient data, skipping item'\n    All watched history has been successfully imported: 'All watched history has been successfully imported'\n    All watched history has been successfully exported: 'All watched history has been successfully exported'\n    Unable to read file: 'Unable to read file'\n    Unable to write file: 'Unable to write file'\n    Unknown data key: 'Unknown data key'\n    How do I import my subscriptions?: 'How do I import my subscriptions?'\n    Manage Subscriptions: Manage Subscriptions\n    Import Playlists: Import playlists\n    Export Playlists: Export playlists\n    Playlist insufficient data: Insufficient data for ‘{playlist}’ playlist, skipping item\n    All playlists has been successfully imported: All playlists has been successfully imported\n    All playlists has been successfully exported: All playlists has been successfully exported\n    Playlist File: Playlist file\n    Subscription File: Subscription file\n    History File: History file\n    Export Playlists For Older FreeTube Versions:\n      Label: Export playlists for older FreeTube versions\n      Tooltip: \"This option exports videos from all playlists into one playlist named ‘Favourites’.\\nHow to export and import videos in playlists for an older version of FreeTube:\\n1. Export your playlists with this option enabled.\\n2. Delete all of your existing playlists using the Remove All playlists option under Privacy settings.\\n3. Launch the older version of FreeTube and import the exported playlists.’\"\n\n    Search history file: Search history file\n    Search history: Search history\n    Import search history: Import search history\n    Export search history: Export search history\n    All search history has been successfully imported: All search history has been successfully imported\n    All search history has been successfully exported: All search history has been successfully exported\n  Distraction Free Settings:\n    Hide Live Chat: Hide Live Chat\n    Hide Popular Videos: Hide Popular Videos\n    Hide Trending Videos: Hide Trending Videos\n    Hide Recommended Videos: Hide Recommended Videos\n    Hide Comment Likes: Hide Comment Likes\n    Hide Channel Subscribers: Hide Channel Subscribers\n    Hide Video Likes And Dislikes: Hide Video Likes And Dislikes\n    Hide Video Views: Hide Video Views\n    Hide Active Subscriptions: Hide Active Subscriptions\n    Distraction Free Settings: Distraction Free\n    Hide Playlists: Hide Playlists\n    Hide Comments: Hide comments\n    Hide Video Description: Hide video description\n    Hide Live Streams: Hide live streams\n    Hide Upcoming Premieres: Hide Upcoming Premieres\n    Hide Sharing Actions: Hide sharing actions\n    Hide Videos on Watch: 'Hide Videos on Watch'\n    Hide Chapters: Hide chapters\n    Hide Channels: Hide videos from channels\n    Hide Channels Placeholder: Channel ID\n    Display Titles Without Excessive Capitalisation: Display titles without excessive capitalisation and punctuation\n    Hide Featured Channels: Hide featured channels\n    Hide Channel Playlists: Hide channel \"playlists\" tab\n    Hide Channel Posts: Hide channel \"Posts\" tab\n    Hide Channel Shorts: Hide channel \"shorts\" tab\n    Sections:\n      Side Bar: Side bar\n      General: General\n      Channel Page: Channel Page\n      Watch Page: Watch Page\n      Subscriptions Page: Subscriptions page\n    Hide Channel Podcasts: Hide channel \"podcasts\" tab\n    Hide Channel Releases: Hide channel \"releases\" tab\n    Hide Subscriptions Shorts: Hide subscriptions shorts\n    Hide Subscriptions Live: Hide subscriptions live\n    Hide Subscriptions Videos: Hide subscriptions videos\n    Hide Subscriptions Posts: Hide subscriptions Posts\n    Hide Profile Pictures in Comments: Hide profile pictures in comments\n    Hide Channels Invalid: Channel ID provided was invalid\n    Hide Channels Disabled Message: Some channels were blocked using ID and weren't processed. Feature is blocked while those IDs are updating\n    Hide Channels Already Exists: Channel ID already exists\n    Hide Channels API Error: Error retrieving user with the ID provided. Please check again if the ID is correct.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Word, word Fragment or phrase\n    Hide Videos, Playlists and Channels Containing Text: Hide videos and playlists containing text\n    Hide Channel Home: Hide Channel \"Home\" Tab\n    Show Added Items: Show Added Items\n    Hide Channel Courses: Hide Channel \"Courses\" Tab\n  The app needs to restart for changes to take effect. Restart and apply change?: The app needs to restart for changes to take effect. Do you want to restart and apply the changes?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Error getting network information. Is your proxy configured properly?\n    City: City\n    Region: Region\n    Country: Country\n    Ip: Ip\n    Your Info: Your Info\n    Test Proxy: Test Proxy\n    Clicking on Test Proxy will send a request to: Clicking on Test Proxy will send a request to\n    Proxy Port Number: Proxy Port Number\n    Proxy Host: Proxy Host\n    Proxy Protocol: Proxy Protocol\n    Enable Tor / Proxy: Enable Tor / Proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube doesn't have a built-in proxy but can connect to an external proxy, such as one running on your machine like Tor or an external proxy such-as a SOCKS5 proxy provided by some VPNs. If enabled, make sure your proxy/Tor is configured properly, or FreeTube won't be able to fetch any data.\n    Proxy Username: Proxy Username\n    Proxy Password: Proxy Password\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notify when sponsor segment is skipped\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API Url (Default is https://sponsor.ajay.app)\n    Enable SponsorBlock: Enable SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Skip option\n      Auto Skip: Auto skip\n      Show In Seek Bar: Show in seek bar\n      Prompt To Skip: Prompt to skip\n      Do Nothing: Do nothing\n    Category Color: Category colour\n    UseDeArrowTitles: Use DeArrow video titles\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Thumbnail Generator API URL (Default is https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Use DeArrow for thumbnails\n  Parental Control Settings:\n    Hide Unsubscribe Button: Hide Unsubscribe button\n    Parental Control Settings: Parental Control\n    Show Family Friendly Only: Show family-friendly only\n    Hide Search Bar: Hide search bar\n    Hide Uploader on Watch page: Hide Uploader on Watch page\n  Experimental Settings:\n    Replace HTTP Cache: Replace HTTP cache\n    Experimental Settings: Experimental\n    Warning: These settings are experimental, they may cause crashes while enabled. Making backups is highly recommended. Use at your own risk!\n  Password Dialog:\n    Password: Password\n    Enter Password To Unlock: Enter password to unlock settings\n  Password Settings:\n    Set Password To Prevent Access: Set a password to prevent access to settings\n    Remove Password: Remove password\n    Password Settings: Password\n    Set Password: Set password\n  Sort Settings Sections (A-Z): Sort settings sections (A-Z)\n  Return to Settings Menu: Return to Settings Menu\nAbout:\n  #On About page\n  About: About\n  Help: Help\n  Donate: Donate\n  Beta: Beta\n  Email: E-mail\n  FAQ: FAQ\n  Credits: Credits\n  Blog: Blog\n  Website: Website\n\n  these people and projects: these people and projects\n  Translate: Translate\n  room rules: room rules\n  Chat on Matrix: Chat on Matrix\n  Mastodon: Mastodon\n  Please check for duplicates before posting: Please check for duplicates before posting\n  GitHub issues: GitHub issues\n  Report a problem: Report a problem\n  FreeTube Wiki: FreeTube Wiki\n  GitHub releases: GitHub releases\n  Downloads / Changelog: Downloads / Changelog\n  Source code: Source code\n  Discussions: Discussions\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licensed under the {licenseLink}\n  Please read the {roomRulesLink}: Please read the {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube is made possible by {creditsPageLink}\nProfile:\n  Profile Settings: Profile\n  Profile Select: 'Profile Select'\n  All Channels: 'All Channels'\n  Profile Manager: 'Profile Manager'\n  Create New Profile: 'Create New Profile'\n  Edit Profile: 'Edit Profile'\n  Color Picker: 'Colour Picker'\n  Custom Color: 'Custom colour'\n  Profile Preview: 'Profile Preview'\n  Create Profile: 'Create Profile'\n  Update Profile: 'Update Profile'\n  Make Default Profile: 'Make Default Profile'\n  Delete Profile: 'Delete Profile'\n  Are you sure you want to delete this profile?: 'Are you sure you want to delete this profile?'\n  All subscriptions will also be deleted.: 'All subscriptions will also be deleted.'\n  Your profile name cannot be empty: 'Your profile name cannot be empty'\n  Profile has been created: 'Profile has been created'\n  Profile has been updated: 'Profile has been updated'\n  Your default profile has been set to {profile}: 'Your default profile has been set to {profile}'\n  Removed {profile} from your profiles: 'Removed {profile} from your profiles'\n  Your default profile has been changed to your primary profile: 'Your default profile has been changed to your primary profile'\n  '{profile} is now the active profile': '{profile} is now the active profile'\n  Subscription List: 'Subscription List'\n  Other Channels: 'Other Channels'\n  Select All: 'Select All'\n  Select None: 'Select None'\n  Delete Selected: 'Delete Selected'\n  Add Selected To Profile: 'Add Selected To Profile'\n  No channel(s) have been selected: 'No channel(s) have been selected'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.'\n#On Channel Page\n  Profile Filter: Profile Filter\n  '{number} selected': '{number} selected'\n  Toggle Profile List: Toggle profile list\n  Create Profile Name: Create profile name\n  Profile Name: Profile name\n  Edit Profile Name: Edit profile name\n  Open Profile Dropdown: Open profile dropdown\n  Close Profile Dropdown: Close profile dropdown\nChannel:\n  Subscribe: 'Subscribe'\n  Unsubscribe: 'Unsubscribe'\n  Channel has been removed from your subscriptions: 'Channel has been removed from your subscriptions'\n  Removed subscription from {count} other channel(s): 'Removed subscription from {count} other channel(s)'\n  Added channel to your subscriptions: 'Added channel to your subscriptions'\n  Search Channel: 'Search Channel'\n  Your search results have returned 0 results: 'Your search results have returned 0 results'\n  Videos:\n    Videos: 'Videos'\n    This channel does not currently have any videos: 'This channel does not currently have any videos'\n    Sort Types:\n      Newest: 'Newest'\n      Oldest: 'Oldest'\n      Most Popular: 'Most Popular'\n  Playlists:\n    Playlists: 'Playlists'\n    This channel does not currently have any playlists: 'This channel does not currently have any playlists'\n    Sort Types:\n      Last Video Added: 'Last Video Added'\n      Newest: 'Newest'\n      Oldest: 'Oldest'\n  About:\n    About: 'About'\n    Channel Description: 'Channel Description'\n    Featured Channels: 'Featured Channels'\n    Tags:\n      Tags: Tags\n      Search for: Search for ‘{tag}’\n    Details: Details\n    Joined: Joined\n    Location: Location\n  This channel does not exist: This channel does not exist\n  Channel Tabs: Channel tabs\n  This channel does not allow searching: This channel does not allow searching\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: This channel is age resticted and currently cannot be viewed in FreeTube.\n  Posts:\n    This channel currently does not have any posts: This channel currently does not have any posts\n    Reveal Answers: Reveal answers\n    Hide Answers: Hide answers\n    votes: '{votes} votes'\n    Video hidden by FreeTube: Video hidden by FreeTube\n    View Full Post: View Full Post\n    Viewing Posts Only Supported By Invidious: Viewing Posts is only supported by Invidious. Head to a channel's community tab to view content there without Invidious.\n  Live:\n    This channel does not currently have any live streams: This channel does not currently have any live streams\n    Live: Live\n  Shorts:\n    This channel does not currently have any shorts: This channel does not currently have any shorts\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: This channel does not currently have any podcasts\n  Releases:\n    Releases: Releases\n    This channel does not currently have any releases: This channel does not currently have any releases\n  Home:\n    Home: Home\n    View Playlist: View Playlist\n  Courses:\n    Courses: Courses\n    This channel does not currently have any courses: This channel does not currently have any courses\nVideo:\n  Mark As Watched: 'Mark As Watched'\n  Remove From History: 'Remove From History'\n  Video has been marked as watched: 'Video has been marked as watched'\n  Video has been removed from your history: 'Video has been removed from your history'\n  Open in YouTube: 'Open in YouTube'\n  Copy YouTube Link: 'Copy YouTube Link'\n  Open YouTube Embedded Player: 'Open YouTube Embedded Player'\n  Copy YouTube Embedded Player Link: 'Copy YouTube Embedded Player Link'\n  Open in Invidious: 'Open in Invidious'\n  Copy Invidious Link: 'Copy Invidious Link'\n  Views: 'Views'\n  Loop Playlist: 'Loop Playlist'\n  Shuffle Playlist: 'Shuffle Playlist'\n  Reverse Playlist: 'Reverse Playlist'\n  Previous: 'Previous'\n  Next: 'Next'\n  Watched: 'Watched'\n  Autoplay: 'Autoplay'\n  Starting soon, please refresh the page to check again: 'Starting soon, please refresh the page to check again'\n  # As in a Live Video\n  Live: 'Live'\n  Live Now: 'Live Now'\n  Live Chat: 'Live Chat'\n  Enable Live Chat: 'Enable Live Chat'\n  Live Chat is currently not supported in this build.: 'Live Chat is currently not supported in this build.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Live chat is enabled.  Chat messages will appear here once sent.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Live Chat is currently not supported with the Invidious API.  A direct connection to YouTube is required.'\n  Published:\n    In less than a minute: In less than a minute\n  Published on: 'Published on'\n#& Videos\n  Started streaming on: Started streaming on\n  Streamed on: Streamed on\n  Copy Invidious Channel Link: Copy the link of this Invidious Channel\n  Open Channel in Invidious: Open this Channel in Invidious\n  Copy YouTube Channel Link: Copy the Link of this YouTube Channel\n  Open Channel in YouTube: Open this Channel in YouTube\n  Video has been removed from your saved list: Video has been removed from your saved list\n  Video has been saved: Video has been saved\n  Save Video: Save Video\n  Sponsor Block category:\n    music offtopic: Music offtopic\n    interaction: Interaction\n    self-promotion: Self-promotion\n    outro: Outro\n    intro: Intro\n    sponsor: Sponsor\n    recap: Recap\n    filler: Filler\n  External Player:\n    OpenInTemplate: Open in {externalPlayer}\n    video: video\n    playlist: playlist\n    OpeningTemplate: Opening {videoOrPlaylist} in {externalPlayer}...\n    UnsupportedActionTemplate: '{externalPlayer} does not support: {action}'\n    Unsupported Actions:\n      starting video at offset: starting video at offset\n      setting a playback rate: setting a playback rate\n      opening playlists: opening playlists\n      opening specific video in a playlist (falling back to opening the video): opening specific video in a playlist (falling back to opening the video)\n      reversing playlists: reversing playlists\n      shuffling playlists: shuffling playlists\n      looping playlists: looping playlists\n  Premieres: Premieres\n  Show Super Chat Comment: Show Super Chat comment\n  Scroll to Bottom: Scroll to bottom\n  Upcoming: Upcoming\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Live Chat is unavailable for this stream. It may have been disabled by the uploader.\n  Hide Channel: Hide channel\n  Unhide Channel: Show channel\n  More Options: More options\n  Player:\n    TranslatedCaptionTemplate: '{language} (translated from ‘{originalLanguage}’)'\n    Audio Tracks: Audio tracks\n    Theatre Mode: Theatre mode\n    Exit Theatre Mode: Exit theatre mode\n    Full Window: Full window\n    Exit Full Window: Exit full window\n    Take Screenshot: Take screenshot\n    Show Stats: Show stats\n    Hide Stats: Hide stats\n    Stats:\n      Stats: Stats\n      Video ID: 'Video ID: {videoId}'\n      Media Formats: 'Media formats: {formats}'\n      Resolution: 'Resolution: {width}×{height}{''@''}{frameRate}'\n      Player Dimensions: 'Player dimensions: {width}×{height}'\n      Bitrate: 'Bitrate: {bitrate} kb/s'\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Bandwidth: {bandwidth} kb/s'\n      Buffered: 'Buffered: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Dropped frames: {droppedFrames} / Total frames: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n    You appear to be offline: You appear to be offline.\n    Playback will resume automatically when your connection comes back: Playback will resume automatically when your connection comes back.\n    Skipped segment: 'Skipped {segmentCategory} segment'\n    Autoplay is off: Autoplay is off\n    Autoplay is on: Autoplay is on\n  IP block: YouTube has blocked your IP address from watching videos. Please try switching to a different VPN or proxy.\n  Unlisted: Unlisted\n  MembersOnly: Members-only videos cannot be watched with FreeTube as they require Google login and paid membership to the uploader's channel.\n  AgeRestricted: Age-restricted videos cannot be watched with FreeTube as they require Google login and using an age-verified YouTube account.\n  DeArrow:\n    Show Original Details: Show Original Details\n    Show Modified Details: Show Modified Details\n#& Playlists\n  DRMProtected: DRM protected videos cannot be played in FreeTube, as they require proprietary, closed source components. If you want to watch this video please watch it on the official YouTube website in a DRM enabled web browser.\n  Save Watched Progress: Save Watched Progress\n  Watched Progress Saved: Watched Progress Saved\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Remaining preroll-ad time: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Remaining SABR backoff time: {remindingTimeSeconds}s'\n  Popout Live Chat: Popout Chat\nPlaylist:\n  #& About\n  Playlist: Playlist\n  View Full Playlist: 'View full playlist'\n  Last Updated On: 'Last updated on'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    DateAddedNewest: Date added (Newest)\n    VideoTitleDescending: Title (Z-A)\n    Custom: Custom\n    DateAddedOldest: Date added (Oldest)\n    AuthorAscending: Author (A-Z)\n    AuthorDescending: Author (Z-A)\n    VideoTitleAscending: Title (A-Z)\n    VideoDurationAscending: Duration (Shortest)\n    VideoDurationDescending: Duration (Longest)\n    PublishedNewest: Date published (Newest)\n    PublishedOldest: Date published (Oldest)\nChange Format:\n  Change Media Formats: 'Change Media Formats'\n  Use Dash Formats: 'Use DASH Formats'\n  Use Legacy Formats: 'Use Legacy Formats'\n  Use Audio Formats: 'Use Audio Formats'\n  Dash formats are not available for this video: 'DASH formats are not available for this video'\n  Audio formats are not available for this video: 'Audio formats are not available for this video'\n  Legacy formats are not available for this video: Legacy formats are not available for this video\nShare:\n  Share Video: 'Share Video'\n  Share Channel: 'Share Channel'\n  Share Playlist: 'Share Playlist'\n  Include Timestamp: 'Include Timestamp'\n  Copy Link: 'Copy Link'\n  Open Link: 'Open Link'\n  Copy Embed: 'Copy Embed'\n  Open Embed: 'Open Embed'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL copied to clipboard'\n  Invidious Embed URL copied to clipboard: 'Invidious Embed URL copied to clipboard'\n  YouTube URL copied to clipboard: 'YouTube URL copied to clipboard'\n  YouTube Embed URL copied to clipboard: 'YouTube Embed URL copied to clipboard'\n  YouTube Channel URL copied to clipboard: YouTube Channel URL copied to clipboard\n  Invidious Channel URL copied to clipboard: Invidious Channel URL copied to clipboard\n  Share Post: Share Post\nMini Player: 'Mini Player'\nComments:\n  Comments: 'Comments'\n  Click to View Comments: 'Click to View Comments'\n  Getting comment replies, please wait: 'Getting comment replies, please wait'\n  There are no more comments for this video: 'There are no more comments for this video'\n  Hide Comments: 'Hide Comments'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'There are no comments available for this video'\n  Load More Comments: 'Load More Comments'\n  Newest first: Newest First\n  Top comments: Top comments\n  Show More Replies: Show more replies\n  Pinned by: Pinned by\n  Member: Member\n  Hearted: Hearted\n  View {replyCount} replies: View 1 reply | View {replyCount} replies\n  Subscribed: Subscribed\n  There are no comments available for this post: There are no comments available for this post\n  Hide {replyCount} replies: Hide 1 reply | Hide {replyCount} replies\n  View 1 reply from {channelName}: View 1 reply from {channelName}\n  View {replyCount} replies from {channelName} and others: View {replyCount} replies from {channelName} and others\nUp Next: 'Up Next'\nDescription:\n  Expand Description: '...more'\n  Collapse Description: Show less\n\n# Toast Messages\nLocal API Error (Click to copy): 'Local API Error (Click to copy)'\nInvidious API Error (Click to copy): 'Invidious API Error (Click to copy)'\nFalling back to Invidious API: 'Falling back to Invidious API'\nFalling back to Local API: 'Falling back to Local API'\nLoop is now disabled: 'Loop is now disabled'\nLoop is now enabled: 'Loop is now enabled'\nShuffle is now disabled: 'Shuffle is now disabled'\nShuffle is now enabled: 'Shuffle is now enabled'\nThe playlist has been reversed: 'The playlist has been reversed'\nPlaying Next Video: 'Playing Next Video'\nPlaying Previous Video: 'Playing Previous Video'\nCanceled next video autoplay: 'Cancelled next video autoplay'\n'The playlist has ended. Enable loop to continue playing': 'The playlist has ended.  Enable loop to continue playing'\n\nYes: 'Yes'\nNo: 'No'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: This video is unavailable because of missing formats. This can happen due to country unavailability.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: When enabled, FreeTube will use RSS instead of its default method to grab your subscription feed. RSS is faster and prevents IP blocking, but it doesn’t provide certain information like video duration, live status or posts\n    Fetch Automatically: When enabled, FreeTube will automatically fetch your subscription feed on startup and when a new window is opened.\n  Player Settings:\n    Default Video Format: Set the formats used when a video plays. DASH formats can play higher qualities. Legacy formats are limited to a max of 360p but use less bandwidth. Audio formats are audio only streams.\n    Proxy Videos Through Invidious: Will connect to Invidious to serve videos instead of making a direct connection to YouTube.\n    Scroll Playback Rate Over Video Player: While the cursor is over the video, press and hold the Control key (Command Key on Mac) and scroll the mouse wheel forwards or backwards to control the playback rate. Press and hold the Control key (Command Key on Mac) and left click the mouse to quickly return to the default playback rate (1x unless it has been changed in the settings).\n    Skip by Scrolling Over Video Player: Use the scroll wheel to skip through the video, MPV style.\n  General Settings:\n    Region for Trending: The region of trends allows you to pick which country’s trending videos you want to have displayed.\n    Invidious Instance: The Invidious instance that FreeTube will connect to for API calls.\n    Thumbnail Preference: All thumbnails throughout FreeTube will be replaced with a frame of the video, blurred or hidden instead of the default thumbnail.\n    Fallback to Non-Preferred Backend on Failure: When your preferred API has a problem, FreeTube will automatically attempt to use your non-preferred API as a fallback method when enabled.\n    Preferred API Backend: Choose the back-end that FreeTube uses to obtain data. The local API is a built-in extractor. The Invidious API requires an Invidious server to connect to.\n    External Link Handling: \"Choose the default behaviour when a link, which cannot be opened in FreeTube, is clicked.\\nBy default FreeTube will open the clicked link in your default browser.\\n\"\n    Open Deep Links In New Window: URLs passed to FreeTube, such as by redirect browser extensions or command line arguments, are opened in a new window.\n  External Player Settings:\n    External Player: Choosing an external player will display an icon, for opening the video (playlist if supported) in the external player, on the thumbnail. Warning, Invidious settings do not affect external players.\n    Custom External Player Executable: By default, FreeTube will assume that the chosen external player can be found via the PATH environment variable. If needed, a custom path can be set here.\n    Ignore Warnings: Suppress warnings for when the current external player does not support the current action (e.g. reversing playlists, etc.).\n    Ignore Default Arguments: Do not send any default arguments to the external player aside from the video URL (e.g. playback rate, playlist URL, etc.). Custom arguments will still be passed on.\n    Custom External Player Arguments: Any custom command line arguments you want to be passed on to the external player.\n    DefaultCustomArgumentsTemplate: '(Default: ‘{defaultCustomArguments}’)'\n  Experimental Settings:\n    Replace HTTP Cache: Disables Electron's disk-based HTTP cache and enables a custom in-memory image cache. Will lead to increased RAM usage.\n  Distraction Free Settings:\n    Hide Channels: Enter a channel ID to hide all videos, playlists and the channel itself from appearing in search, trending, most popular and recommended. The channel ID entered must be a complete match and is case sensitive.\n    Hide Subscriptions Live: This setting is overridden by the app-wide ‘{appWideSetting}’ setting, in the ‘{subsection}’ section of the ‘{settingsSection}’\n    Hide Videos, Playlists and Channels Containing Text: Enter a word, word fragment, or phrase (case insensitive) to hide all videos and playlists whose original titles contain it throughout all of FreeTube, excluding only History, Your playlists, and videos inside of playlists.\n    Hide Videos on Watch: Hides watched videos from the Videos, Shorts, and Live tabs on the Subscription and Channel pages. This does not affect the Home tab on Channel pages\n  SponsorBlock Settings:\n    UseDeArrowTitles: Replace video titles with user-submitted titles from DeArrow.\n    UseDeArrowThumbnails: Replace video thumbnails with thumbnails from DeArrow.\nPlaying Next Video Interval: Playing next video in no time. Click to cancel. | Playing next video in {nextVideoInterval} second. Click to cancel. | Playing next video in {nextVideoInterval} seconds. Click to cancel.\nMore: More\nUnknown YouTube url type, cannot be opened in app: Unknown YouTube url type, cannot be opened in app\nOpen New Window: Open New Window\nDefault Invidious instance has been cleared: Default Invidious instance has been cleared\nDefault Invidious instance has been set to {instance}: Default Invidious instance has been set to {instance}\nSearch Bar:\n  Clear Input: Clear input\n  Remove: Remove\nExternal link opening has been disabled in the general settings: External link opening has been disabled in the general settings\nAre you sure you want to open this link?: Are you sure you want to open this link?\nScreenshot Error: Screenshot failed. {error}\nScreenshot Success: Saved screenshot\nNew Window: New window\nChannels:\n  Empty: Your channel list is currently empty.\n  Unsubscribe Prompt: Are you sure you want to Unsubscribe from ‘{channelName}’?\n  Title: Channel list\n  Search bar placeholder: Search channels\n  Channels: Channels\n  Count: '{number} channel(s) found.'\nAge Restricted:\n  This channel is age restricted: This channel is age restricted\n  This video is age restricted: This video is age restricted\nChapters:\n  Chapters: Chapters\n  Key Moments: Key Moments\nClipboard:\n  Copy failed: Copy to clipboard failed\n  Cannot access clipboard without a secure connection: Cannot access clipboard without a secure connection\nPreferences: Preferences\nOk: Ok\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: This hashtag does not currently have any videos\nGo to page: Go to {page}\nTag already exists: ‘{tagName}’ tag already exists\nClose Banner: Close Banner\nChannel Hidden: '{channel} added to channel filter'\nChannel Unhidden: '{channel} removed from channel filter'\nTrimmed input must be at least N characters long: Trimmed input must be at least 1 character long | Trimmed input must be at least {length} characters long\nYes, Delete: Yes, delete\nYes, Restart: Yes, restart\nYes, Open Link: Yes, open link\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Subtitles\n    Closed Captions: Closed Captions\n    8K: 8K\n    3D: 3D\n    VR180: VR180\n    360 Video: 360°\n    New: New\nSearch character limit: Search query is over the {searchCharacterLimit} character limit\nFeed:\n  Feed Last Updated: '{feedName} feed last updated: {date}'\n  Refresh Feed: Refresh {subscriptionName}\nCancel: Cancel\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nMoments Ago: moments ago\nKeys:\n  arrowup: Up Arrow\n  arrowleft: Left Arrow\n  arrowright: Right Arrow\n  ctrl: Ctrl\n  alt: Alt\n  arrowdown: Down Arrow\n  enter: Enter\n  shift: Shift\n  plus: Plus\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: Right-click or hold to see history\nAutoplay Interruption Timer: Autoplay cancelled due to {autoplayInterruptionIntervalHours} hours of inactivity\nKeyboardShortcutPrompt:\n  Zoom Out: Zoom out\n  Volume Down: Decrease volume\n  Decrease Video Speed: Decrease video speed based on Video Playback Rate Interval\n  Small Fast Forward: Fast-Forward X seconds based on the Fast-Forward Interval and current Video Playback Rate\n  Small Rewind: Rewind X seconds based on the Rewind Interval and current Video Playback Rate\n  Focus Secondary Search: Focus on the secondary search bar (if one is present)\n  Captions: Toggle captions ON/OFF\n  Fullscreen: Toggle fullscreen\n  Large Fast Forward: Forward 10 seconds / Fast-Forward video based on current Video Playback Rate\n  Mute: Toggle mute\n  Next Frame: Next frame (while paused)\n  Toggle Developer Tools: Toggle developer tools\n  Reset Zoom: Reset zoom level / UI scale\n  Zoom In: Zoom in\n  Increase Video Speed: Increase video speed based on Video Playback Rate Interval\n  Take Screenshot: Take screenshot\n  Full Window: Toggle full window\n  Theatre Mode: Toggle cinema mode\n  Minimize Window: Minimise window\n  Close Window: Close window\n  Search in New Window: Search in a new window\n  Next Chapter: Next Chapter\n  Skip by Tenths: Skip through video by percentage (3 skips to 30% of duration)\n  Play: Toggle play/pause\n  Keyboard Shortcuts: Keyboard Shortcuts\n  Sections:\n    Video:\n      Playback: Video: Playback\n      General: Video: General\n    App:\n      Situational: 'App: Situational'\n      General: App: General\n  Show Keyboard Shortcuts: Show keyboard shortcuts\n  History Backward: Go back one page\n  History Forward: Go forward one page\n  New Window: Create a new window\n  Navigate to Settings: Navigate to the Settings page\n  Navigate to History: Navigate to the History page\n  Refresh: Refresh feed with latest content\n  Large Rewind: Rewind 10 seconds / Rewind video based on current Video Playback Rate\n  Volume Up: Increase volume\n  Picture in Picture: Toggle Picture-in-Picture mode\n  Last Frame: Previous frame (while paused)\n  Stats: Show video statistics\n  Focus Search: Focus on the search bar\n  Last Chapter: Last Chapter\n  Home: Seek to the beginning of the video\n  End: Seek to the end of the video\n  Skip to Next Video: Skip to the next video in a playlist or next recommended video\n  Skip to Previous Video: Skip to the previous video in a playlist\nshortcutLabelSeparator: ｜\nCompact side navigation: Compact side navigation\nExpand side navigation: Expand side navigation\n"
  },
  {
    "path": "static/locales/en-US.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: English (US)\n\n# Webkit Menu Bar\nFile: File\nNew Window: New Window\nPreferences: Preferences\nQuit: Quit\nEdit: Edit\nUndo: Undo\nRedo: Redo\nCut: Cut\nCopy: Copy\nPaste: Paste\nDelete: Delete\nSelect all: Select all\nToggle Developer Tools: Toggle Developer Tools\nActual size: Actual size\nZoom in: Zoom in\nZoom out: Zoom out\nToggle fullscreen: Toggle fullscreen\nWindow: Window\nMinimize: Minimize\nClose: Close\nCompact side navigation: Compact side navigation\nExpand side navigation: Expand side navigation\nBack: Back\nForward: Forward\nRight-click or hold to see history: Right-click or hold to see history\nOpen New Window: Open New Window\nGo to page: Go to {page}\nClose Banner: Close Banner\n\nVersion {versionNumber} is now available!  Click for more details: Version {versionNumber} is now available!  Click\n  for more details\nDownload From Site: Download From Site\nA new blog is now available, {blogTitle}. Click to view more: A new blog is now available, {blogTitle}.\n  Click to view more\nAre you sure you want to open this link?: Are you sure you want to open this link?\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: Videos\n  Shorts: Shorts\n  Live: Live\n  Posts: Posts\n  Sort By: Sort By\n  Counts:\n    Video Count: 1 video | {count} videos\n    Channel Count: 1 channel | {count} channels\n    Subscriber Count: 1 subscriber | {count} subscribers\n    View Count: 1 view | {count} views\n    Like Count: 1 like | {count} likes\n    Comment Count: 1 comment | {count} comments\n    Watching Count: 1 watching | {count} watching\n\n# Search Bar\nSearch / Go to URL: Search / Go to URL\nSearch Bar:\n  Clear Input: Clear Input\n  Remove: Remove\nSearch character limit: Search query is over the {searchCharacterLimit} character limit\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    Subtitles: Subtitles\n    New: New\n    3D: 3D\n    # Aria labels\n    Closed Captions: Closed Captions\n  # In Filter Button\nSearch Filters:\n  Search Filters: Search Filters\n  Sort By:\n    Most Relevant: Most Relevant\n    Rating: Rating\n    Upload Date: Upload Date\n    View Count: View Count\n  Time:\n    Time: Time\n    Any Time: Any Time\n    Last Hour: Last Hour\n    Today: Today\n    This Week: This Week\n    This Month: This Month\n    This Year: This Year\n  Type:\n    Type: Type\n    All Types: All Types\n    Videos: Videos\n    Channels: Channels\n    Movies: Movies\n    #& Playlists\n  Duration:\n    Duration: Duration\n    All Durations: All Durations\n    Short (< 4 minutes): Short (< 4 minutes)\n    Medium (4 - 20 minutes): Medium (4 - 20 minutes)\n    Long (> 20 minutes): Long (> 20 minutes)\n  Features:\n    Features: Features\n    HD: HD\n    Subtitles: Subtitles\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Live\n    4K: 4K\n    360 Video: 360 Video\n    Location: Location\n    HDR: HDR\n    VR180: VR180\n  # On Search Page\n  Search Results: Search Results\n  Fetching results. Please wait: Fetching results. Please wait\n  Fetch more results: Fetch more results\n  There are no more results for this search: There are no more results for this search\n  Clear Filters: Clear Filters\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: Subscriptions\n  # channels that were likely deleted\n  Error Channels: Channels with Errors\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: This\n    profile has a large number of subscriptions.  Forcing RSS to avoid rate limiting\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': Your Subscription list is currently empty. If you want to import your subscriptions you can go to Data Settings and select Import Subscriptions or you can search for a channel and subscribe to them.\n  Disabled Automatic Fetching: You have disabled automatic subscription fetching. Refresh subscriptions to see them here.\n  Empty Channels: Your subscribed channels currently does not have any videos.\n  Empty Posts: Your subscribed channels currently do not have any posts.\n  Load More Videos: Load More Videos\n  Load More Posts: Load More Posts\n  Subscriptions Tabs: Subscriptions Tabs\n  All Subscription Tabs Hidden: 'All subscription tabs are hidden. To see content here, please unhide some tabs in the \"{subsection}\" section in \"{settingsSection}\".'\nMore: More\nChannels:\n  Channels: Channels\n  Title: Channel List\n  Search bar placeholder: Search Channels\n  Count: '{number} channel(s) found.'\n  Empty: Your channel list is currently empty.\n  Unsubscribe Prompt: Are you sure you want to unsubscribe from \"{channelName}\"?\nTrending:\n  Trending: Trending\n  Gaming: Gaming\n  Sports: Sports\n  Trending Tabs: Trending Tabs\nMost Popular: Most Popular\nFeed:\n  Feed Last Updated: '{feedName} feed last updated: {date}'\n  Refresh Feed: Refresh {subscriptionName}\nPlaylists: Playlists\nUser Playlists:\n  Your Playlists: Your Playlists\n  You have no playlists. Click on the create new playlist button to create a new one.: You have no playlists. Click on the create new playlist button to create a new one.\n  Empty Search Message: There are no videos in this playlist that match your search\n  Search bar placeholder: Search for Playlists\n  Playlists with Matching Videos: Playlists with Matching Videos\n\n  This playlist currently has no videos.: This playlist currently has no videos.\n\n  Create New Playlist: Create New Playlist\n\n  Add to Playlist: Add to Playlist\n  Add to Favorites: Add to {playlistName}\n  Remove from Favorites: Remove from {playlistName}\n\n  Move Video Up: Move Video Up\n  Move Video Down: Move Video Down\n  Remove from Playlist: Remove from Playlist\n\n  Playlist Name: Playlist Name\n  Playlist Description: Playlist Description\n\n  Save Changes: Save Changes\n  Cancel: Cancel\n  Edit Playlist Info: Edit Playlist Info\n  Copy Playlist: Copy Playlist\n  Remove Duplicate Videos: Remove Duplicate Videos\n  Remove Watched Videos: Remove Watched Videos\n  Enable Quick Bookmark With This Playlist: Enable Quick Bookmark With This Playlist\n  Quick Bookmark Enabled: Quick Bookmark Enabled\n  Export Playlist: Export This Playlist\n  Export list of URLs: Export list of URLs\n  The playlist has been successfully exported: The playlist has been successfully exported\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Are you sure you want to remove 1 duplicate video from this playlist? This cannot be undone. | Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Are you sure you want to remove 1 watched video from this playlist? This cannot be undone. | Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone.\n  Delete Playlist: Delete Playlist\n  Cannot delete the quick bookmark target playlist.: Cannot delete the quick bookmark target playlist.\n  Are you sure you want to delete this playlist? This cannot be undone: Are you sure you want to delete this playlist? This cannot be undone.\n\n  TotalTimePlaylist: \"Total time: {duration}\"\n\n  Sort By:\n    NameAscending: 'A-Z'\n    NameDescending: 'Z-A'\n\n    LatestCreatedFirst: 'Date Created (Newest)'\n    EarliestCreatedFirst: 'Date Created (Oldest)'\n\n    LatestUpdatedFirst: 'Date Updated (Newest)'\n    EarliestUpdatedFirst: 'Date Updated (Oldest)'\n\n    LatestPlayedFirst: 'Date Played (Newest)'\n    EarliestPlayedFirst: 'Date Played (Oldest)'\n  SinglePlaylistView:\n    Search for Videos: Search for Videos\n\n    Toast:\n      This video cannot be moved up.: This video cannot be moved up.\n      This video cannot be moved down.: This video cannot be moved down.\n      Video has been removed: Video has been removed\n      Video has been removed. Click here to undo.: Video has been removed. Click here to undo.\n      There was a problem with removing this video: There was a problem with removing this video\n\n      This playlist is already being used for quick bookmark.: This playlist is already being used for quick bookmark.\n      This playlist is now used for quick bookmark: This playlist is now used for quick bookmark\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo\n      Reverted to use {oldPlaylistName} for quick bookmark: Reverted to use {oldPlaylistName} for quick bookmark\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Some videos in the playlist are not loaded yet. Click here to copy anyway.\n      Playlist name cannot be empty. Please input a name.: Playlist name cannot be empty. Please input a name.\n      Playlist has been updated.: Playlist has been updated.\n      There was an issue with updating this playlist.: There was an issue with updating this playlist.\n      \"{videoCount} video(s) have been removed\": \"1 video has been removed | {videoCount} videos have been removed\"\n      There were no videos to remove.: There were no videos to remove.\n      This playlist is protected and cannot be removed.: This playlist is protected and cannot be removed.\n      Playlist {playlistName} has been deleted.: Playlist {playlistName} has been deleted.\n\n      This playlist does not exist: This playlist does not exist\n\n      This playlist has a video with a duration error: This playlist contains at least one video that doesn't have a duration, it will be sorted as if their duration is zero.\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: 'Select a playlist to add your video to | Select a playlist to add your {videoCount} videos to'\n    N playlists selected: '{playlistCount} Selected'\n    Search in Playlists: Search in Playlists\n    Allow Adding Duplicate Video(s): Allow Adding Duplicate Video(s)\n    Save: Save\n\n    Added {count} Times: 'Already Added | Added {count} Times'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videos Will Be Added'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Videos Already Added'\n\n    Toast:\n      You haven't selected any playlist yet.: You haven't selected any playlist yet.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(s) added to 1 playlist | Video(s) added to {playlistCount} playlists\"\n  CreatePlaylistPrompt:\n    New Playlist Name: New Playlist Name\n    Create: Create\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: There is already a playlist with this name. Please pick a different name.\n      Playlist {playlistName} has been successfully created.: Playlist {playlistName} has been successfully created.\n      There was an issue with creating the playlist.: There was an issue with creating the playlist.\nHistory:\n  # On History Page\n  History: History\n  Watch History: Watch History\n  Your history list is currently empty.: Your history list is currently empty.\n  Empty Search Message: There are no videos in your history that match your search\n  Search bar placeholder: \"Search in History\"\n  Case Sensitive Search: Case Sensitive Search\n  DateOldestHistory: Date Watched (Oldest)\n  DateNewestHistory: Date Watched (Newest)\nSettings:\n  # On Settings Page\n  Settings: Settings\n  Sort Settings Sections (A-Z): Sort Settings Sections (A-Z)\n  Return to Settings Menu: Return to Settings Menu\n  The app needs to restart for changes to take effect. Restart and apply change?: The\n    app needs to restart for changes to take effect. Restart and apply change?\n  General Settings:\n    General Settings: General\n    Check for Updates: Check for Updates\n    Check for Latest Blog Posts: Check for Latest Blog Posts\n    Fallback to Non-Preferred Backend on Failure: Fallback to Non-Preferred Backend\n      on Failure\n    Enable Search Suggestions: Enable Search Suggestions\n    Open Deep Links In New Window: Open URLs Passed to FreeTube in a New Window\n    Minimize to system tray: Minimize to system tray\n    Auto Load Next Page:\n      Label: Auto Load Next Page\n      Tooltip: Load additional pages and comments automatically.\n    Default Landing Page: Default Landing Page\n    Locale Preference: Locale Preference\n    System Default: System Default\n    Preferred API Backend:\n      Preferred API Backend: Preferred API Backend\n      Local API: Local API\n      Invidious API: Invidious API\n    Video View Type:\n      Video View Type: Video View Type\n      Grid: Grid\n      List: List\n    Thumbnail Preference:\n      Thumbnail Preference: Thumbnail Preference\n      Default: Default\n      Beginning: Beginning\n      Middle: Middle\n      End: End\n      Hidden: Hidden\n      Blur: Blur\n    Current Invidious Instance: Current Invidious Instance\n    The currently set default instance is {instance}: The currently set default instance is {instance}\n    No default instance has been set: No default instance has been set\n    Current instance will be randomized on startup: Current instance will be randomized on startup\n    Set Current Instance as Default: Set Current Instance as Default\n    Clear Default Instance: Clear Default Instance\n    View all Invidious instance information: View all Invidious instance information\n    Region for Trending: Region for Trending\n    #! List countries\n    External Link Handling:\n      External Link Handling: External Link Handling\n      Open Link: Open Link\n      Ask Before Opening Link: Ask Before Opening Link\n      No Action: No Action\n  Theme Settings:\n    Theme Settings: Theme\n    Match Top Bar with Main Color: Match Top Bar with Main Color\n    Expand Side Bar by Default: Expand Side Bar by Default\n    Disable Smooth Scrolling: Disable Smooth Scrolling\n    UI Scale: UI Scale\n    Hide Side Bar Labels: Hide Side Bar Labels\n    Hide FreeTube Header Logo: Hide FreeTube Header Logo\n    Base Theme:\n      Base Theme: Base Theme\n      Black: Black\n      Dark: Dark\n      System Default: System Default\n      Light: Light\n      Dracula: Dracula\n      Catppuccin Frappe: Catppuccin Frappe\n      Catppuccin Latte: Catppuccin Latte\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastel Pink\n      Hot Pink: Hot Pink\n      Nordic: Nordic\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Light\n      Solarized Dark: Solarized Dark\n      Solarized Light: Solarized Light\n      Everforest Dark Hard: Everforest Dark Hard\n      Everforest Dark Medium: Everforest Dark Medium\n      Everforest Dark Low: Everforest Dark Low\n      Everforest Light Hard: Everforest Light Hard\n      Everforest Light Medium: Everforest Light Medium\n      Everforest Light Low: Everforest Light Low\n    Main Color Theme:\n      Main Color Theme: Main Color Theme\n      Red: Red\n      Pink: Pink\n      Purple: Purple\n      Deep Purple: Deep Purple\n      Indigo: Indigo\n      Blue: Blue\n      Light Blue: Light Blue\n      Cyan: Cyan\n      Teal: Teal\n      Green: Green\n      Light Green: Light Green\n      Lime: Lime\n      Yellow: Yellow\n      Amber: Amber\n      Orange: Orange\n      Deep Orange: Deep Orange\n      Dracula Cyan: Dracula Cyan\n      Dracula Green: Dracula Green\n      Dracula Orange: Dracula Orange\n      Dracula Pink: Dracula Pink\n      Dracula Purple: Dracula Purple\n      Dracula Red: Dracula Red\n      Dracula Yellow: Dracula Yellow\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Red\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maroon\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow\n      Catppuccin Frappe Green: Catppuccin Frappe Green\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Sky: Catppuccin Frappe Sky\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Sapphire\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Red: Catppuccin Mocha Red\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow\n      Catppuccin Mocha Green: Catppuccin Mocha Green\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender\n      Gruvbox Dark Green: Gruvbox Dark Green\n      Gruvbox Dark Yellow: Gruvbox Dark Yellow\n      Gruvbox Dark Blue: Gruvbox Dark Blue\n      Gruvbox Dark Purple: Gruvbox Dark Purple\n      Gruvbox Dark Aqua: Gruvbox Dark Aqua\n      Gruvbox Dark Orange: Gruvbox Dark Orange\n      Gruvbox Light Red: Gruvbox Light Red\n      Gruvbox Light Blue: Gruvbox Light Blue\n      Gruvbox Light Purple: Gruvbox Light Purple\n      Gruvbox Light Orange: Gruvbox Light Orange\n      Solarized Yellow: Solarized Yellow\n      Solarized Orange: Solarized Orange\n      Solarized Red: Solarized Red\n      Solarized Magenta: Solarized Magenta\n      Solarized Violet: Solarized Violet\n      Solarized Blue: Solarized Blue\n      Solarized Cyan: Solarized Cyan\n      Solarized Green: Solarized Green\n      Everforest Dark Red: Everforest Dark Red\n      Everforest Dark Orange: Everforest Dark Orange\n      Everforest Dark Yellow: Everforest Dark Yellow\n      Everforest Dark Green: Everforest Dark Green\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Dark Blue\n      Everforest Dark Purple: Everforest Dark Purple\n      Everforest Light Red: Everforest Light Red\n      Everforest Light Orange: Everforest Light Orange\n      Everforest Light Yellow: Everforest Light Yellow\n      Everforest Light Green: Everforest Light Green\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Light Blue: Everforest Light Blue\n      Everforest Light Purple: Everforest Light Purple\n    Secondary Color Theme: Secondary Color Theme\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: Player\n    Play Next Video: Autoplay Recommended Videos\n    Autoplay Playlists: Autoplay Playlist Videos\n    Autoplay Videos: Start Videos Automatically\n    Turn on Subtitles by Default: Enable Subtitles by Default\n    Proxy Videos Through Invidious: Proxy Videos Through Invidious\n    Default Viewing Mode:\n      Theater: Theater\n      Default Viewing Mode: Default Viewing Mode\n      Full Screen: Full Screen\n      Picture in Picture: Picture in Picture\n      External Player: External Player ({externalPlayerName})\n    Scroll Volume Over Video Player: Scroll Volume Over Video Player\n    Scroll Playback Rate Over Video Player: Scroll Playback Rate Over Video Player\n    Skip by Scrolling Over Video Player: Skip by Scrolling Over Video Player\n    Display Play Button In Video Player: Display Play Button In Video Player\n    Enter Fullscreen on Display Rotate: Enter Fullscreen on Display Rotate\n    Next Video Interval: Autoplay Countdown Timer\n    Autoplay Interruption Timer: Autoplay Interruption Timer\n    Fast-Forward / Rewind Interval: Fast-Forward / Rewind Interval\n    Default Volume: Default Volume\n    Default Playback Rate: Default Playback Rate\n    Max Video Playback Rate: Max Video Playback Rate\n    Video Playback Rate Interval: Video Playback Rate Interval\n    Default Video Format:\n      Default Video Format: Default Video Format\n      Dash Formats: DASH Formats\n      Legacy Formats: Legacy Formats\n      Audio Formats: Audio Formats\n    Default Quality:\n      Default Quality: Default Quality\n      Auto: Auto\n      144p: 144p\n      240p: 240p\n      360p: 360p\n      480p: 480p\n      720p: 720p\n      1080p: 1080p\n      1440p: 1440p\n      4k: 4k\n      8k: 8k\n    Screenshot:\n      Enable: Enable Screenshot\n      Format Label: Screenshot Format\n      Quality Label: Screenshot Quality\n      Ask Path: Ask for Save Folder\n      Folder Label: Screenshot Folder\n      Folder Button: Select Folder\n      File Name Label: Filename Pattern\n      File Name Tooltip: You can use variables below. %Y Year 4 digits. %M Month 2 digits.\n        %D Day 2 digits. %H Hour 2 digits. %N Minute 2 digits. %S Second 2 digits. %T Millisecond 3 digits.\n        %s Video Second. %t Video Millisecond 3 digits. %i Video ID.\n      Error:\n        Forbidden Characters: Forbidden Characters\n        Empty File Name: Empty File Name\n  External Player Settings:\n    External Player Settings: External Player\n    External Player: External Player\n    Ignore Unsupported Action Warnings: Ignore Unsupported Action Warnings\n    Ignore Default Arguments: Ignore Default Arguments\n    Custom External Player Executable: Custom External Player Executable\n    Custom External Player Arguments: Custom External Player Arguments\n    Players:\n      None:\n        Name: None\n  Privacy Settings:\n    Privacy Settings: Privacy\n    Remember History: Remember Watch History\n    Remember Search History: Remember Search History\n    Save Watched Progress: Save Watched Progress\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Auto\n        Semi-auto: Semi-auto\n        Never: Never\n      Tooltip:\n        Auto = Save on every video page exit, when video ended and error encountered (e.g. ratelimited and watch session expired). Semi-auto = Like Auto except on video page exit and can save progress manually via a button called Save Watched Progress, located beneath the video player.\n    Save Watched Videos With Last Viewed Playlist: Save Watched Videos With Last Viewed Playlist\n    Clear Search History and Cache: Clear Search History and Cache\n    Are you sure you want to clear out your search history and cache?: Are you sure you want to\n      clear out your search history and cache?\n    Search history and cache have been cleared: Search history and cache have been cleared\n    Remove Watch History: Remove Watch History\n    Are you sure you want to remove your entire watch history?: Are you sure you want\n      to remove your entire watch history?\n    Watch history has been cleared: Watch history has been cleared\n    Remove All Subscriptions / Profiles: Remove All Subscriptions / Profiles\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Are\n      you sure you want to remove all subscriptions and profiles?  This cannot be\n      undone.\n    Remove All Playlists: Remove All Playlists\n    All playlists have been removed: All playlists have been removed\n    Are you sure you want to remove all your playlists?: Are you sure you want to remove all your playlists?\n  Subscription Settings:\n    Subscription Settings: Subscription\n    Fetch Feeds from RSS: Fetch Feeds from RSS\n    Fetch Automatically: Fetch Feed Automatically\n    'Limit the number of videos displayed for each channel': 'Limit the number of videos displayed for each channel'\n    To: To\n    Confirm Before Unsubscribing: Confirm Before Unsubscribing\n  Distraction Free Settings:\n    Distraction Free Settings: Distraction Free\n    Sections:\n      Side Bar: Side Bar\n      Subscriptions Page: Subscriptions Page\n      Channel Page: Channel Page\n      Watch Page: Watch Page\n      General: General\n    Hide Video Views: Hide Video Views\n    Hide Video Likes And Dislikes: Hide Video Likes And Dislikes\n    Hide Channel Subscribers: Hide Channel Subscribers\n    Hide Comment Likes: Hide Comment Likes\n    Hide Recommended Videos: Hide Recommended Videos\n    Hide Trending Videos: Hide Trending Videos\n    Hide Popular Videos: Hide Popular Videos\n    Hide Playlists: Hide Playlists\n    Hide Live Chat: Hide Live Chat\n    Hide Active Subscriptions: Hide Active Subscriptions\n    Hide Video Description: Hide Video Description\n    Hide Comments: Hide Comments\n    Hide Profile Pictures in Comments: Hide Profile Pictures in Comments\n    Display Titles Without Excessive Capitalisation: Display Titles Without Excessive Capitalisation And Punctuation\n    Hide Live Streams: Hide Live Streams\n    Hide Upcoming Premieres: Hide Upcoming Premieres\n    Hide Sharing Actions: Hide Sharing Actions\n    Hide Videos on Watch: Hide Videos on Watch\n    Hide Chapters: Hide Chapters\n    Hide Channels: Hide Videos From Channels\n    Hide Channels Disabled Message: Some channels were blocked using ID and weren't processed. Feature is blocked while those IDs are updating\n    Hide Channels Placeholder: Channel ID\n    Hide Channels Invalid: Channel ID provided was invalid\n    Hide Channels API Error: Error retrieving user with the ID provided. Please check again if the ID is correct.\n    Hide Channels Already Exists: Channel ID already exists\n    Hide Featured Channels: Hide Featured Channels\n    Hide Channel Playlists: Hide Channel \"Playlists\" Tab\n    Hide Channel Posts: Hide Channel \"Posts\" Tab\n    Hide Channel Home: Hide Channel \"Home\" Tab\n    Hide Channel Shorts: Hide Channel \"Shorts\" Tab\n    Hide Channel Podcasts: Hide Channel \"Podcasts\" Tab\n    Hide Channel Releases: Hide Channel \"Releases\" Tab\n    Hide Channel Courses: Hide Channel \"Courses\" Tab\n    Hide Videos, Playlists and Channels Containing Text: Hide Videos, Playlists and Channels Containing Text\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Word, Word Fragment, or Phrase\n    Hide Subscriptions Videos: Hide Subscriptions Videos\n    Hide Subscriptions Shorts: Hide Subscriptions Shorts\n    Hide Subscriptions Live: Hide Subscriptions Live\n    Hide Subscriptions Posts: Hide Subscriptions Posts\n    Show Added Items: Show Added Items\n  Data Settings:\n    Data Settings: Data\n    Select Export Type: Select Export Type\n    Import Subscriptions: Import Subscriptions\n    Subscription File: Subscription File\n    History File: History File\n    Playlist File: Playlist File\n    Search history file: Search history file\n    Export Subscriptions: Export Subscriptions\n    Export FreeTube: Export FreeTube\n    Export YouTube: Export YouTube\n    Export NewPipe: Export NewPipe\n    Import History: Import History\n    Export History: Export History\n    Import Playlists: Import Playlists\n    Export Playlists: Export Playlists\n    Search history: Search history\n    Import search history: Import search history\n    Export search history: Export search history\n    Profile object has insufficient data, skipping item: Profile object has insufficient\n      data, skipping item\n    All subscriptions and profiles have been successfully imported: All subscriptions\n      and profiles have been successfully imported\n    All subscriptions have been successfully imported: All subscriptions have been\n      successfully imported\n    Invalid subscriptions file: Invalid subscriptions file\n    Invalid history file: Invalid history file\n    Subscriptions have been successfully exported: Subscriptions have been successfully\n      exported\n    History object has insufficient data, skipping item: History object has insufficient\n      data, skipping item\n    All watched history has been successfully imported: All watched history has been\n      successfully imported\n    All watched history has been successfully exported: All watched history has been\n      successfully exported\n    Playlist insufficient data: Insufficient data for \"{playlist}\" playlist, skipping item\n    All playlists has been successfully imported: All playlists has been\n      successfully imported\n    All playlists has been successfully exported: All playlists has been\n      successfully exported\n    All search history has been successfully imported: All search history has been\n      successfully imported\n    All search history has been successfully exported: All search history has been\n      successfully exported\n    Unable to read file: Unable to read file\n    Unable to write file: Unable to write file\n    Unknown data key: Unknown data key\n    How do I import my subscriptions?: How do I import my subscriptions?\n    Manage Subscriptions: Manage Subscriptions\n  Proxy Settings:\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube doesn't have a built-in proxy but can connect to an external proxy, such as one running on your machine like Tor or an external proxy such-as a SOCKS5 proxy provided by some VPNs. If enabled, make sure your proxy/Tor is configured properly, or FreeTube won't be able to fetch any data.\n    Enable Tor / Proxy: Enable Tor / Proxy\n    Proxy Protocol: Proxy Protocol\n    Proxy Host: Proxy Host\n    Proxy Port Number: Proxy Port Number\n    Proxy Username: Proxy Username\n    Proxy Password: Proxy Password\n    Clicking on Test Proxy will send a request to: Clicking on Test Proxy will send a request to\n    Test Proxy: Test Proxy\n    Your Info: Your Info\n    Ip: Ip\n    Country: Country\n    Region: Region\n    City: City\n    Error getting network information. Is your proxy configured properly?: Error getting network information. Is your proxy configured properly?\n  SponsorBlock Settings:\n    SponsorBlock Settings: SponsorBlock\n    Enable SponsorBlock: Enable SponsorBlock\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API Url (Default is https://sponsor.ajay.app)\n    Notify when sponsor segment is skipped: Notify when sponsor segment is skipped\n    UseDeArrowTitles: Use DeArrow Video Titles\n    UseDeArrowThumbnails: Use DeArrow for thumbnails\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)'\n    Skip Options:\n      Skip Option: Skip Option\n      Auto Skip: Auto Skip\n      Show In Seek Bar: Show In Seek Bar\n      Prompt To Skip: Prompt To Skip\n      Do Nothing: Do Nothing\n    Category Color: Category Color\n  Parental Control Settings:\n    Parental Control Settings: Parental Control\n    Hide Unsubscribe Button: Hide Unsubscribe Button\n    Hide Uploader on Watch page: Hide Uploader on Watch page\n    Show Family Friendly Only: Show Family Friendly Only\n    Hide Search Bar: Hide Search Bar\n  Experimental Settings:\n    Experimental Settings: Experimental\n    Warning: These settings are experimental, they may cause crashes while enabled. Making backups is highly recommended. Use at your own risk!\n    Replace HTTP Cache: Replace HTTP Cache\n  Password Dialog:\n    Password: Password\n    Enter Password To Unlock: Enter password to unlock settings\n  Password Settings:\n    Password Settings: Password\n    Set Password To Prevent Access: Set a password to prevent access to settings\n    Set Password: Set Password\n    Remove Password: Remove Password\nAbout:\n  #On About page\n  About: About\n  Beta: Beta\n  Source code: Source code\n  Licensed under the {licenseLink}: Licensed under the {licenseLink}\n  AGPLv3: AGPLv3\n  Downloads / Changelog: Downloads / Changelog\n  GitHub releases: GitHub Releases\n  Help: Help\n  FreeTube Wiki: FreeTube Wiki\n  FAQ: FAQ\n  Discussions: Discussions\n  Report a problem: Report a problem\n  GitHub issues: GitHub issues\n  Please check for duplicates before posting: Please check for duplicates before posting\n  Website: Website\n  Blog: Blog\n  Email: Email\n  Mastodon: Mastodon\n  Chat on Matrix: Chat on Matrix\n  Please read the {roomRulesLink}: Please read the {roomRulesLink}\n  room rules: room rules\n  Translate: Translate\n  Credits: Credits\n  FreeTube is made possible by {creditsPageLink}: FreeTube is made possible by {creditsPageLink}\n  these people and projects: these people and projects\n  Donate: Donate\n\nProfile:\n  Profile Settings: Profile\n  Toggle Profile List: Toggle Profile List\n  Profile Select: Profile Select\n  Profile Filter: Profile Filter\n  All Channels: All Channels\n  Profile Manager: Profile Manager\n  Create New Profile: Create New Profile\n  Edit Profile: Edit Profile\n  Edit Profile Name: Edit Profile Name\n  Create Profile Name: Create Profile Name\n  Profile Name: Profile Name\n  Color Picker: Color Picker\n  Custom Color: Custom Color\n  Profile Preview: Profile Preview\n  Create Profile: Create Profile\n  Update Profile: Update Profile\n  Make Default Profile: Make Default Profile\n  Delete Profile: Delete Profile\n  Are you sure you want to delete this profile?: Are you sure you want to delete this\n    profile?\n  All subscriptions will also be deleted.: All subscriptions will also be deleted.\n  Your profile name cannot be empty: Your profile name cannot be empty\n  Profile has been created: Profile has been created\n  Profile has been updated: Profile has been updated\n  Your default profile has been set to {profile}: Your default profile has been set to {profile}\n  Removed {profile} from your profiles: Removed {profile} from your profiles\n  Your default profile has been changed to your primary profile: Your default profile\n    has been changed to your primary profile\n  '{profile} is now the active profile': '{profile} is now the active profile'\n  Subscription List: Subscription List\n  Other Channels: Other Channels\n  '{number} selected': '{number} selected'\n  Select All: Select All\n  Select None: Select None\n  Delete Selected: Delete Selected\n  Add Selected To Profile: Add Selected To Profile\n  No channel(s) have been selected: No channel(s) have been selected\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  : This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Are\n    you sure you want to delete the selected channels?  This will not delete the channel\n    from any other profile.\n  Close Profile Dropdown: Close Profile Dropdown\n  Open Profile Dropdown: Open Profile Dropdown\n#On Channel Page\nChannel:\n  Subscribe: Subscribe\n  Unsubscribe: Unsubscribe\n  Channel has been removed from your subscriptions: Channel has been removed from\n    your subscriptions\n  Removed subscription from {count} other channel(s): Removed subscription from {count} other channel(s)\n  Added channel to your subscriptions: Added channel to your subscriptions\n  Search Channel: Search Channel\n  Your search results have returned 0 results: Your search results have returned 0\n    results\n  This channel does not exist: This channel does not exist\n  This channel does not allow searching: This channel does not allow searching\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: This channel is age-restricted and currently cannot be viewed in FreeTube.\n  Channel Tabs: Channel Tabs\n  Videos:\n    Videos: Videos\n    This channel does not currently have any videos: This channel does not currently\n      have any videos\n    Sort Types:\n      Newest: Newest\n      Oldest: Oldest\n      Most Popular: Most Popular\n  Shorts:\n    This channel does not currently have any shorts: This channel does not currently have any shorts\n  Live:\n    Live: Live\n    This channel does not currently have any live streams: This channel does not currently\n      have any live streams\n  Playlists:\n    Playlists: Playlists\n    This channel does not currently have any playlists: This channel does not currently\n      have any playlists\n    Sort Types:\n      Last Video Added: Last Video Added\n      Newest: Newest\n      Oldest: Oldest\n  Home:\n    Home: Home\n    View Playlist: View Playlist\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: This channel does not currently have any podcasts\n  Releases:\n    Releases: Releases\n    This channel does not currently have any releases: This channel does not currently have any releases\n  Courses:\n    Courses: Courses\n    This channel does not currently have any courses: This channel does not currently have any courses\n  About:\n    About: About\n    Channel Description: Channel Description\n    Tags:\n      Tags: Tags\n      Search for: Search for \"{tag}\"\n    Details: Details\n    Joined: Joined\n    Location: Location\n    Featured Channels: Featured Channels\n  Posts:\n    This channel currently does not have any posts: This channel currently does not have any posts\n    votes: '{votes} votes'\n    View Full Post: View Full Post\n    Reveal Answers: Reveal Answers\n    Hide Answers: Hide Answers\n    Video hidden by FreeTube: Video hidden by FreeTube\nVideo:\n  IP block: 'YouTube has blocked your IP address from watching videos. Please try switching to a different VPN or proxy.'\n  MembersOnly: Members-only videos cannot be watched with FreeTube as they require Google login and paid membership to the uploader's channel.\n  AgeRestricted: Age-restricted videos cannot be watched with FreeTube as they require Google login and using an age-verified YouTube account.\n  DRMProtected: DRM protected videos cannot be played in FreeTube, as they require proprietary, closed source components. If you want to watch this video please watch it on the official YouTube website in a DRM enabled web browser.\n  More Options: More Options\n  Mark As Watched: Mark As Watched\n  Remove From History: Remove From History\n  Video has been marked as watched: Video has been marked as watched\n  Video has been removed from your history: Video has been removed from your history\n  Save Watched Progress: Save Watched Progress\n  Watched Progress Saved: Watched Progress Saved\n  Save Video: Save Video\n  Video has been saved: Video has been saved\n  Video has been removed from your saved list: Video has been removed from your saved list\n  Open in YouTube: Open in YouTube\n  Copy YouTube Link: Copy YouTube Link\n  Open YouTube Embedded Player: Open YouTube Embedded Player\n  Copy YouTube Embedded Player Link: Copy YouTube Embedded Player Link\n  Open in Invidious: Open in Invidious\n  Copy Invidious Link: Copy Invidious Link\n  Open Channel in YouTube: Open Channel in YouTube\n  Copy YouTube Channel Link: Copy YouTube Channel Link\n  Open Channel in Invidious: Open Channel in Invidious\n  Copy Invidious Channel Link: Copy Invidious Channel Link\n  Hide Channel: Hide Channel\n  Unhide Channel: Show Channel\n  Views: Views\n  Loop Playlist: Loop Playlist\n  Shuffle Playlist: Shuffle Playlist\n  Reverse Playlist: Reverse Playlist\n  Previous: Previous\n  Next: Next\n  Watched: Watched\n  Autoplay: Autoplay\n  Starting soon, please refresh the page to check again: Starting soon, please refresh\n    the page to check again\n  # As in a Live Video\n  Premieres: Premieres\n  Upcoming: Upcoming\n  Unlisted: Unlisted\n  Live: Live\n  Live Now: Live Now\n  Live Chat: Live Chat\n  Enable Live Chat: Enable Live Chat\n  Popout Live Chat: Popout Chat\n  Live Chat is currently not supported in this build.: Live Chat is currently not\n    supported in this build.\n  Live chat is enabled. Chat messages will appear here once sent.: Live chat is enabled.  Chat\n    messages will appear here once sent.\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': Live\n    Chat is currently not supported with the Invidious API.  A direct connection to\n    YouTube is required.\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'Live Chat is unavailable for this stream. It may have been disabled by the uploader.'\n  Show Super Chat Comment: Show Super Chat Comment\n  Scroll to Bottom: Scroll to Bottom\n  Published:\n    In less than a minute: In less than a minute\n  Published on: Published on\n  Streamed on: Streamed on\n  Started streaming on: Started streaming on\n  DeArrow:\n    Show Original Details: Show Original Details\n    Show Modified Details: Show Modified Details\n  Sponsor Block category:\n    sponsor: Sponsor\n    intro: Intro\n    outro: Outro\n    self-promotion: Self-Promotion\n    interaction: Interaction\n    music offtopic: Music Offtopic\n    recap: Recap\n    filler: Filler\n  External Player:\n    OpenInTemplate: Open in {externalPlayer}\n    video: video\n    playlist: playlist\n    OpeningTemplate: Opening {videoOrPlaylist} in {externalPlayer}...\n    UnsupportedActionTemplate: '{externalPlayer} does not support: {action}'\n    Unsupported Actions:\n      starting video at offset: starting video at offset\n      setting a playback rate: setting a playback rate\n      opening playlists: opening playlists\n      opening specific video in a playlist (falling back to opening the video): opening specific video in a playlist (falling back to opening the video)\n      reversing playlists: reversing playlists\n      shuffling playlists: shuffling playlists\n      looping playlists: looping playlists\n  Player:\n    TranslatedCaptionTemplate: '{language} (translated from \"{originalLanguage}\")'\n    Audio Tracks: Audio Tracks\n    Autoplay is off: Autoplay is off\n    Autoplay is on: Autoplay is on\n    Theatre Mode: Theater Mode\n    Exit Theatre Mode: Exit Theater Mode\n    Full Window: Full Window\n    Exit Full Window: Exit Full Window\n    Take Screenshot: Take Screenshot\n    Show Stats: Show Stats\n    Hide Stats: Hide Stats\n    Stats:\n      Stats: Stats\n      Video ID: 'Video ID: {videoId}'\n      Media Formats: 'Media Formats: {formats}'\n      Resolution: 'Resolution: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Player Dimensions: {width}x{height}'\n      Bitrate: 'Bitrate: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Bandwidth: {bandwidth} kbps'\n      Buffered: 'Buffered: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Dropped Frames: {droppedFrames} / Total Frames: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n    You appear to be offline: You appear to be offline.\n    Playback will resume automatically when your connection comes back: Playback will resume automatically when your connection comes back.\n    Skipped segment: 'Skipped {segmentCategory} segment'\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Remaining preroll-ad time: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Remaining SABR backoff time: {remindingTimeSeconds}s'\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: Playlist\n  View Full Playlist: View Full Playlist\n  Last Updated On: Last Updated On\n  Sort By:\n    DateAddedNewest: Date added (Newest)\n    DateAddedOldest: Date added (Oldest)\n    PublishedNewest: Date published (Newest)\n    PublishedOldest: Date published (Oldest)\n    AuthorAscending: Author (A-Z)\n    AuthorDescending: Author (Z-A)\n    VideoTitleAscending: Title (A-Z)\n    VideoTitleDescending: Title (Z-A)\n    VideoDurationAscending: Duration (Shortest)\n    VideoDurationDescending: Duration (Longest)\n    Custom: Custom\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: Change Media Formats\n  Use Dash Formats: Use DASH Formats\n  Use Legacy Formats: Use Legacy Formats\n  Use Audio Formats: Use Audio Formats\n  Dash formats are not available for this video: DASH formats are not available for\n    this video\n  Audio formats are not available for this video: Audio formats are not available\n    for this video\n  Legacy formats are not available for this video: Legacy formats are not available\n    for this video\nShare:\n  Share Video: Share Video\n  Share Post: Share Post\n  Share Channel: Share Channel\n  Share Playlist: Share Playlist\n  Include Timestamp: Include Timestamp\n  Copy Link: Copy Link\n  Open Link: Open Link\n  Copy Embed: Copy Embed\n  Open Embed: Open Embed\n  # On Click\n  Invidious URL copied to clipboard: Invidious URL copied to clipboard\n  Invidious Embed URL copied to clipboard: Invidious Embed URL copied to clipboard\n  Invidious Channel URL copied to clipboard: Invidious Channel URL copied to clipboard\n  YouTube URL copied to clipboard: YouTube URL copied to clipboard\n  YouTube Embed URL copied to clipboard: YouTube Embed URL copied to clipboard\n  YouTube Channel URL copied to clipboard: YouTube Channel URL copied to clipboard\nClipboard:\n  Copy failed: Copy to clipboard failed\n  Cannot access clipboard without a secure connection: Cannot access clipboard without a secure connection\n\nChapters:\n  Chapters: Chapters\n  Key Moments: Key Moments\n\nMini Player: Mini Player\nComments:\n  Comments: Comments\n  Click to View Comments: Click to View Comments\n  Getting comment replies, please wait: Getting comment replies, please wait\n  There are no more comments for this video: There are no more comments for this video\n  Hide Comments: Hide Comments\n  Top comments: Top comments\n  Newest first: Newest First\n  View {replyCount} replies: View 1 reply | View {replyCount} replies\n  Hide {replyCount} replies: Hide 1 reply | Hide {replyCount} replies\n  View 1 reply from {channelName}: View 1 reply from {channelName}\n  View {replyCount} replies from {channelName} and others: View {replyCount} replies from {channelName} and others\n  Show More Replies: Show More Replies\n  There are no comments available for this video: There are no comments available\n    for this video\n  There are no comments available for this post: There are no comments available for this post\n  Load More Comments: Load More Comments\n  Pinned by: Pinned by\n  Member: Member\n  Subscribed: Subscribed\n  Hearted: Hearted\n\nUp Next: Up Next\nDescription:\n  Expand Description: ...more\n  Collapse Description: Show less\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: Choose the backend that FreeTube uses to obtain data. The\n      local API is a built-in extractor. The Invidious API requires an Invidious server\n      to connect to.\n    Fallback to Non-Preferred Backend on Failure: When your preferred API has a problem,\n      FreeTube will automatically attempt to use your non-preferred API as a fallback\n      method when enabled.\n    Thumbnail Preference: All thumbnails throughout FreeTube will be replaced with\n      a frame of the video, blurred or hidden instead of the default thumbnail.\n    Invidious Instance: The Invidious instance that FreeTube will connect to for API\n      calls.\n    Region for Trending: The region of trends allows you to pick which country's trending\n      videos you want to have displayed.\n    External Link Handling: |\n      Choose the default behavior when a link, which cannot be opened in FreeTube, is clicked.\n      By default FreeTube will open the clicked link in your default browser.\n    Open Deep Links In New Window: URLs passed to FreeTube, such as by redirect\n      browser extensions or command line arguments, are opened in a new window.\n  Player Settings:\n    Proxy Videos Through Invidious: Will connect to Invidious to serve videos instead\n      of making a direct connection to YouTube.\n    Default Video Format: Set the formats used when a video plays. DASH formats can\n      play higher qualities. Legacy formats are limited to a max of 360p but use less\n      bandwidth. Audio formats are audio only streams.\n    Scroll Playback Rate Over Video Player: While the cursor is over the video, press and\n      hold the Control key (Command Key on Mac) and scroll the mouse wheel forwards or backwards to control\n      the playback rate. Press and hold the Control key (Command Key on Mac) and left click the mouse\n      to quickly return to the default playback rate (1x unless it has been changed in the settings).\n    Skip by Scrolling Over Video Player: Use the scroll wheel to skip through the video, MPV style.\n  External Player Settings:\n    External Player: Choosing an external player will display an icon, for opening the\n      video (playlist if supported) in the external player, on the thumbnail. Warning, Invidious settings do not affect external players.\n    Custom External Player Executable: By default, FreeTube will assume that the chosen external\n      player can be found via the PATH environment variable. If needed, a custom path can\n      be set here.\n    Ignore Warnings: Suppress warnings for when the current external player does not support\n      the current action (e.g. reversing playlists, etc.).\n    Ignore Default Arguments: Do not send any default arguments to the external player\n      aside from the video URL (e.g. playback rate, playlist URL, etc.).\n      Custom arguments will still be passed on.\n    Custom External Player Arguments: Any custom command line arguments you want to be passed on to the external player.\n    DefaultCustomArgumentsTemplate: \"(Default: '{defaultCustomArguments}')\"\n  Distraction Free Settings:\n    Hide Channels: Enter a channel ID to hide all videos, playlists and the channel itself from appearing in search, trending, most popular and recommended.\n       The channel ID entered must be a complete match and is case sensitive.\n    Hide Subscriptions Live: 'This setting is overridden by the app-wide \"{appWideSetting}\" setting, in the \"{subsection}\" section of the \"{settingsSection}\"'\n    Hide Videos, Playlists and Channels Containing Text: Enter a word, word fragment, or phrase (case insensitive) to hide all videos, playlists and channels whose original titles contain it throughout all of FreeTube, excluding only History, Your Playlists, and videos inside of playlists.\n    Hide Videos on Watch: 'Hides watched videos from the Videos, Shorts, and Live tabs on the Subscription and Channel pages. This does not affect the Home tab on Channel pages'\n  Subscription Settings:\n    Fetch Feeds from RSS: When enabled, FreeTube will use RSS instead of its default\n      method for grabbing your subscription feed. RSS is faster and prevents IP blocking,\n      but doesn't provide certain information like video duration, live status or posts\n    Fetch Automatically: When enabled, FreeTube will automatically fetch\n      your subscription feed on startup and when a new window is opened.\n  Experimental Settings:\n    Replace HTTP Cache: Disables Electron's disk based HTTP cache and enables a custom in-memory image cache. Will lead to increased RAM usage.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Replace video titles with user-submitted titles from DeArrow.\n    UseDeArrowThumbnails: Replace video thumbnails with thumbnails from DeArrow.\n\n# Toast Messages\nLocal API Error (Click to copy): Local API Error (Click to copy)\nInvidious API Error (Click to copy): Invidious API Error (Click to copy)\nFalling back to Invidious API: Falling back to Invidious API\nFalling back to Local API: Falling back to Local API\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: This\n  video is unavailable because of missing formats. This can happen due to country\n  unavailability.\nUnknown YouTube url type, cannot be opened in app: Unknown YouTube url type, cannot be opened in app\nLoop is now disabled: Loop is now disabled\nLoop is now enabled: Loop is now enabled\nShuffle is now disabled: Shuffle is now disabled\nShuffle is now enabled: Shuffle is now enabled\nThe playlist has been reversed: The playlist has been reversed\nPlaying Next Video: Playing Next Video\nPlaying Previous Video: Playing Previous Video\nPlaying Next Video Interval: Playing next video in no time. Click to cancel. | Playing next video in {nextVideoInterval} second. Click to cancel. | Playing next video in {nextVideoInterval} seconds. Click to cancel.\nCanceled next video autoplay: Canceled next video autoplay\nAutoplay Interruption Timer: Autoplay canceled due to {autoplayInterruptionIntervalHours} hours of inactivity\n\nDefault Invidious instance has been set to {instance}: Default Invidious instance has been set to {instance}\nDefault Invidious instance has been cleared: Default Invidious instance has been cleared\n'The playlist has ended. Enable loop to continue playing': 'The playlist has ended.  Enable\n  loop to continue playing'\nAge Restricted:\n  This channel is age restricted: This channel is age restricted\n  This video is age restricted: This video is age restricted\nExternal link opening has been disabled in the general settings: 'External link opening has been disabled in the general settings'\nScreenshot Success: Saved screenshot\nScreenshot Error: Screenshot failed. {error}\nChannel Hidden: '{channel} added to channel filter'\nChannel Unhidden: '{channel} removed from channel filter'\nTrimmed input must be at least N characters long: Trimmed input must be at least 1 character long | Trimmed input must be at least {length} characters long\nTag already exists: '\"{tagName}\" tag already exists'\n\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: This hashtag does not currently\n      have any videos\nMoments Ago: moments ago\nYes: Yes\nNo: No\nOk: Ok\nYes, Delete: Yes, Delete\nYes, Restart: Yes, Restart\nYes, Open Link: Yes, Open Link\nCancel: Cancel\n# symbol used to indicate that an item is correct\ncheckmark: ✓\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: '{label}: {value}'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nshortcutLabelSeparator: '｜'\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Plus\n  arrowdown: Down Arrow\n  arrowleft: Left Arrow\n  arrowright: Right Arrow\n  arrowup: Up Arrow\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Keyboard Shortcuts\n  Sections:\n    Video:\n      Playback: Video: Playback\n      General: Video: General\n    App:\n      Situational: 'App: Situational'\n      General: App: General\n  Show Keyboard Shortcuts: Show keyboard shortcuts\n  History Backward: Go back one page\n  History Forward: Go forward one page\n  New Window: Create a new window\n  Navigate to Settings: Navigate to the Settings page\n  Navigate to History: Navigate to the History page\n  Refresh: Refresh feed with latest content\n  Focus Secondary Search: Focus on the secondary search bar (if one is present)\n  Captions: Toggle captions ON/OFF\n  Stats: Show video statistics\n  Fullscreen: Toggle fullscreen\n  Picture in Picture: Toggle Picture-in-Picture mode\n  Large Rewind: 'Rewind 10 seconds / Rewind video based on current Video Playback Rate'\n  Play: Toggle play/pause\n  Large Fast Forward: 'Forward 10 seconds / Fast-Forward video based on current Video Playback Rate'\n  Mute: Toggle mute\n  Decrease Video Speed: 'Decrease video speed based on Video Playback Rate Interval'\n  Increase Video Speed: 'Increase video speed based on Video Playback Rate Interval'\n  Full Window: Toggle full window\n  Theatre Mode: Toggle theater mode\n  Take Screenshot: Take screenshot\n  Minimize Window: Miminize window\n  Close Window: Close window\n  Toggle Developer Tools: Toggle developer tools\n  Reset Zoom: Reset zoom level / UI scale\n  Zoom In: Zoom in\n  Zoom Out: Zoom out\n  Focus Search: Focus on the search bar\n  Search in New Window: Search in a new window\n  Last Frame: Previous frame (while paused)\n  Next Frame: Next frame (while paused)\n  Volume Up: Increase volume\n  Volume Down: Decrease volume\n  Small Rewind: 'Rewind X seconds based on the Rewind Interval and current Video Playback Rate'\n  Small Fast Forward: 'Fast-Forward X seconds based on the Fast-Forward Interval and current Video Playback Rate'\n  Last Chapter: Last Chapter\n  Next Chapter: Next Chapter\n  Skip by Tenths: Skip through video by percentage (3 skips to 30% of duration)\n  Home: Seek to the beginning of the video\n  End: Seek to the end of the video\n  Skip to Next Video: Skip to the next video in a playlist or next recommended video\n  Skip to Previous Video: Skip to the previous video in a playlist\n"
  },
  {
    "path": "static/locales/eo.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Esperanto'\n\nFile: 'Dosiero'\nQuit: 'Eliri'\nEdit: 'Redakti'\nUndo: 'Malfari'\nRedo: 'Refari'\nCut: 'Eltondi'\nCopy: 'Kopii'\nPaste: 'Alglui'\nDelete: 'Forigi'\nSelect all: 'Elekti ĉiujn'\nZoom in: 'Zomi'\nZoom out: 'Malzomi'\nToggle fullscreen: 'Baskuli tutekranon'\nWindow: 'Fenestro'\nMinimize: 'Minimumigi'\nClose: 'Fermi'\nBack: 'Reen'\nForward: 'Antaŭen'\n\nGlobal:\n  Sort By: 'Ordigi laŭ'\n\n  Videos: Videaĵoj\nVersion {versionNumber} is now available!  Click for more details: 'Versio {versionNumber}\n  disponeblas nun!  Alklaki por pli informoj.'\nDownload From Site: 'Elŝuti el retejo'\nSearch / Go to URL: 'Serĉi / Iri al URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Serĉaj filtriloj'\n  Sort By:\n    Most Relevant: 'Plej rilataj'\n    Rating: 'Takso'\n    Upload Date: 'Alŝuta dato'\n    View Count: 'Spektonombro'\n  Time:\n    Time: 'Tempo'\n    Any Time: 'Ajna tempo'\n    Last Hour: 'Lasta horo'\n    Today: 'Hodiaŭ'\n    This Week: 'Ĉi-semajne'\n    This Month: 'Ĉi-monate'\n    This Year: 'Ĉi-jare'\n  Type:\n    Type: 'Speco'\n    All Types: 'Ĉiuj specoj'\n    Videos: 'Videaĵoj'\n    Channels: 'Kanaloj'\n    #& Playlists\n  Duration:\n    Duration: 'Daŭrtempo'\n    All Durations: 'Ĉiuj daŭrtempoj'\n    Short (< 4 minutes): 'Mallongaj (<4 minutoj)'\n    Long (> 20 minutes): 'Longaj (> 20 minutoj)'\n  # On Search Page\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonoj'\n  Load More Videos: Ŝargi pli videaĵojn\nTrending:\n  Trending: 'Popularaj'\n  Gaming: Ludismo\nMost Popular: 'Plej popularaj'\nPlaylists: 'Ludlistoj'\nUser Playlists:\n  Your Playlists: 'Viaj ludlistoj'\nHistory:\n  # On History Page\n  History: 'Historio'\n  Watch History: 'Spekthistorio'\n  Your history list is currently empty.: 'Via historia listo nune malplenas.'\nSettings:\n  # On Settings Page\n  Settings: 'Agordoj'\n  General Settings:\n    General Settings: 'Ĝeneralaj agordoj'\n    Check for Updates: 'Kontroli por ĝisdatigi'\n    Enable Search Suggestions: 'Ŝalti serĉproponoj'\n    Video View Type:\n      Grid: 'Krado'\n      List: 'Listo'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Bildeta agordo'\n      Default: 'Defaŭlta'\n      Beginning: 'Komenco'\n      Middle: 'Mezo'\n      End: 'Fino'\n    System Default: Operaciuma defaŭlto\n  Theme Settings:\n    Base Theme:\n      Dark: 'Malluma'\n      Light: 'Luma'\n  Player Settings: {}\nAbout:\n  #On About page\n  Blog: Blogo\n  Website: Retejo\n  Email: Retpoŝto\nChannel:\n  About:\n    Details: Detaloj\n  Videos:\n    Videos: Videaĵoj\nVideo: {}\nMore: Pli\nSearch Bar:\n  Clear Input: Klarigi enigon\nAre you sure you want to open this link?: Ĉu vi certe volas malfermi ĉi-ligilon?\nOpen New Window: Malfermi novan fenestron\nPreferences: Agordoj\nNew Window: Nova Fenestro\nGo to page: Iri al {page}\nActual size: Reala grando\nProfile:\n  Select All: Elekti ĉiujn\nKeyboardShortcutPrompt:\n  Zoom In: Zomi\n  Zoom Out: Malzomi\n  Fullscreen: Baskuli tutekranon\n"
  },
  {
    "path": "static/locales/es-AR.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'español (Argentina)'\n\n# Webkit Menu Bar\nFile: 'Archivo'\nQuit: 'Salir'\nEdit: 'Editar'\nUndo: 'Deshacer'\nRedo: 'Rehacer'\nCut: 'Cortar'\nCopy: 'Copiar'\nPaste: 'Pegar'\nDelete: 'Eliminar'\nSelect all: 'Seleccionar todo'\nToggle Developer Tools: 'Activar/Desactivar Herramientas de Desarrollo'\nActual size: 'Escala : 100%'\nZoom in: 'Acercarse'\nZoom out: 'Alejarse'\nToggle fullscreen: 'Alternar pantalla completa'\nWindow: 'Ventana'\nMinimize: 'Minimizar'\nClose: 'Cerrar'\nBack: 'Volver'\nForward: 'Avanzar'\n\n# Search Bar\nSearch / Go to URL: 'Buscar / Ir a URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtros de búsqueda'\n  Sort By:\n    Most Relevant: 'Más relevante'\n    Rating: 'Clasificación'\n    Upload Date: 'Fecha de carga'\n    View Count: 'Conteo de visitas'\n  Time:\n    Time: 'Hora'\n    Any Time: 'En cualquier momento'\n    Last Hour: 'Última hora'\n    Today: 'Hoy'\n    This Week: 'Esta semana'\n    This Month: 'Este mes'\n    This Year: 'Este año'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Todos los tipos'\n    Videos: 'Vidéos'\n    Channels: 'Canales'\n    #& Playlists\n    Movies: Películas\n  Duration:\n    Duration: 'Duración'\n    All Durations: 'Todas las duraciones'\n    Short (< 4 minutes): 'Corto (< 4 minutos)'\n    Long (> 20 minutes): 'Larga (> 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Media (4 - 20 minutos)\n  Search Results: 'Resultados de la búsqueda'\n  Fetching results. Please wait: 'Obteniendo resultados. Por favor esperá'\n  Fetch more results: 'Obtener más resultados'\n# Sidebar\n  There are no more results for this search: No hay más resultados para esta búsqueda\n  Features:\n    Subtitles: Subtítulos\n    Features: Características\n    3D: 3D\n    HD: HD\n    Creative Commons: Creative Commons\n    Live: En vivo\n    Location: Ubicación\n    HDR: HDR\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Suscripciones'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tu lista de suscripciones está actualmente vacía. Si deseas importar tus suscripciones, puedes ir a Configuración de datos y seleccionar Importar suscripciones, o puedes buscar un canal y suscribirte a él.'\n  Load More Videos: Cargar más videos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil tiene un gran número de suscriptores. Forzando RSS para evitar límites\n  Load More Posts: Cargar más publicaciones\n  Empty Channels: Tus canales suscriptos actualmente no tienen ningún video.\n  Subscriptions Tabs: Pestañas de suscripciones\n  Empty Posts: Tus canales suscriptos actualmente no tienen ninguna publicación.\n  All Subscription Tabs Hidden: Todas las pestañas de suscripciones están ocultas. Para ver contenido acá, por favor, desocultá algunas pestañas en la sección \"{subsection}\" en \"{settingsSection}\".\n  Disabled Automatic Fetching: Has desactivado la recuperación automática de suscripciones. Actualizá las suscripciones para verlas acá.\n  Error Channels: Canales con errores\nTrending:\n  Trending: 'Tendencias'\n  Gaming: Juegos\n  Trending Tabs: Lo más destacado\nMost Popular: 'Más popular'\nPlaylists: 'Listas de reproducción'\nUser Playlists:\n  Your Playlists: 'Tus listas de reproducción'\n  Search bar placeholder: Buscar listas de reproducción\n  Empty Search Message: No hay videos en esta lista de reproducción que coincidan con tu búsqueda.\n  This playlist currently has no videos.: Esta lista de reproducción no tiene videos.\n  Playlists with Matching Videos: Listas de reproducción con videos repetidos\n  Create New Playlist: Crear nueva lista de reproducción\n  Add to Favorites: Añadir a {playlistName}\n  Add to Playlist: Añadir a la lista de reproducción\n  Remove from Playlist: Eliminar de la lista de reproducción\n  Playlist Description: Descripción de la lista de reproducción\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ¿Estás seguro de que quieres eliminar 1 video duplicado de esta lista de reproducción? Esto no se puede deshacer.\n  You have no playlists. Click on the create new playlist button to create a new one.: No tienes listas de reproducción. Haz clic en el botón de crear nueva lista de reproducción para crear una.\n  Are you sure you want to delete this playlist? This cannot be undone: ¿Estás seguro de que quieres eliminar esta lista de reproducción? Esto no se puede deshacer.\n  Export Playlist: Exportar esta lista de reproducción\n  Playlist Name: Nombre de la lista de reproducción\n  Quick Bookmark Enabled: Marcador rápido habilitado\n  Cannot delete the quick bookmark target playlist.: No se puede eliminar la lista de reproducción objetivo del marcador rápido.\n  Remove Watched Videos: Eliminar videos vistos\n  Enable Quick Bookmark With This Playlist: Habilitar marcador rápido con esta lista de reproducción\n  Cancel: Cancelar\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ¿Estás seguro de que quieres eliminar 1 video duplicado de esta lista de reproducción? Esto no se puede deshacer.\n  TotalTimePlaylist: 'Tiempo total: {duration}'\n  Remove from Favorites: Eliminar de {playlistName}\n  Move Video Up: Mover video hacia arriba\n  Move Video Down: Mover video hacia abajo\n  Save Changes: Guardar cambios\n  Edit Playlist Info: Editar información de la lista de reproducción\n  Copy Playlist: Copiar lista de reproducción\n  Remove Duplicate Videos: Eliminar videos duplicados\n  The playlist has been successfully exported: La lista de reproducción ha sido exportada con éxito\n  Delete Playlist: Eliminar lista de reproducción\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: El video ha sido eliminado\n      This playlist is already being used for quick bookmark.: Esta lista ya se está usando para marcadores rápidos.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Esta lista de reproducción ahora se usa como marcador rápido en lugar de {oldPlaylistName}. Hacé clic acá para deshacer.\n      Playlist name cannot be empty. Please input a name.: El nombre de la lista de reproducción no puede estar vacío. Por favor, ingresá un nombre.\n      There was an issue with updating this playlist.: Hubo un problema al actualizar esta lista de reproducción.\n      This video cannot be moved down.: Este video no se puede mover hacia abajo.\n      This video cannot be moved up.: Este video no se puede mover hacia arriba.\n      This playlist is now used for quick bookmark: Esta lista de reproducción ahora se usa como marcador rápido\n      Reverted to use {oldPlaylistName} for quick bookmark: '\"Se volvió a usar {oldPlaylistName} como marcador rápido.'\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Algunos videos de la lista de reproducción todavía no se cargaron. Hacé clic acá para copiar igual.\n      Playlist has been updated.: La lista de reproducción fue actualizada.\n      \"{videoCount} video(s) have been removed\": Se eliminó 1 video | {videoCount} videos fueron eliminados\n      Video has been removed. Click here to undo.: El video fue eliminado. Hacé clic aquí para deshacer.\n      There was a problem with removing this video: Hubo un problema al eliminar este video.\n      Playlist {playlistName} has been deleted.: La lista de reproducción {playlistName} ha sido eliminada.\n      There were no videos to remove.: No había videos para eliminar.\n      This playlist is protected and cannot be removed.: Esta lista de reproducción está protegida y no se puede eliminar.\n      This playlist does not exist: Esta lista de reproducción no existe.\n      This playlist has a video with a duration error: Esta lista de reproducción contiene al menos un video sin duración; será ordenado como si su duración fuera cero.\n    Search for Videos: Buscar videos\n  Sort By:\n    NameAscending: A-Z\n    LatestCreatedFirst: Recientemente creada\n    EarliestCreatedFirst: creada más temprana\n    LatestUpdatedFirst: recientemente actualizada\n    EarliestPlayedFirst: Reproducido más temprano\n    EarliestUpdatedFirst: Actualizado más temprano\n    LatestPlayedFirst: Reproducido recientemente\n  AddVideoPrompt:\n    Allow Adding Duplicate Video(s): Permitir agregar videos duplicados\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} videos serán agregados'\n    Select a playlist to add your N videos to: Seleccioná una lista de reproducción para agregar tu video | Seleccioná una lista de reproducción para agregar tus {videoCount} videos.\n    Added {count} Times: Ya agregado | Agregado {count} veces\n    Save: Guardar\n    N playlists selected: '{playlistCount} seleccionadas'\n    Search in Playlists: Buscar en listas de reproducción\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videos ya agregados'\n    Toast:\n      You haven't selected any playlist yet.: Todavía no seleccionaste ninguna lista de reproducción.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: Nombre de la nueva lista de reproducción\n    Toast:\n      Playlist {playlistName} has been successfully created.: La lista de reproducción {playlistName} se creó correctamente.\n      There is already a playlist with this name. Please pick a different name.: Ya existe una lista de reproducción con este nombre. Por favor, elegí otro nombre.\n      There was an issue with creating the playlist.: Hubo un problema al crear la lista de reproducción.\n    Create: Crear\nHistory:\n  # On History Page\n  History: 'Historial'\n  Watch History: 'Ver historial'\n  Your history list is currently empty.: 'Su lista de historial está actualmente vacía.'\n  Search bar placeholder: Buscar en el Historial\n  Empty Search Message: No hay videos en tu historial que coincidan con tu búsqueda.\n  Case Sensitive Search: Búsqueda con mayúsculas y minúsculas\nSettings:\n  # On Settings Page\n  Settings: 'Configuraciones'\n  General Settings:\n    General Settings: 'General'\n    Fallback to Non-Preferred Backend on Failure: 'Usar una Alternativa en Caso de Problemas con la Opción Preferida'\n    Enable Search Suggestions: 'Habilitar sugerencias de búsqueda'\n    Default Landing Page: 'Página de destino predeterminada'\n    Locale Preference: 'Preferencia regional'\n    Preferred API Backend:\n      Preferred API Backend: 'Backend de API preferido'\n      Local API: 'API local'\n      Invidious API: 'API de Invidious'\n    Video View Type:\n      Video View Type: 'Tipo de vista de video'\n      Grid: 'Cuadrícula'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencia de miniaturas'\n      Default: 'Predeterminado'\n      Beginning: 'Comenzando'\n      Middle: 'Medio'\n      End: 'Final'\n      Hidden: Oculto\n      Blur: Desenfocar\n    Region for Trending: 'Región para Tendencias'\n        #! List countries\n    View all Invidious instance information: Ver toda la información sobre la instancia de Invidious\n    Check for Latest Blog Posts: Buscar nuevas entradas de blogs\n    Check for Updates: Buscar actualizaciones\n    Set Current Instance as Default: Definir Instancia Actual como Por Defecto\n    Clear Default Instance: Limpiar Instancia Por Defecto\n    Current Invidious Instance: Instancia Actual de Individuous\n    The currently set default instance is {instance}: La instancia actual es {instance}\n    No default instance has been set: No se ha elegido ninguna instancia\n    Current instance will be randomized on startup: La instancia actual será aleatorizada en el inicio\n    System Default: Por defecto del Sistema\n    External Link Handling:\n      No Action: Sin Acción\n      External Link Handling: Manejo de Enlaces Externos\n      Open Link: Abrir enlace\n      Ask Before Opening Link: Preguntar antes de abrir el enlace\n    Open Deep Links In New Window: Abrir las URLs enviadas a FreeTube en una nueva ventana\n    Auto Load Next Page:\n      Label: Cargar automáticamente la próxima página\n      Tooltip: Cargar automáticamente páginas y comentarios adicionales.\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Utilizar el color principal para la barra superior'\n    Base Theme:\n      Base Theme: 'Tema base'\n      Black: 'Negro'\n      Dark: 'Oscuro'\n      Light: 'Claro'\n      Dracula: 'Drácula'\n      Pastel Pink: Rosa claro\n      Hot Pink: Rosa Intenso\n      Catppuccin Mocha: Cappuccino Moka\n      System Default: Predeterminado del sistema\n      Catppuccin Frappe: Catppuccin Frappe\n      Nordic: Nordic (tema)\n    Main Color Theme:\n      Main Color Theme: 'Color principal del tema'\n      Red: 'Rojo'\n      Pink: 'Rosa'\n      Purple: 'Morado'\n      Deep Purple: 'Morado oscuro'\n      Indigo: 'Indigo'\n      Blue: 'Azul'\n      Light Blue: 'Celeste'\n      Cyan: 'Cian'\n      Teal: 'Verde azulado'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Lima'\n      Yellow: 'Amarillo'\n      Amber: 'Ámbar'\n      Orange: 'Naranja'\n      Deep Orange: 'Naranja oscuro'\n      Dracula Cyan: 'Drácula Cian'\n      Dracula Green: 'Drácula Verde'\n      Dracula Orange: 'Drácula Naranja'\n      Dracula Pink: 'Drácula Rosado'\n      Dracula Purple: 'Drácula Morado'\n      Dracula Red: 'Drácula Rojo'\n      Dracula Yellow: 'Drácula Amarillo'\n      Catppuccin Mocha Red: Cappuccino Mocca Rojo\n      Catppuccin Mocha Maroon: Cappuccino Mocca Bordó\n      Catppuccin Mocha Sky: Cappuccino Mocca Cielo\n      Catppuccin Mocha Sapphire: Cappuccino Mocca Zafiro\n      Catppuccin Mocha Teal: Cappuccino Mocca Turquesa\n      Catppuccin Mocha Yellow: Cappuccino Mocca Amarillo\n      Catppuccin Mocha Rosewater: Cappuccino Mocca Rosa Claro\n      Catppuccin Mocha Peach: Cappuccino Mocca Durazno\n      Catppuccin Mocha Flamingo: Cappuccino Mocca Flamenco\n      Catppuccin Mocha Mauve: Cappuccino Mocca Violeta Claro\n      Catppuccin Mocha Pink: Cappuccino Mocca Rosa\n      Catppuccin Mocha Lavender: Cappuccino Mocca Lavanda\n      Catppuccin Mocha Blue: Cappuccino Mocca Azul\n      Catppuccin Mocha Green: Cappuccino Mocca Verde\n      Gruvbox Dark Green: Gruvbox Dark Green\n      Gruvbox Dark Yellow: Gruvbox Dark Yellow\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow (tema)\n      Catppuccin Frappe Green: Catppuccin Frappe Green (tema)\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n    Secondary Color Theme: 'Color secundario del tema'\n        #* Main Color Theme\n    UI Scale: Escala de la interfaz de usuario\n    Disable Smooth Scrolling: Desactivar desplazamiento suave\n    Expand Side Bar by Default: Expandir la barra lateral por defecto\n    Hide Side Bar Labels: Esconder las etiquetas de la barra lateral\n    Hide FreeTube Header Logo: Ocultar el logo de FreeTube del encabezado\n  Player Settings:\n    Player Settings: 'Configuraciones del reproductor'\n    Play Next Video: 'Reproducción automática de videos recomendados'\n    Turn on Subtitles by Default: 'Activar subtítulos por defecto'\n    Autoplay Videos: 'Iniciar videos automáticamente'\n    Proxy Videos Through Invidious: 'Redirigir Videos a Través de Invidious'\n    Autoplay Playlists: 'Reproducción automática de videos de la lista de reproducción'\n    Enable Theatre Mode by Default: 'Habilitar modo cine por defecto'\n    Default Volume: 'Volumen por defecto'\n    Default Playback Rate: 'Velocidad de reproducción por defecto'\n    Default Video Format:\n      Default Video Format: 'Formato de video por defecto'\n      Dash Formats: 'Formatos de Transmisión de Video DASH'\n      Legacy Formats: 'Formatos antiguos'\n      Audio Formats: 'Formatos de audio'\n    Default Quality:\n      Default Quality: 'Calidad de video por defecto'\n      Auto: 'Automática'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n      1080p: 1080p\n    Screenshot:\n      Folder Label: Carpeta de capturas de pantalla\n      Error:\n        Empty File Name: Nombre de archivo vacío\n        Forbidden Characters: Caracteres prohibidos\n      Folder Button: Seleccionar carpeta\n      Format Label: Formato de las capturas de pantalla\n      Enable: Habilitar capturas de pantalla\n      Ask Path: Solicitar Carpeta de Guardado\n      Quality Label: Calidad de Captura de Pantalla\n      File Name Tooltip: 'Podés utilizar las siguientes variables: %Y Año (4 dígitos). %M Mes (2 dígitos). %D Día (2 dígitos). %H Hora (2 dígitos). %N Minuto (2 dígitos). %S Segundo (2 dígitos). %T Milisegundo (3 dígitos). %s Segundo del Video. %t Milisegundo del Video (3 dígitos). %i ID del Video.'\n      File Name Label: Formato de Nombre de Archivo\n    Scroll Volume Over Video Player: Barra de volumen en el reproductor\n    Skip by Scrolling Over Video Player: Saltar Deslizando sobre el Reproductor de Video\n    Scroll Playback Rate Over Video Player: Acelerar video con la rueda del mouse\n    Fast-Forward / Rewind Interval: Período de Avance Rápido / Retroceso\n    Video Playback Rate Interval: Intervalo entre velocidades del video\n    Max Video Playback Rate: Velocidad máxima de reproducción de video\n    Enter Fullscreen on Display Rotate: Cambiar a pantalla completa al girar la pantalla\n    Next Video Interval: Temporizador de reproducción automática\n    Display Play Button In Video Player: Mostrar botón de reproducir antes de empezar el video\n    Default Viewing Mode:\n      Default Viewing Mode: Modo de visualización predeterminado\n      Theater: Cine\n      Picture in Picture: Imagen en imagen\n      Full Screen: Pantalla completa\n      External Player: Reproductor externo ({externalPlayerName})\n    Autoplay Interruption Timer: Temporizador de interrupción de reproducción automática\n  Privacy Settings:\n    Privacy Settings: 'Privacidad'\n    Remember History: 'Recordar historial de reproducciones'\n    Save Watched Progress: 'Guardar el progreso observado'\n    Clear Search Cache: 'Borrar la caché de búsqueda'\n    Are you sure you want to clear out your search cache?: '¿Realmente deseas limpiar la caché de búsqueda?'\n    Search cache has been cleared: 'La caché de búsqueda ha sido borrada'\n    Remove Watch History: 'Borrar historial de videos vistos'\n    Are you sure you want to remove your entire watch history?: '¿Estás seguro de querer borrar tu historial completo de videos vistos?'\n    Watch history has been cleared: 'El historial de videos vistos ha sido borrado'\n    Remove All Subscriptions / Profiles: 'Remover todas las suscripciones / perfiles'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: '¿Realmente querés remover todas las suscripciones y perfiles? Esta acción no puede deshacerse.'\n    Save Watched Videos With Last Viewed Playlist: Guardar videos vistos con la última lista de reproducción vista\n    Clear Search History and Cache: Borrar historial de búsqueda y caché\n    Are you sure you want to clear out your search history and cache?: ¿Estás seguro de que querés borrar tu historial de búsqueda y caché?\n    Remember Search History: Recordar historial de búsquedas\n    Watched Progress Saving Mode:\n      Tooltip: Automático = Guarda al salir de cada página de video, cuando el video termina y cuando ocurre un error (por ejemplo, límite de velocidad o sesión de reproducción expirada). Semiautomático = Igual que Automático, excepto que no guarda al salir de la página de video. Se puede guardar el progreso manualmente usando el botón \"Guardar progreso de visualización\", ubicado debajo del reproductor de video.\n      Modes:\n        Never: Nunca\n        Auto: Automático\n        Semi-auto: Semiautomático\n    All playlists have been removed: Todas las listas de reproducción han sido eliminadas.\n    Search history and cache have been cleared: El historial de búsqueda y la caché han sido borrados.\n    Remove All Playlists: Eliminar todas las listas de reproducción\n    Are you sure you want to remove all your playlists?: ¿Estás seguro de que querés eliminar todas tus listas de reproducción?\n  Subscription Settings:\n    Subscription Settings: 'Suscripción'\n    Fetch Automatically: Obtener feed automáticamente\n    Fetch Feeds from RSS: Obtener feeds desde RSS\n    To: A\n    'Limit the number of videos displayed for each channel': Limitar la cantidad de videos mostrados por cada canal\n    Confirm Before Unsubscribing: Confirmar antes de darse de baja\n  Data Settings:\n    Data Settings: 'Datos'\n    Select Export Type: 'Seleccionar tipo para exportar'\n    Import Subscriptions: 'Importar suscripciones'\n    Export Subscriptions: 'Exportar suscripciones'\n    Export FreeTube: 'Exportar Freetube'\n    Export YouTube: 'Exportar Youtube'\n    Export NewPipe: 'Exportar NewPipe'\n    Import History: 'Importar historial'\n    Export History: 'Exportar historial'\n    All playlists has been successfully exported: Todas las listas de reproducción se han exportado con éxito\n    Playlist File: Archivo de lista de reproducción\n    History object has insufficient data, skipping item: El historial no tiene datos suficientes, omitiendo objeto\n    Subscription File: Archivo de suscripción\n    All watched history has been successfully imported: Historial de reproducciones se importó con éxito\n    How do I import my subscriptions?: ¿Cómo puedo importar mis suscripciones?\n    All subscriptions and profiles have been successfully imported: Suscripciones y perfiles se importaron con éxito\n    Unable to read file: No se pudo leer el archivo\n    Invalid subscriptions file: Archivo de suscripciones no válido\n    History File: Archivo de historial\n    Profile object has insufficient data, skipping item: El objeto de perfil tiene datos insuficientes, saltando elemento\n    All watched history has been successfully exported: Historial de reproducciones se exportó con éxito\n    Export Playlists: Exportar lista de reproducción\n    Manage Subscriptions: Administrar suscripciones\n    Import Playlists: Importar lista de reproducción\n    All playlists has been successfully imported: Todas sus listas han sido importadas con éxito\n    Subscriptions have been successfully exported: Suscripciones se exportaron con éxito\n    Playlist insufficient data: Datos insuficientes de la lista \"{playlist}\", omitiendo\n    All subscriptions have been successfully imported: Suscripciones se importaron con éxito\n    Unable to write file: No se pudo escribir el archivo\n    Unknown data key: Clave de datos desconocida\n    Invalid history file: Archivo de historial no válido\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"\\\"Esta opción exporta los videos de todas las listas de reproducción en una sola lista llamada 'Favoritos'.\\nCómo exportar e importar videos en listas de reproducción para una versión anterior de FreeTube:\\n\\nExportá tus listas de reproducción con esta opción activada.\\n\\nEliminá todas tus listas existentes usando la opción 'Eliminar todas las listas de reproducción' en la sección de Configuración de privacidad.\\n\\nIniciá la versión anterior de FreeTube e importá las listas de reproducción exportadas.\\\"\"\n      Label: Exportar listas de reproducción para versiones anteriores de FreeTube\n  Distraction Free Settings:\n    Hide Active Subscriptions: Ocultar suscripciones activas\n    Hide Live Chat: Ocultar chat en vivo\n    Hide Popular Videos: Ocultar videos populares\n    Hide Trending Videos: Ocultar videos en tendencia\n    Hide Recommended Videos: Ocultar videos recomendados\n    Hide Comment Likes: Ocultar los \"Me gusta\" de comentarios\n    Hide Channel Subscribers: Ocultar los suscriptores del canal\n    Hide Video Likes And Dislikes: Ocultar calificaciones del video\n    Hide Video Views: Ocultar vistas del video\n    Distraction Free Settings: Sin distracciones\n    Hide Channels Placeholder: ID del canal\n    Hide Video Description: Ocultar la descripción del vídeo\n    Hide Chapters: Ocultar los capítulos\n    Sections:\n      Watch Page: Ver la página\n      Side Bar: Barra lateral\n      Channel Page: Página del canal\n      Subscriptions Page: Página de suscripciones\n      General: General\n    Hide Subscriptions Videos: Ocultar las suscripciones de los videos\n    Hide Comments: Ocultar comentarios\n    Hide Channel Shorts: Ocultar la pestaña de 'Shorts' del canal\n    Hide Sharing Actions: Ocultar acciones de uso compartido\n    Hide Videos on Watch: 'Ocultar videos vistos'\n    Hide Channel Podcasts: Ocultar la pestaña de 'Podcasts' del canal\n    Hide Live Streams: Ocultar transmisiones en vivo\n    Hide Channel Playlists: Ocultar la pestaña de 'Listas de reproducción' del canal\n    Hide Channels: Ocultar los vídeos de los canales\n    Hide Subscriptions Live: Ocultar Suscripciones en Vivo\n    Hide Subscriptions Shorts: Ocultar las suscripciones para los Shorts\n    Display Titles Without Excessive Capitalisation: Mostrar títulos sin uso excesivo de mayúsculas y puntuación\n    Hide Featured Channels: Ocultar los canales recomendados\n    Hide Profile Pictures in Comments: Ocultar las fotos del perfil en los comentarios\n    Hide Upcoming Premieres: Ocultar próximos estrenos\n    Hide Channel Releases: Ocultar la pestaña de 'Lanzamientos' del canal\n    Hide Playlists: Ocultar listas de reproducción\n    Hide Channels Invalid: El ID del canal proporcionado no es válido.\n    Hide Channel Home: Ocultar la pestaña de 'Inicio' del canal\n    Hide Channels API Error: Error al obtener el usuario con el ID proporcionado. Por favor, verificá nuevamente si el ID es correcto.\n    Hide Channels Disabled Message: Algunos canales fueron bloqueados usando ID y no se procesaron. La función está bloqueada mientras se actualizan esos IDs.\n    Hide Videos, Playlists and Channels Containing Text: Ocultar videos y listas de reproducción que contengan texto\n    Hide Channels Already Exists: El ID del canal ya existe.\n    Hide Channel Courses: Ocultar la pestaña de 'Cursos' del canal\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Palabra, fragmento de palabra o frase\n    Show Added Items: Mostrar elementos agregados\n  The app needs to restart for changes to take effect. Restart and apply change?: Esta aplicación necesita reiniciarse para que los cambios entren en efecto. ¿Reiniciar y aplicar el cambio?\n  Proxy Settings:\n    Clicking on Test Proxy will send a request to: Hacer clic en Probar proxy enviará una solicitud a\n    Proxy Protocol: Protocolo de Proxy\n    Proxy Port Number: Puerto del Proxy\n    Region: Región\n    Country: País\n    City: Ciudad\n    Proxy Settings: Proxy\n    Ip: IP\n    Enable Tor / Proxy: Habilitar Tor/Proxy\n    Test Proxy: Probar proxy\n    Error getting network information. Is your proxy configured properly?: Error al recibir datos de la red. ¿Configuraste bien tu Proxy?\n    Your Info: Sus datos\n    Proxy Host: Host del Proxy\n    Proxy Warning: FreeTube no tiene un proxy integrado, pero puede conectarse a un proxy externo, como uno que se esté ejecutando en tu máquina (como Tor) o un proxy externo, como un proxy SOCKS5 provisto por algunas VPNs. Si activás esta opción, asegurate de que tu proxy o Tor esté configurado correctamente, de lo contrario FreeTube no podrá obtener datos.\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar cuando el tramo publicitario es omitido\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL de la API de SponsorBlock (https://sponsor.ajay.app por defecto)\n    Skip Options:\n      Skip Option: Omitir opción\n      Auto Skip: Salto Automático\n      Show In Seek Bar: Mostrar en la barra de búsqueda\n      Prompt To Skip: Avisar para omitir\n      Do Nothing: No hacer nada\n    UseDeArrowTitles: Utilizar «DeArrow» para los títulos de los videos\n    Enable SponsorBlock: Habilitar SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Category Color: Color de categoría\n    UseDeArrowThumbnails: Usar DeArrow para las miniaturas\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL de la API del generador de miniaturas DeArrow (la predeterminada es https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    External Player: Reproductor externo\n    External Player Settings: Reproductor externo\n    Custom External Player Executable: Reproductor externo personalizado\n    Ignore Unsupported Action Warnings: Ignorar advertencias de acciones no compatibles\n    Custom External Player Arguments: Argumentos del reproductor externo\n    Players:\n      None:\n        Name: Ninguno\n    Ignore Default Arguments: Ignorar argumentos predeterminados\n  Parental Control Settings:\n    Parental Control Settings: Control parental\n  Sort Settings Sections (A-Z): Ordenar secciones de configuración (A-Z)\n  Return to Settings Menu: Volver al menú de configuración\nAbout:\n  #On About page\n  Website: Sitio web\n  Email: Correo electrónico\n  Blog: Blog\nChannel:\n  Videos: {}\n  Playlists: {}\n  About:\n    Tags:\n      Search for: Buscar por «{tag}»\n    Details: Detalles\nYes: 'Sí'\nNo: 'No'\nA new blog is now available, {blogTitle}. Click to view more: 'Un nuevo blog está disponible, {blogTitle}. Hacé clic para ver más'\nDownload From Site: Descargar desde el sitio\nVersion {versionNumber} is now available!  Click for more details: La versión {versionNumber} ya está disponible. Hacé clic acá para más detalles\nMore: Más\nAre you sure you want to open this link?: ¿Está seguro que desea abrir este enlace?\nOpen New Window: Abrir nueva ventana\nSearch Bar:\n  Clear Input: Limpiar Entrada\n  Remove: Eliminar\nNew Window: Nueva ventana\nGlobal:\n  Counts:\n    Video Count: 1 vidéo | {count} vidéos\n    Subscriber Count: 1 suscriptor | {count} suscriptores\n    View Count: 1 vista | {count} vistas\n    Watching Count: 1 espectador | {count} espectadores\n    Channel Count: 1 canal | {count} canales\n    Like Count: 1 me gusta | {count} me gusta\n    Comment Count: 1 comentario | {count} comentarios\n  Posts: Publicaciones\n  Videos: Videos\n  Shorts: Shorts\n  Live: En vivo\n  Sort By: 'Ordenar por'\nChannels:\n  Search bar placeholder: Buscar Canales\n  Unsubscribe Prompt: ¿Deseás confirmar la desuscripción de \"{channelName}\"?\n  Channels: Canales\n  Title: Lista de canales\n  Empty: Tu lista de canales está actualmente vacía.\n  Count: '{number} canal(es) encontrado(s).'\nPreferences: Preferencias\nTooltips:\n  Distraction Free Settings:\n    Hide Subscriptions Live: Esta configuración se reemplaza por la configuración «{appWideSetting}» de toda la aplicación, en la sección «{subsection}» de «{settingsSection}»\nGo to page: Ir a {page}\nClose Banner: Cerrar banner\nSearch Listing:\n  Label:\n    3D: 3D\n    Closed Captions: Subtítulos cerrados\n    8K: 8K\n    VR180: VR180 (realidad virtual 180°)\n    4K: Resolución 4K\n    Subtitles: Subtítulos\n    360 Video: 360°\n    New: Nuevo\nFeed:\n  Refresh Feed: Actualizar {subscriptionName}\n  Feed Last Updated: 'Última actualización del feed de {feedName}: {date}'\nRight-click or hold to see history: Haz clic derecho o mantén presionado para ver el historial\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Activar/Desactivar Herramientas de Desarrollo\n  Zoom Out: Alejarse\n  Zoom In: Acercarse\n  Fullscreen: Alternar pantalla completa\nProfile:\n  Select All: Seleccionar todo\n"
  },
  {
    "path": "static/locales/es-MX.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Archivo'\nQuit: 'Salir'\nEdit: 'Editar'\nUndo: 'Deshacer'\nRedo: 'Rehacer'\nCut: 'Cortar'\nCopy: 'Copiar'\nPaste: 'Pegar'\nDelete: 'Eliminar'\nSelect all: 'Seleccionar todo'\nToggle Developer Tools: 'Herramientas para desarrolladores'\nActual size: 'Escala : 100%'\nZoom in: 'Ampliar'\nZoom out: 'Reducir'\nToggle fullscreen: 'Pantalla completa'\nWindow: 'Ventana'\nMinimize: 'Minimizar'\nClose: 'Cerrar'\nBack: 'Volver'\nForward: 'Adelante'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videos'\n\n# Search Bar\n  Posts: Publicaciones\n  Live: En vivo\n  Sort By: 'Ordenar por'\n  Counts:\n    View Count: 1 vista | {count} vistas\n    Channel Count: 1 canal | {count} canales\n    Video Count: 1 video | {count} vídeos\n    Subscriber Count: 1 suscriptor | {count} suscriptores\n    Watching Count: 1 viendo | {count} viendo\n    Like Count: 1 me gusta | {count} me gustas\n    Comment Count: 1 comentario | {count} comentarios\n  Shorts: Shorts\nSearch / Go to URL: 'Buscar / Ir a la URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtros de búsqueda'\n  Sort By:\n    Most Relevant: 'Más relevante'\n    Rating: 'Clasificación'\n    Upload Date: 'Fecha de carga'\n    View Count: 'Recuento de vistas'\n  Time:\n    Time: 'Tiempo'\n    Any Time: 'Cualquier momento'\n    Last Hour: 'Última hora'\n    Today: 'Hoy'\n    This Week: 'Esta semana'\n    This Month: 'Este mes'\n    This Year: 'Este año'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Todos tipos'\n    Videos: 'Videos'\n    Channels: 'Canales'\n    #& Playlists\n    Movies: Películas\n  Duration:\n    Duration: 'Duración'\n    All Durations: 'Todas las duraciones'\n    Short (< 4 minutes): 'Corto (< 4 minutos)'\n    Long (> 20 minutes): 'Largo (> 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Medio (4 - 20 minutos)\n  Search Results: 'Resultados de búsqueda'\n  Fetching results. Please wait: 'Obteniendo más resultados. Por favor espere'\n  Fetch more results: 'Obtener más resultados'\n# Sidebar\n  There are no more results for this search: No hay más resultados para ésta búsqueda\n  Features:\n    Features: Características\n    Subtitles: Subtitulos\n    HD: HD\n    Live: En vivo\n    4K: 4K\n    360 Video: Video 360\n    Location: Ubicación\n    HDR: HDR\n    VR180: VR180\n    Creative Commons: Comunes Creativos\n    3D: 3D\n  Clear Filters: Limpiar Filtros\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Suscripciones'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tu lista de suscripciones está actualmente vacía. Si deseas importar tus suscripciones, puedes ir a Configuración de datos y seleccionar Importar suscripciones, o puedes buscar un canal y suscribirte a él.'\n  Load More Videos: Cargar más videos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil tiene un gran número de suscripciones. Forzando RSS para evitar limitaciones\n  Error Channels: Canales con errores\n  Empty Channels: Sus canales suscritos no tienen ningún video actualmente.\n  Disabled Automatic Fetching: Has deshabilitado la obtención automática de suscripciones. Actualiza las suscripciones para verlas aquí.\n  All Subscription Tabs Hidden: Todas las pestañas de suscripciones están ocultas. Para ver contenido aquí, por favor desoculta algunas pestañas en la sección '{subsection}' en '{settingsSection}'.\n  Subscriptions Tabs: Pestañas de suscripciones\n  Empty Posts: Tus canales suscritos actualmente no tienen publicaciones.\n  Load More Posts: Cargar más publicaciones\nTrending:\n  Trending: 'Tendencias'\n  Gaming: Juegos\n  Trending Tabs: Tendencias\nMost Popular: 'Más Popular'\nPlaylists: 'Listas de Reproducción'\nUser Playlists:\n  Your Playlists: 'Tus Listas de Reproducción'\n  Search bar placeholder: Buscar en la listas de reproducción\n  Empty Search Message: No hay videos en esta lista de reproducción que coincidan con su búsqueda\n  SinglePlaylistView:\n    Toast:\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Esta lista de reproducción ahora se usa para marcadores rápidos en lugar de {oldPlaylistName}. Haz clic aquí para deshacer.\n      Reverted to use {oldPlaylistName} for quick bookmark: Se revertió para usar {oldPlaylistName} como marcador rápido.\n      This playlist is protected and cannot be removed.: Esta lista de reproducción está protegida y no se puede eliminar.\n      Playlist {playlistName} has been deleted.: La lista de reproducción {playlistName} ha sido eliminada.\n      \"{videoCount} video(s) have been removed\": 1 video ha sido eliminado | {videoCount} videos han sido eliminados\n      There was an issue with updating this playlist.: Hubo un problema al actualizar esta lista de reproducción.\n      Playlist has been updated.: La lista de reproducción ha sido actualizada.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Algunos videos en la lista de reproducción aún no se han cargado. Haz clic aquí para copiar de todos modos.\n      Playlist name cannot be empty. Please input a name.: El nombre de la lista de reproducción no puede estar vacío. Por favor, ingresa un nombre.\n      There were no videos to remove.: No había videos para eliminar.\n      This video cannot be moved up.: Este vídeo no se puede mover.\n    Search for Videos: Buscar videos\n  You have no playlists. Click on the create new playlist button to create a new one.: No tienes listas de reproducción. Haz clic en el botón de crear nueva lista de reproducción para crear una nueva.\n  Playlists with Matching Videos: Listas de reproducción con videos coincidentes\n  Remove from Favorites: Eliminar de {playlistName}\n  Move Video Down: Mover video hacia abajo\n  Enable Quick Bookmark With This Playlist: Habilitar marcador rápido con esta lista de reproducción\n  Delete Playlist: Eliminar lista de reproducción\n  Are you sure you want to delete this playlist? This cannot be undone: ¿Estás seguro de que deseas eliminar esta lista de reproducción? Esto no se puede deshacer.\n  Sort By:\n    LatestCreatedFirst: Fecha de creación (más reciente)\n    EarliestCreatedFirst: Fecha de creación (más antiguo)\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestUpdatedFirst: Fecha de actualización (más reciente)\n    EarliestUpdatedFirst: Fecha de actualización (más antigua)\n    EarliestPlayedFirst: Fecha de reproducción (más antiguo)\n    LatestPlayedFirst: Fecha de reproducción (más reciente)\n  Export Playlist: Exportar esta lista de reproducción\n  The playlist has been successfully exported: La lista de reproducción ha sido exportada con éxito\n  This playlist currently has no videos.: Esta lista de reproducción no tiene videos actualmente.\n  Cancel: Cancelar\n  Save Changes: Guardar cambios\n  Remove Watched Videos: Eliminar videos vistos\n  Create New Playlist: Crear nueva lista de reproducción\n  Add to Playlist: Agregar a la lista de reproducción\n  Add to Favorites: Agregar a Mi Lista Favorita\n  Playlist Description: Descripción de la lista de reproducción\n  Edit Playlist Info: Editar información de la lista de reproducción\n  Copy Playlist: Copiar lista de reproducción\n  Cannot delete the quick bookmark target playlist.: No se puede eliminar la lista de reproducción objetivo del marcador rápido.\n  Quick Bookmark Enabled: Marcador rápido habilitado\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Estás seguro de que deseas eliminar 1 video duplicado de esta lista de reproducción? Esto no se puede deshacer.\n  Move Video Up: Mover video hacia arriba\n  TotalTimePlaylist: 'Tiempo total: {duration}'\n  Remove from Playlist: Eliminar de la lista de reproducción\n  Playlist Name: Nombre de la lista de reproducción\n  Remove Duplicate Videos: Eliminar videos duplicados\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ¿Estás seguro de que deseas eliminar 1 video visto de esta lista de reproducción? Esto no se puede deshacer.\n  AddVideoPrompt:\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: Aún no has seleccionado ninguna playlist.\n    Save: Guardar\n    Allow Adding Duplicate Video(s): Permitir agregar videos duplicados\n    Added {count} Times: Ya agregado | Agregado {count} veces\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videos ya agregados'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": Se agregarán {videoCount}/{totalVideoCount} videos\n  CreatePlaylistPrompt:\n    Toast:\n      Playlist {playlistName} has been successfully created.: La playlist {playlistName} ha sido creada exitosamente.\n      There is already a playlist with this name. Please pick a different name.: Ya existe una playlist con este nombre. Por favor, elige otro nombre.\n      There was an issue with creating the playlist.: Hubo un problema al crear la playlist.\n    New Playlist Name: Nombre de la nueva playlist\n    Create: Crear\n  Export list of URLs: Exportar lista de URL\nHistory:\n  # On History Page\n  History: 'Historial'\n  Watch History: 'Ver Historial'\n  Your history list is currently empty.: 'Tu lista de historial está actualmente vacía.'\n  Empty Search Message: No hay videos en su historial que coincidan con su búsqueda\n  Search bar placeholder: Buscar en el Historial\n  Case Sensitive Search: Búsqueda sensible a mayúsculas/minúsculas\nSettings:\n  # On Settings Page\n  Settings: 'Ajustes'\n  General Settings:\n    General Settings: 'Ajustes generales'\n    Fallback to Non-Preferred Backend on Failure: 'Recurrir a otro motor en caso de fallo'\n    Enable Search Suggestions: 'Activar sugerencias de búsqueda'\n    Default Landing Page: 'Página de destino predeterminada'\n    Locale Preference: 'Ajustes de ubicación'\n    Preferred API Backend:\n      Preferred API Backend: 'API principal'\n      Local API: 'API Local'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Tipo de vista de video'\n      Grid: 'Cuadrícula'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencias de miniatura'\n      Default: 'Predeterminado'\n      Beginning: 'Comienzo'\n      Middle: 'Medio'\n      End: 'Fin'\n      Hidden: Oculto\n      Blur: Desenfoque\n    Region for Trending: 'Tendencia por región'\n        #! List countries\n    Check for Updates: Buscar actualizaciones\n    Check for Latest Blog Posts: Compruebe las últimas publicaciones del blog\n    Current instance will be randomized on startup: La dirección actual será aleatorizada al iniciar la app\n    System Default: Por defecto\n    Current Invidious Instance: 'Dirección de Invidious actual:'\n    The currently set default instance is {instance}: La dirección por defecto actualmente establecida es {instance}\n    No default instance has been set: No se ha establecido ninguna dirección por defecto\n    Set Current Instance as Default: Establecer la dirección actual por defecto\n    Clear Default Instance: Borrar dirección por defecto\n    View all Invidious instance information: Ver la información de todas las direcciones de Invidious\n    External Link Handling:\n      No Action: No proceder\n      Ask Before Opening Link: Preguntar antes de abrir\n      External Link Handling: 'Al abrir un link externo:'\n      Open Link: Abrir enlace\n    Auto Load Next Page:\n      Label: Cargar automáticamente la siguiente página\n      Tooltip: Cargar automáticamente páginas y comentarios adicionales.\n    Open Deep Links In New Window: Abrir las URL enviadas a FreeTube en una nueva ventana\n  Theme Settings:\n    Theme Settings: 'Ajustes de apariencia'\n    Match Top Bar with Main Color: 'Igualar la barra superior con el color principal'\n    Base Theme:\n      Base Theme: 'Apariencia base'\n      Black: 'Negro'\n      Dark: 'Oscuro'\n      Light: 'Claro'\n      Dracula: 'Drácula'\n      System Default: Por defecto\n      Nordic: Nórdico\n      Pastel Pink: Rosa Pastel\n      Hot Pink: Rosa Fucsia\n      Solarized Dark: Solarized Dark\n      Catppuccin Frappe: Catppuccin Frappe\n      Catppuccin Mocha: Catppuccin Mocha\n      Gruvbox Light: Gruvbox Light\n      Gruvbox Dark: Gruvbox Dark\n    Main Color Theme:\n      Main Color Theme: 'Color principal de la apariencia'\n      Red: 'Rojo'\n      Pink: 'Rosado'\n      Purple: 'Morado'\n      Deep Purple: 'Morado profundo'\n      Indigo: 'Indigo'\n      Blue: 'Azul'\n      Light Blue: 'Azul claro'\n      Cyan: 'Cian'\n      Teal: 'Verde agua'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Lima'\n      Yellow: 'Amarillo'\n      Amber: 'Ámbar'\n      Orange: 'Naranja'\n      Deep Orange: 'Naranja profundo'\n      Dracula Cyan: 'Drácula Cian'\n      Dracula Green: 'Drácula Verde'\n      Dracula Orange: 'Drácula Naranja'\n      Dracula Pink: 'Drácula Rosado'\n      Dracula Purple: 'Drácula Púrpura'\n      Dracula Red: 'Drácula Rojo'\n      Dracula Yellow: 'Drácula Amarillo'\n    Secondary Color Theme: 'Color secundario de la apariencia'\n        #* Main Color Theme\n    Expand Side Bar by Default: Expandir barra lateral por defecto\n    UI Scale: Escala de la interfaz\n    Disable Smooth Scrolling: Desactivar desplazamiento suave\n    Hide Side Bar Labels: Ocultar etiquetas de la barra lateral\n    Hide FreeTube Header Logo: Ocultar el logo del encabezado de FreeTube\n  Player Settings:\n    Player Settings: 'Reproductor'\n    Play Next Video: 'Reproducir automáticamente videos recomendados'\n    Turn on Subtitles by Default: 'Habilitar subtítulos por defecto'\n    Autoplay Videos: 'Iniciar videos automáticamente'\n    Proxy Videos Through Invidious: 'Enmascarar videos a través de invidious'\n    Autoplay Playlists: 'Reproducir automáticamente los videos de la lista de reproducción'\n    Enable Theatre Mode by Default: 'Activar modo teatro por defecto'\n    Default Volume: 'Volumen predeterminado'\n    Default Playback Rate: 'Velocidad de reproducción predeterminada'\n    Default Video Format:\n      Default Video Format: 'Formato de video predeterminado'\n      Dash Formats: 'Formatos DASH'\n      Legacy Formats: 'Formatos heredados'\n      Audio Formats: 'Formatos de audio'\n    Default Quality:\n      Default Quality: 'Calidad predeterminada'\n      Auto: 'Automático'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Display Play Button In Video Player: Mostrar botón de reproducir antes de empezar el video\n    Scroll Playback Rate Over Video Player: Acelerar video con la rueda del ratón\n    Next Video Interval: Intervalo para el video siguiente\n    Scroll Volume Over Video Player: Barra de volumen sobre el reproductor\n    Max Video Playback Rate: Velocidad máxima del video\n    Video Playback Rate Interval: Intervalo entre velocidades del video\n    Fast-Forward / Rewind Interval: Intervalo para adelantar/retrasar el video\n    Default Viewing Mode:\n      Full Screen: Pantalla completa\n      Picture in Picture: Imagen en imagen\n      Theater: Teatro\n      Default Viewing Mode: Modo de visualización predeterminado\n      External Player: Reproductor externo ({externalPlayerName})\n    Skip by Scrolling Over Video Player: Saltar desplazando sobre el reproductor de video\n    Screenshot:\n      Error:\n        Empty File Name: Nombre de archivo vacío\n        Forbidden Characters: Caracteres Prohibidos\n      File Name Tooltip: Puedes usar las siguientes variables. %Y Año 4 dígitos. %M Mes 2 dígitos. %D Día 2 dígitos. %H Hora 2 dígitos. %N Minuto 2 dígitos. %S Segundo 2 dígitos. %T Milisegundo 3 dígitos. %s Segundo del video. %t Milisegundo del video 3 dígitos. %i ID del video.\n  Subscription Settings:\n    Subscription Settings: 'Ajustes de suscripción'\n    Fetch Feeds from RSS: Buscar Información desde RSS\n\n  Privacy Settings:\n    Search cache has been cleared: Se ha borrado la caché de búsqueda\n    Are you sure you want to clear out your search cache?: ¿Está seguro de que desea borrar su caché de búsqueda?\n    Clear Search Cache: Borrar Caché de Búsqueda\n    Remember History: Recuerda Historial\n    Privacy Settings: Ajustes de privacidad\n    Watch history has been cleared: El historial de vistas ha sido borrado\n    Are you sure you want to remove your entire watch history?: Estas seguro que quiere eliminar todo tu historial de vistas?\n    Remove Watch History: Eliminar historial de vistas\n    Save Watched Progress: Guardar el progreso observado\n    Remove All Subscriptions / Profiles: Eliminar todos los suscripciones / perfiles\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ¿Estás seguro de que deseas eliminar todos los suscripciones y perfiles? Esto no puede ser deshecho.\n    Watched Progress Saving Mode:\n      Modes:\n        Semi-auto: Semi-automático\n        Auto: Automático\n        Never: Nunca\n      Tooltip: Automático = Guardar en cada salida de página de video, cuando el video termine y se encuentre un error (por ejemplo, cuando se limite la tasa o la sesión de visualización haya expirado). Semi-automático = Igual que Automático, excepto al salir de la página del video y se puede guardar el progreso manualmente mediante un botón llamado 'Guardar progreso visto', ubicado debajo del reproductor de video.\n    Remember Search History: Recordar el historial de búsquedas\n  Data Settings:\n    How do I import my subscriptions?: ¿Cómo puedo importar mis suscripciones?\n    Export History: Exportar Historia\n    Import History: Importar Historia\n    Export NewPipe: Exportar NewPipe\n    Export YouTube: Exportar YouTube\n    Export FreeTube: Exportar FreeTube\n    Export Subscriptions: Exportar Suscripciones\n    Import Subscriptions: Importar Suscripciones\n    Select Export Type: Seleccionar tipo de exportación\n    Data Settings: Ajustes de datos\n    All watched history has been successfully exported: Historial de reproducciones se exportó con éxito\n    All watched history has been successfully imported: Historial de reproducciones se importó con éxito\n    All subscriptions and profiles have been successfully imported: Suscripciones y perfiles se importaron con éxito\n    All subscriptions have been successfully imported: Suscripciones se importaron con éxito\n    Subscriptions have been successfully exported: Suscripciones se exportaron con éxito\n    Invalid subscriptions file: Archivo de suscripciones no válido\n    Invalid history file: Archivo de historia no válido\n    Unknown data key: Clave de datos desconocida\n    Unable to write file: El archivo no se puede escribir\n    Unable to read file: El archivo no se puede leer\n    History object has insufficient data, skipping item: El objeto de historial tiene datos insuficientes, ignorando artículo\n    Profile object has insufficient data, skipping item: El objeto de perfil tiene datos insuficientes, ignorando artículo\n    Import Playlists: Importar listas de reproducción\n    Export Playlists: Exportar listas de reproducción\n    All playlists has been successfully exported: Todas sus listas de reproducción han sido exportadas con éxito\n    All playlists has been successfully imported: Todas sus listas han sido importadas con éxito\n    Playlist insufficient data: Datos insuficientes de la lista \"{playlist}\", omitiendo\n    Manage Subscriptions: Administrar suscripciones\n  The app needs to restart for changes to take effect. Restart and apply change?: El programa requiere reiniciarse para que los cambios hagan efecto. ¿Desea reiniciar para aplicar los cambios?\n  Proxy Settings:\n    Proxy Host: Host del Proxy\n    Enable Tor / Proxy: Habilitar Tor/Proxy\n    Region: Estado\n    City: Ciudad\n    Error getting network information. Is your proxy configured properly?: Error al recibir datos de la red. ¿Configuró bien su Proxy?\n    Proxy Settings: Configuración del Proxy\n    Proxy Port Number: Puerto del Proxy\n    Proxy Protocol: Protocolo de Proxy\n    Test Proxy: Probar Proxy\n    Clicking on Test Proxy will send a request to: Al cliquear \"Probar Proxy\" se enviará una solicitud a\n    Your Info: Sus datos\n    Country: País\n    Ip: Ip\n  Distraction Free Settings:\n    Hide Video Likes And Dislikes: Ocultar los \"Me gusta\" y \"No me gusta\" del video\n    Hide Popular Videos: Ocultar los videos populares\n    Hide Playlists: Ocultar las listas de reproducción\n    Distraction Free Settings: Configuración de distractores\n    Hide Video Views: Ocultar vistas del video\n    Hide Channel Subscribers: Ocultar los suscriptores del canal\n    Hide Comment Likes: Ocultar los \"Me gusta\" de los comentarios\n    Hide Recommended Videos: Ocultar videos recomendados\n    Hide Trending Videos: Ocultar los videos en tendencia\n    Hide Live Chat: Ocultar chat en vivo\n    Hide Active Subscriptions: Ocultar suscripciones activas\n    Hide Chapters: Ocultar capítulos\n    Hide Live Streams: Ocultar transmisiones en vivo\n    Hide Channels: Ocultar videos de los canales\n    Hide Channels Disabled Message: Algunos canales fueron bloqueados usando ID y no fueron procesados. La función está bloqueada mientras esos IDs se actualizan.\n    Hide Upcoming Premieres: Ocultar estrenos próximos\n    Hide Channels Placeholder: ID del canal\n    Hide Channels Invalid: El ID del canal proporcionado no es válido.\n    Hide Sharing Actions: Ocultar acciones de compartición\n    Hide Videos on Watch: 'Ocultar videos vistos'\n  External Player Settings:\n    External Player: 'Reproductor externo:'\n    Ignore Unsupported Action Warnings: Ignorar advertencias de acciones inválidas\n    Custom External Player Executable: Ejecutable del reproductor externo\n    Custom External Player Arguments: Argumentos para el reproductor externo\n    External Player Settings: Opciones de reproductor externo\n    Ignore Default Arguments: Ignorar los argumentos predeterminados\n    Players:\n      None:\n        Name: Ninguno\n  SponsorBlock Settings:\n    SponsorBlock Settings: Configuración de SponsorBlock\n    Enable SponsorBlock: Habilitar SponsorBlock\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL de la API de SponsorBlock (https://sponsor.ajay.app por defecto)\n    Notify when sponsor segment is skipped: Notificar cuando el tramo publicitario es omitido\n  Sort Settings Sections (A-Z): Ordenar secciones de configuración (A-Z)\n  Return to Settings Menu: Volver al menú de configuración\nAbout:\n  #On About page\n  About: 'Acerca de'\n  #& About\n#On Channel Page\n  Blog: Blog\n  Website: Sitio web\n  Email: Correo electrónico\n  Mastodon: Mastodon\n  Source code: Código fuente\n  Beta: Beta\n  Downloads / Changelog: Descargas / Informe de cambios\n  GitHub releases: Lanzamientos en GitHub\n  Help: Ayuda\n  FreeTube Wiki: Wiki de FreeTube\n  Please check for duplicates before posting: Por favor evite repetir preguntas\n  FAQ: Preguntas Frecuentes\n  Report a problem: Reportar un problema\n  GitHub issues: Reportar en GitHub\n  room rules: reglas de la sala\n  Chat on Matrix: Contáctenos en Matrix\n  Translate: Traducir\n  these people and projects: estas personas y proyectos\n  Donate: Donar\n  Credits: Créditos\nChannel:\n  Subscribe: 'Suscribir'\n  Unsubscribe: 'Desuscribir'\n  Search Channel: 'Buscar canal'\n  Your search results have returned 0 results: 'Los resultados de su búsqueda han arrojado 0 resultados'\n  Videos:\n    Videos: 'Videos'\n    This channel does not currently have any videos: 'Este canal no tiene ningun video actualmente'\n    Sort Types:\n      Newest: 'Mas nuevo'\n      Oldest: 'Mas viejo'\n      Most Popular: 'Mas popular'\n  Playlists:\n    Playlists: 'Listas de Reproducción'\n    This channel does not currently have any playlists: 'Este canal no tiene ninguna lista de reproducción actualmente'\n    Sort Types:\n      Last Video Added: 'Último Vídeo Añadido'\n      Newest: 'Mas nuevo'\n      Oldest: 'Mas viejo'\n  About:\n    About: 'Acerca de'\n    Channel Description: 'Descripción del canal'\n    Featured Channels: 'Canales destacados'\n    Tags:\n      Search for: Buscar por «{tag}»\n    Details: Detalles\n  Added channel to your subscriptions: Canal añadido a sus suscripciones\n  Removed subscription from {count} other channel(s): Suscripción eliminada de {count} otros canales\n  Channel has been removed from your subscriptions: El canal ha sido eliminado de sus suscripciones\nVideo:\n  Mark As Watched: 'Marcar como visto'\n  Remove From History: 'Borrar del historial'\n  Video has been marked as watched: 'El vídeo ha sido marcado como visto'\n  Video has been removed from your history: 'El vídeo se ha borrado de tu historial'\n  Open in YouTube: 'Abrir en Youtube'\n  Copy YouTube Link: 'Copiar enlace de YouTube'\n  Open YouTube Embedded Player: 'Abrir el reproductor incrustado de YouTube'\n  Copy YouTube Embedded Player Link: 'Copiar enlace del reproductor incrustado de YouTube'\n  Open in Invidious: 'Abrir en Invidious'\n  Copy Invidious Link: 'Copiar enlace de Invidious'\n  Views: 'Vistas'\n  Watched: 'Visto'\n  # As in a Live Video\n  Live: 'En vivo'\n  Live Now: 'En vivo'\n  Live Chat: 'Chat en vivo'\n  Enable Live Chat: 'Activar chat en vivo'\n  Live Chat is currently not supported in this build.: 'El chat en vivo no esta soportado actualmente en esta compilación.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'El chat en vivo esta activado. Los mensajes del chat aparecerán aquí cuando sean enviados.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'El chat en vivo no esta soportado actualmente con la API de Invidious. Es necesaria una conexión directa a YouTube.'\n  Published on: 'Publicado en'\n#& Videos\n  Autoplay: Reproducción Automática\n  Previous: Anterior\n  Next: Siguiente\n  Reverse Playlist: Lista de reproducción invertida\n  Shuffle Playlist: Lista de reproducción aleatoria\n  Loop Playlist: Lista de reproducción en bucle\n  Video has been removed from your saved list: El video se ha eliminado de su lista de guardado\n  Video has been saved: Video guardado\n  Starting soon, please refresh the page to check again: Empezará pronto, por favor actualice la página para volver a revisar\n  External Player:\n    Unsupported Actions:\n      reversing playlists: revirtiendo listas\n      starting video at offset: Video iniciando con retraso\n      setting a playback rate: fijando velocidad de reproducción\n      opening playlists: abriendo listas de reproducción\n      opening specific video in a playlist (falling back to opening the video): abriendo el video específico en una lista (reponiéndolo para abrir el video)\n      looping playlists: listas de reproducción en bucle\n      shuffling playlists: listas de reproducción mezcladas\n    OpeningTemplate: Abriendo {videoOrPlaylist} en {externalPlayer}...\n    UnsupportedActionTemplate: '{externalPlayer} no soporta: {action}'\n    OpenInTemplate: Abrir en {externalPlayer}\n    video: video\n    playlist: lista de reproducción\n  Sponsor Block category:\n    interaction: interacción\n    sponsor: publicitante\n    intro: introducción\n    outro: final\n    self-promotion: auto-promoción\n    music offtopic: música irrelevante\n  Save Video: Guardar video\n  Streamed on: Transmitido en\n  Open Channel in YouTube: Abrir canal en YouTube\n  Started streaming on: Empezó a transmitir\n  Open Channel in Invidious: Abrir canal en Invidious\n  Copy Invidious Channel Link: Copiar link del canal en Invidious\n  Copy YouTube Channel Link: Copiar link del canal en YouTube\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Ver lista de reproducción completa'\n  Last Updated On: 'Última actualización el'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lista de reproducción\nChange Format:\n  Change Media Formats: 'Cambia formatos de vídeo'\n  Use Dash Formats: 'Usar formatos DASH'\n  Use Legacy Formats: 'Usar formatos heredados'\n  Use Audio Formats: 'Usa formatos de audio'\n  Audio formats are not available for this video: Los formatos de audio no están disponibles por este video\n  Dash formats are not available for this video: Formatos DASH no disponibles para este video\nShare:\n  Share Video: 'Compartir Video'\n  Share Playlist: 'Compartir lista de reproducción'\n  Copy Link: 'Copiar enlace'\n  Open Link: 'Abrir enlace'\n  Copy Embed: 'Copiar incrustado'\n  Open Embed: 'Abrir incrustado'\n  # On Click\n  Invidious URL copied to clipboard: 'La URL de Invidious ha sido copiado al portapapeles'\n  Invidious Embed URL copied to clipboard: 'URL incrustada de Invidious copiada al portapapeles'\n  YouTube URL copied to clipboard: 'La URL de Youtube ha sido copiado al portapapeles'\n  YouTube Embed URL copied to clipboard: 'URL incrustada de YouTube copiada al portapapeles'\n  Include Timestamp: Incluir marca del tiempo\n  YouTube Channel URL copied to clipboard: Link del canal en YouTube copiado al portapapeles\n  Invidious Channel URL copied to clipboard: Link del canal en Invidious copiado al portapapeles\nMini Player: 'Mini reproductor'\nComments:\n  Comments: 'Comentarios'\n  Click to View Comments: 'Presione para Ver Comentarios'\n  Getting comment replies, please wait: 'Recibiendo respuestas de comentarios, por favor espere'\n  Hide Comments: 'Esconde comentarios'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'No hay comentarios disponibles para este video'\n  Load More Comments: 'Cargar Más Comentarios'\n  Top comments: Más populares\n  Member: Miembro\n  Pinned by: Fijado por\n  There are no more comments for this video: No hay más comentarios en este video\n  Newest first: Más recientes\n  Show More Replies: Mostrar más respuestas\nUp Next: 'A continuación'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Error de la API local (Presione para copiar)'\nInvidious API Error (Click to copy): 'Error de la API de Invidious (Presione para copiar)'\nFalling back to Invidious API: 'Recurriendo a la API de Invidious'\nFalling back to Local API: 'Recurriendo a la API local'\nLoop is now disabled: 'El bucle esta desactivado'\nLoop is now enabled: 'El bucle esta activado'\nShuffle is now disabled: 'La reproducción aleatoria se ha desactivada'\nShuffle is now enabled: 'La reproducción aleatoria se ha activado'\nPlaying Next Video: 'Reproduciendo el video siguiente'\nPlaying Previous Video: 'Reproduciendo el video anterior'\nCanceled next video autoplay: 'Reproducción automática del siguiente video cancelado'\n'The playlist has ended. Enable loop to continue playing': 'La lista de reproducción ha terminado. Activa el bucle para continuar reproduciendo'\n\nYes: 'Sí'\nNo: 'No'\nLocale Name: español (MX)\nProfile:\n  '{profile} is now the active profile': '{profile} ahora es el perfil activo'\n  Your default profile has been changed to your primary profile: Su perfil predeterminado se ha cambiado a su perfil principal\n  Removed {profile} from your profiles: Se eliminó {profile} de sus perfiles\n  Your default profile has been set to {profile}: Su perfil predeterminado ha sido establecido a {profile}\n  Profile has been updated: El perfil ha sido actualizado\n  Profile has been created: El profil ha sido creado\n  Your profile name cannot be empty: Su nombre de perfil no puede estar vacío\n  All subscriptions will also be deleted.: Todas las suscripciones serán borradas también.\n  Are you sure you want to delete this profile?: ¿Está seguro que quiere borrar este perfil?\n  Delete Profile: Borrar Perfil\n  Make Default Profile: Hacer perfil predeterminado\n  Update Profile: Actualizar Perfil\n  Create Profile: Crear Perfil\n  Profile Preview: Vista previa del perfil\n  Custom Color: Color personalizado\n  Color Picker: Selector de color\n  Edit Profile: Editar Perfil\n  Create New Profile: Crear Perfil Nuevo\n  Profile Manager: Gestor de Perfiles\n  All Channels: Todos Los Canales\n  Profile Select: Selección de perfil\n  Select None: No Seleccionar Ninguno\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Este es su perfil principal. ¿Estás seguro de que quieres borrar los canales seleccionados? Los mismos canales serán borrados de cualquier perfil en el que se encuentren.\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ¿Estás seguro de que quieres borrar los canales seleccionados? Esto no se borrará el canal de ningún otro perfil.\n  No channel(s) have been selected: Ningún canal ha sido seleccionado\n  Add Selected To Profile: Añadir Seleccionado al Perfil\n  Delete Selected: Borrar Seleccionado\n  Select All: Seleccionar Todo\n  '{number} selected': '{number} seleccionado'\n  Other Channels: Otros Canales\n  Subscription List: Lista de Suscripciones\n  Profile Filter: Filtro de Perfil\n  Profile Settings: Configuración de perfil\nThe playlist has been reversed: La lista de reproducción ha sido invertida\nA new blog is now available, {blogTitle}. Click to view more: Un nuevo blog ya está disponible, {blogTitle}. Presione para ver más\nDownload From Site: Descargar desde el sitio\nVersion {versionNumber} is now available!  Click for more details: Versión {versionNumber} ya está disponible! Presione para más detalles\nOpen New Window: Abrir nueva ventana\nMore: Más\nAre you sure you want to open this link?: ¿Estás seguro de abrir este link?\nSearch Bar:\n  Clear Input: Limpiar entrada\n  Remove: Eliminar\nTooltips:\n  General Settings:\n    Preferred API Backend: Elija el método que usará FreeTube para obtener datos. La API local es un recolector integrado. La API de Invidious requerirá un servidor al cual conectarse.\n    Invidious Instance: La dirección de Invidious a la que FreeTube se conectará para solicitudes de la API.\n    Region for Trending: La región de tendencias le permitirá elegir las tendencias del país que deseé ver mostradas.\n    Thumbnail Preference: Todas las miniaturas a través de FreeTube serán reemplazadas con un fotograma del video en vez de su miniatura por defecto.\n    External Link Handling: \"Elija el comportamiento previsto para cuando un link, que no pueda ser abierto en FreeTube, sea cliqueado.\\nPor defecto FreeTube abrirá el link cliqueado en su navegador predeterminado.\\n\"\n    Fallback to Non-Preferred Backend on Failure: Si la API que eligió sufre algún problema, FreeTube intentará usar automáticamente otra API como método de respaldo al activar esta opción.\n  External Player Settings:\n    Custom External Player Arguments: Cualquier argumento, que deseé anticipar al reproductor externo.\n    DefaultCustomArgumentsTemplate: \"(Por defecto: '{defaultCustomArguments}')\"\n    External Player: Elegir un reproductor externo mostrará un ícono, para abrir el video (o lista, si es compatible) en el reproductor externo, sobre la miniatura del video.\n    Custom External Player Executable: Por defecto, FreeTube asumirá que el reproductor externo elegido estará en la ruta variable del entorno (PATH environment variable). De ser necesario, coloque aquí una ruta personalizada.\n    Ignore Warnings: Ignorar advertencias en caso de que el reproductor externo sea incompatible con la acción solicitada (p. ej. revertir listas de reproducción, etc.).\n  Player Settings:\n    Proxy Videos Through Invidious: Se conectará a Invidious para obtener videos en lugar de conectarse directamente a YouTube.\n    Default Video Format: Establezca los formatos a usar cuando reproduce un video. Los formatos DASH pueden alcanzar mejores calidades. Los formatos heredados están limitados a un máximo de 720 píxeles de ancho, pero usan menos ancho de banda. Los formatos de audio permiten escuchar solamente el audio.\n    Scroll Playback Rate Over Video Player: Mientras el cursor esté sobre el video, mantenga presionada la tecla Ctrl (tecla Comando en Mac) y use la rueda del ratón hacia adelante o atrás para controlar la velocidad de reproducción. Mantenga presionada la tecla Ctrl (tecla Comando en Mac) y haga clic izquierdo para reestablecer la velocidad de reproducción predeterminada (que es de 1x, a menos que la haya cambiado en configuración).\n  Subscription Settings:\n    Fetch Feeds from RSS: Si se habilita, FreeTube usará RSS en lugar del método predeterminado para recibir videos de sus suscripciones. RSS es más rápido y previene que bloqueen su IP, pero no es capaz de proveer ciertos datos del video, como su duración, o si está en directo\n  Distraction Free Settings:\n    Hide Subscriptions Live: Esta configuración se reemplaza por la configuración «{appWideSetting}» de toda la aplicación, en la sección «{subsection}» de «{settingsSection}»\nDefault Invidious instance has been cleared: La dirección de Invidious predeterminada se ha borrado\nExternal link opening has been disabled in the general settings: La apertura de links externos está deshabilitada en la configuración general\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Este video no está disponible debido a que no se encontraron formatos. Esto puede suceder a causa de indisponibilidad en su región.\nDefault Invidious instance has been set to {instance}: La dirección de Invidious predeterminada se ha establecido en {instance}\nUnknown YouTube url type, cannot be opened in app: Tipo de URL de YouTube desconocida, imposible de abrir en la app\nPlaying Next Video Interval: El próximo video se abrirá inmediatamente. Haga clic aquí para cancelar. | Se abrirá el siguiente video en {nextVideoInterval} segundo. Haga clic aquí para cancelar. | Se abrirá el siguiente video en {nextVideoInterval} segundos. Haga clic aquí para cancelar.\nNew Window: Nueva ventana\nPreferences: Preferencias\nChannels:\n  Channels: Canales\n  Title: Lista de Canales\n  Search bar placeholder: Buscar Canales\n  Unsubscribe Prompt: ¿Estás seguro de que deseas darte de baja de \"{channelName}\"?\n  Count: '{number} canal(es) encontrados.'\n  Empty: Tu lista de canales está actualmente vacía.\nSearch Listing:\n  Label:\n    Subtitles: Subtítulos\n    New: Nuevo\n    Closed Captions: Subtítulos cerrados\n    4K: 4K\n    360 Video: 360°\n    VR180: VR180\n    3D: 3D\n    8K: 8K\nGo to page: Ir a {page}\nSearch character limit: La consulta de búsqueda supera el límite de {searchCharacterLimit} caracteres\nRight-click or hold to see history: Haz clic derecho o mantén presionado para ver el historial\nFeed:\n  Feed Last Updated: 'El feed de {feedName} se actualizó por última vez: {date}'\n  Refresh Feed: Actualizar {subscriptionName}\nClose Banner: Cerrar banner\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Herramientas para desarrolladores\n  Zoom Out: Reducir\n  Zoom In: Ampliar\n  Fullscreen: Pantalla completa\n"
  },
  {
    "path": "static/locales/es.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Español (España)'\n\n# Webkit Menu Bar\nFile: 'Archivo'\nQuit: 'Salir'\nEdit: 'Editar'\nUndo: 'Deshacer'\nRedo: 'Rehacer'\nCut: 'Cortar'\nCopy: 'Copiar'\nPaste: 'Pegar'\nDelete: 'Eliminar'\nSelect all: 'Seleccionar todo'\nToggle Developer Tools: 'Activar herramientas de desarrollo'\nActual size: 'Tamaño actual'\nZoom in: 'Ampliar'\nZoom out: 'Reducir'\nToggle fullscreen: 'Cambiar a pantalla completa'\nWindow: 'Ventana'\nMinimize: 'Minimizar'\nClose: 'Cerrar'\nBack: 'Atrás'\nForward: 'Adelante'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vídeos'\n  Shorts: Vídeos cortos\n  Live: En directo\n  Posts: Publicaciones\n  Sort By: Ordenar por\n\n# Search Bar\n  Counts:\n    Video Count: 1 vídeo | {count} vídeos\n    Channel Count: 1 canal | {count} canales\n    Subscriber Count: 1 suscriptor | {count} suscriptores\n    View Count: 1 vista | {count} vistas\n    Watching Count: 1 espectador | {count} espectadores\n    Comment Count: 1 comentario | {count} comentarios\n    Like Count: 1 me gusta | {count} me gustan\nSearch / Go to URL: 'Buscar / Ir a la URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtros de búsqueda'\n  Sort By:\n    Most Relevant: 'Más relevantes'\n    Rating: 'Mejor valorados'\n    Upload Date: 'Fecha de publicación'\n    View Count: 'Número de visitas'\n  Time:\n    Time: 'Publicado en'\n    Any Time: 'Cualquier momento'\n    Last Hour: 'En la última hora'\n    Today: 'Hoy'\n    This Week: 'Esta semana'\n    This Month: 'Este mes'\n    This Year: 'Este año'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Cualquier tipo'\n    Videos: 'Vídeos'\n    Channels: 'Canales'\n    #& Playlists\n    Movies: Películas\n  Duration:\n    Duration: 'Duración'\n    All Durations: 'Cualquier duración'\n    Short (< 4 minutes): 'Corta (< 4 minutos)'\n    Long (> 20 minutes): 'Larga (> 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Media (4 - 20 minutos)\n  Search Results: 'Resultados de la búsqueda'\n  Fetching results. Please wait: 'Obteniendo resultados. Por favor, espere'\n  Fetch more results: 'Obtener más resultados'\n# Sidebar\n  There are no more results for this search: No hay más resultados para esta búsqueda\n  Features:\n    Subtitles: Subtítulos\n    Creative Commons: Creative Commons\n    3D: 3D\n    4K: 4K\n    Features: Características\n    HD: HD\n    Live: Directo\n    360 Video: Vídeo 360\n    Location: Ubicación\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Limpiar Filtros\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Suscripciones'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tu lista de suscripciones está vacía. Si deseas importar tus suscripciones puedes ir a Configuración de datos y seleccionar Importar suscripciones o puedes buscar un canal y suscribirte.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil tiene muchas suscripciones. Forzar RSS para evitar la limitación de velocidad\n  Load More Videos: Cargar más vídeos\n  Error Channels: Canales con errores\n  Disabled Automatic Fetching: Has desactivado la búsqueda automática de suscripciones. Actualice las suscripciones para verlas aquí.\n  Empty Channels: Tus canales suscritos no tienen actualmente ningún vídeo.\n  Subscriptions Tabs: Pestañas de suscripciones\n  All Subscription Tabs Hidden: Todas las pestañas de las suscripciones están ocultas. Para ver el contenido, por favor, desoculta algunas pestañas en la sección «{subsection}» en «{settingsSection}».\n  Load More Posts: Cargar más publicaciones\n  Empty Posts: Tus canales suscritos no tienen actualmente ninguna publicación.\nTrending:\n  Trending: 'Tendencias'\n  Trending Tabs: Pestañas de tendencias\n  Gaming: Videojuegos\n  Sports: Deportes\nMost Popular: 'Más populares'\nPlaylists: 'Listas de reproducción'\nUser Playlists:\n  Your Playlists: 'Tus listas de reproducción'\n  Search bar placeholder: Buscar listas de reproducción\n  Empty Search Message: No hay vídeos en esta lista de reproducción que coincidan con su búsqueda\n  AddVideoPrompt:\n    Search in Playlists: Buscar en listas de reproducción\n    Save: Guardar\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Video(s) agregado(s) a 1 lista de reproducción | Video(s) agregado(s) a {playlistCount} listas de reproducción\"\n      You haven't selected any playlist yet.: Aún no has seleccionado ninguna lista de reproducción.\n    Select a playlist to add your N videos to: Seleccione una lista de reproducción a la que añadir su vídeo | Seleccione una lista de reproducción a la que añadir sus {videoCount} vídeos\n    N playlists selected: '{playlistCount} seleccionada'\n    Added {count} Times: Ya añadido | Añadido {count} veces\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Vídeos ya añadidos'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Se añadirán vídeos'\n    Allow Adding Duplicate Video(s): Permitir añadir vídeos duplicados\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: No había vídeos que eliminar.\n      Video has been removed: Se ha eliminado el vídeo\n      Playlist has been updated.: Se ha actualizado la lista de reproducción.\n      There was an issue with updating this playlist.: Hubo un problema con la actualización de esta lista de reproducción.\n      This video cannot be moved up.: Este vídeo no se puede subir.\n      This playlist is protected and cannot be removed.: Esta lista de reproducción está protegida y no puede eliminarse.\n      Playlist {playlistName} has been deleted.: La lista de reproducción {playlistName} ha sido eliminada.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Algunos vídeos de la lista de reproducción aún no se han cargado. Haga clic aquí para copiarlos de todos modos.\n      This playlist does not exist: Esta lista de reproducción no existe\n      Playlist name cannot be empty. Please input a name.: El nombre de la lista de reproducción no puede estar vacío. Por favor, introduzca un nombre.\n      There was a problem with removing this video: Hubo un problema al eliminar este vídeo\n      \"{videoCount} video(s) have been removed\": 1 vídeo eliminado | {videoCount} vídeos eliminados\n      This video cannot be moved down.: Este vídeo no se puede bajar.\n      This playlist is now used for quick bookmark: Esta lista de reproducción se utiliza ahora como marcador rápido\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Esta lista de reproducción se utiliza ahora como marcador rápido en lugar de {oldPlaylistName}. Haga clic aquí para deshacer\n      Reverted to use {oldPlaylistName} for quick bookmark: Revertido para usar {oldPlaylistName} para un marcador rápido\n      This playlist is already being used for quick bookmark.: Esta lista de reproducción ya se utiliza como marcador rápido.\n      This playlist has a video with a duration error: Esta lista de reproducción contiene al menos un vídeo sin duración, se ordenará como si su duración fuera cero.\n      Video has been removed. Click here to undo.: El video ha sido eliminado. Clickea aquí para cancelar.\n    Search for Videos: Buscar vídeos\n  Are you sure you want to delete this playlist? This cannot be undone: ¿Estás seguro de que quieres borrar esta lista de reproducción? Esto no se puede deshacer.\n  Sort By:\n    LatestPlayedFirst: Fecha de reproducción (Más reciente)\n    EarliestCreatedFirst: Fecha de Creación (Más antigua)\n    LatestCreatedFirst: Fecha de Creación (Más reciente)\n    EarliestUpdatedFirst: Fecha de Actualización (Más antigua)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Fecha de Reproducción (Más antigua)\n    LatestUpdatedFirst: Fecha de Actualización (Más reciente)\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: No tienes listas de reproducción. Haz clic en el botón Crear nueva lista de reproducción para crear una nueva.\n  Remove from Playlist: Eliminar de la lista de reproducción\n  Save Changes: Guardar los cambios\n  CreatePlaylistPrompt:\n    Create: Crear\n    Toast:\n      There was an issue with creating the playlist.: Hubo un problema con la creación de la lista de reproducción.\n      Playlist {playlistName} has been successfully created.: La lista de reproducción {playlistName} se ha creado correctamente.\n      There is already a playlist with this name. Please pick a different name.: Ya existe una lista de reproducción con este nombre. Por favor, elige un nombre diferente.\n    New Playlist Name: Nuevo nombre de la lista de reproducción\n  This playlist currently has no videos.: Esta lista de reproducción no tiene vídeos.\n  Add to Playlist: Añadir a la lista de reproducción\n  Move Video Down: Bajar el vídeo\n  Playlist Name: Nombre de la lista de reproducción\n  Remove Watched Videos: Eliminar los vídeos vistos\n  Move Video Up: Subir el vídeo\n  Cancel: Cancelar\n  Delete Playlist: Borrar lista de reproducción\n  Create New Playlist: Crear nueva lista de reproducción\n  Edit Playlist Info: Editar información de la lista de reproducción\n  Copy Playlist: Copiar lista de reproducción\n  Playlist Description: Descripción de la lista de reproducción\n  Add to Favorites: Añadir a {playlistName}\n  Remove from Favorites: Eliminar de {playlistName}\n  Enable Quick Bookmark With This Playlist: Activar marcadores rápidos con esta lista de reproducción\n  Playlists with Matching Videos: Listas de reproducción con vídeos relacionados\n  Quick Bookmark Enabled: Marcador rápido habilitado\n  Cannot delete the quick bookmark target playlist.: No se puede eliminar la lista de reproducción de destino de marcadores rápidos.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ¿Estás seguro de que deseas eliminar 1 video visto de esta lista de reproducción? Esto no se puede deshacer. | ¿Estás seguro de que deseas eliminar {playlistItemCount} videos vistos de esta lista de reproducción? Esto no se puede deshacer.\n  Remove Duplicate Videos: Eliminar vídeos duplicados\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ¿Estás seguro de que deseas eliminar 1 video duplicado de esta lista de reproducción? Esto no se puede deshacer. | ¿Estás seguro de que deseas eliminar {playlistItemCount} videos duplicados de esta lista de reproducción? Esto no se puede deshacer.\n  Export Playlist: Exportar esta Playlist\n  The playlist has been successfully exported: La playlist se ha exportado correctamente\n  TotalTimePlaylist: 'Duración total: {duration}'\n  Export list of URLs: Exportar lista de URLs\nHistory:\n  # On History Page\n  History: 'Historial'\n  Watch History: 'Historial de reproducción'\n  Your history list is currently empty.: 'Tu historial está vacío.'\n  Search bar placeholder: Buscar en la historia\n  Empty Search Message: No hay vídeos en tu historial que coincidan con tu búsqueda\n  Case Sensitive Search: Búsqueda sensible a mayúsculas y minúsculas\n  DateOldestHistory: Fecha de Visualización (Más antigua)\n  DateNewestHistory: Fecha de visualización (Más reciente)\nSettings:\n  # On Settings Page\n  Settings: 'Ajustes'\n  General Settings:\n    General Settings: 'General'\n    Fallback to Non-Preferred Backend on Failure: 'Vuelta al backend no preferido en caso de fallo'\n    Enable Search Suggestions: 'Activar sugerencias de búsqueda'\n    Default Landing Page: 'Página de destino predeterminada'\n    Locale Preference: 'Idioma'\n    Preferred API Backend:\n      Preferred API Backend: 'Motor API principal'\n      Local API: 'API local'\n      Invidious API: 'API de Invidious'\n    Video View Type:\n      Video View Type: 'Vista de suscripciones'\n      Grid: 'Cuadrícula'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencia de miniaturas'\n      Default: 'Predeterminado'\n      Beginning: 'Comienzo'\n      Middle: 'Mitad'\n      End: 'Final'\n      Hidden: Oculto\n      Blur: Difuminar\n    Region for Trending: 'Región de las tendencias'\n        #! List countries\n    Check for Latest Blog Posts: Buscar últimas publicaciones del blog\n    Check for Updates: Buscar actualizaciones\n    View all Invidious instance information: Ver toda la información sobre la instancia de Invidious\n    System Default: Predeterminado del sistema\n    Current instance will be randomized on startup: La instancia actual será elegida aleatoriamente al inicio\n    No default instance has been set: No se ha especificado una instancia predeterminada\n    The currently set default instance is {instance}: La instancia predeterminada actual es {instance}\n    Current Invidious Instance: Instancia actual de Invidious\n    Clear Default Instance: Quitar la instancia predeterminada\n    Set Current Instance as Default: Establecer la instancia actual como la instancia predeterminada\n    External Link Handling:\n      No Action: Sin acción\n      Ask Before Opening Link: Preguntar antes de abrir el enlace\n      Open Link: Abrir el enlace\n      External Link Handling: Gestión de enlaces externos\n    Auto Load Next Page:\n      Label: Carga automática de la página siguiente\n      Tooltip: Cargar automáticamente páginas adicionales y comentarios.\n    Open Deep Links In New Window: Abrir URL pasadas a FreeTube en una nueva ventana\n    Minimize to system tray: Minimizar a la bandeja del sistema\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Usar color principal para barra superior'\n    Base Theme:\n      Base Theme: 'Tema base'\n      Black: 'Negro'\n      Dark: 'Oscuro'\n      Light: 'Claro'\n      Dracula: 'Drácula'\n      System Default: Valor por defecto del sistema\n      Catppuccin Mocha: Catppuccin Moca\n      Pastel Pink: Rosa pastel\n      Hot Pink: Rosa fuerte\n      Nordic: Nórdico\n      Solarized Light: Solarized claro\n      Solarized Dark: Solarized oscuro\n      Gruvbox Dark: Gruvbox oscuro\n      Gruvbox Light: Gruvbox claro\n      Catppuccin Frappe: Frappe Capuchino\n      Everforest Dark Hard: Everforest Oscuro Intenso\n      Everforest Dark Medium: Everforest Oscuro Medio\n      Everforest Dark Low: Everforest Oscuro Suave\n      Everforest Light Hard: Everforest Claro Intenso\n      Everforest Light Medium: Everforest Claro Medio\n      Everforest Light Low: Everforest Claro Suave\n      Catppuccin Latte: Capuchino con leche\n    Main Color Theme:\n      Main Color Theme: 'Color principal'\n      Red: 'Rojo'\n      Pink: 'Rosado'\n      Purple: 'Púrpura'\n      Deep Purple: 'Morado'\n      Indigo: 'Índigo'\n      Blue: 'Azul'\n      Light Blue: 'Azul claro'\n      Cyan: 'Cian'\n      Teal: 'Verde azulado'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Verde lima'\n      Yellow: 'Amarillo'\n      Amber: 'Ámbar'\n      Orange: 'Naranja'\n      Deep Orange: 'Naranja oscuro'\n      Dracula Cyan: 'Drácula cian'\n      Dracula Green: 'Drácula verde'\n      Dracula Orange: 'Drácula naranja'\n      Dracula Pink: 'Drácula rosado'\n      Dracula Purple: 'Drácula púrpura'\n      Dracula Red: 'Drácula rojo'\n      Dracula Yellow: 'Drácula amarillo'\n      Catppuccin Mocha Pink: Catppuccin Moca Rosa\n      Catppuccin Mocha Mauve: Catppuccin Mocha Malva\n      Catppuccin Mocha Peach: Catppuccin Moka Melocotón\n      Catppuccin Mocha Green: Catpuccin Moca Verde\n      Catppuccin Mocha Yellow: Catpuccin Moca Amarillo\n      Catppuccin Mocha Red: Catppuccin Moka Rojo\n      Catppuccin Mocha Flamingo: Catppuccin Moka Flamenco\n      Catppuccin Mocha Maroon: Catppuccin Moka Granate\n      Catppuccin Mocha Teal: Catppuccin Moka Turquesa\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Agua de Rosas\n      Catppuccin Mocha Sky: Catppuccin Moka Cielo\n      Catppuccin Mocha Sapphire: Catppuccin Moka Zafiro\n      Catppuccin Mocha Blue: Catpuccin Moka Azul\n      Catppuccin Mocha Lavender: Catppuccin Moka Lavanda\n      Solarized Yellow: Amarillo Solarized\n      Solarized Orange: Naranja Solarized\n      Solarized Red: Rojo Solarized\n      Solarized Magenta: Magenta Solarized\n      Solarized Violet: Violeta Solarized\n      Solarized Blue: Azul Solarized\n      Solarized Cyan: Cian Solarized\n      Solarized Green: Verde Solarized\n      Gruvbox Dark Green: Gruvbox verde oscuro\n      Gruvbox Dark Yellow: Gruvbox amarillo oscuro\n      Gruvbox Dark Blue: Gruvbox azul oscuro\n      Gruvbox Dark Purple: Gruvbox púrpura\n      Gruvbox Dark Aqua: Gruvbox aguamarina oscuro\n      Gruvbox Light Purple: Gruvbox violeta claro\n      Gruvbox Dark Orange: Gruvbox naranja oscuro\n      Gruvbox Light Red: Gruvbox rojo claro\n      Gruvbox Light Blue: Gruvbox azul claro\n      Gruvbox Light Orange: Gruvbox naranja claro\n      Catppuccin Frappe Green: Catppuccin Frappe Verde\n      Catppuccin Frappe Teal: Catppuccin Frappe Turquesa\n      Catppuccin Frappe Sky: Catppuccin Frappe Cielo\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Zafiro\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavanda\n      Everforest Dark Orange: Everforest Oscuro Naranja\n      Everforest Dark Yellow: Everforest Oscuro Amarillo\n      Everforest Dark Green: Everforest Oscuro Verde\n      Everforest Dark Red: Everforest Oscuro Rojo\n      Everforest Dark Blue: Everforest Oscuro Azul\n      Everforest Dark Aqua: Everforest Oscuro Aguamarina\n      Everforest Dark Purple: Everforest Oscuro Morado\n      Everforest Light Red: Everforest Claro Rojo\n      Everforest Light Orange: Everforest Claro Naranja\n      Everforest Light Yellow: Everforest Claro Amarillo\n      Everforest Light Green: Everforest Claro Verde\n      Everforest Light Aqua: Everforest Claro Aguamarina\n      Everforest Light Blue: Everforest Claro Azul\n      Everforest Light Purple: Everforest Claro Morado\n      Catppuccin Frappe Blue: Catppuccin Frappe Azul\n      Catppuccin Frappe Red: Catppuccin Frappe Rojo\n      Catppuccin Frappe Maroon: Catppuccin Frappe Granate\n      Catppuccin Frappe Peach: Catppuccin Frappe Durazno\n      Catppuccin Frappe Yellow: Catppuccin Frappe Amarillo\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Rosa\n      Catppuccin Frappe Mauve: Catppuccin Frappe Malva\n      Catppuccin Latte Mauve: Capuchino con leche malva\n      Catppuccin Latte Red: Capuchino con leche rojo\n    Secondary Color Theme: 'Color secundario'\n        #* Main Color Theme\n    UI Scale: Escala de IU\n    Expand Side Bar by Default: Expandir barra lateral por defecto\n    Disable Smooth Scrolling: Desactivar desplazamiento suave\n    Hide Side Bar Labels: Ocultar las etiquetas de la barra lateral\n    Hide FreeTube Header Logo: Ocultar el logotipo de Freetube de la parte superior\n  Player Settings:\n    Player Settings: 'Reproductor'\n    Play Next Video: 'Reproducción automática de videos recomendados'\n    Turn on Subtitles by Default: 'Habilitar subtítulos por defecto'\n    Autoplay Videos: 'Iniciar videos automáticamente'\n    Proxy Videos Through Invidious: 'Enmascarar vídeos a través de Invidious'\n    Autoplay Playlists: 'Reproducción automática de videos en la lista de reproducción'\n    Enable Theatre Mode by Default: 'Activar el modo cine por defecto'\n    Default Volume: 'Volumen predeterminado'\n    Default Playback Rate: 'Velocidad de reproducción predeterminada'\n    Default Video Format:\n      Default Video Format: 'Formato de vídeo predeterminado'\n      Dash Formats: 'Formatos DASH'\n      Legacy Formats: 'Formatos heredados'\n      Audio Formats: 'Formatos de audio'\n    Default Quality:\n      Default Quality: 'Calidad predeterminada'\n      Auto: 'Automático'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Temporizador de cuenta atrás de reproducción automática\n    Display Play Button In Video Player: Mostrar el botón de reproducción sobre el vídeo\n    Scroll Volume Over Video Player: Cambiar el volumen con la rueda del ratón sobre el vídeo\n    Fast-Forward / Rewind Interval: Intervalo de avance/rebobinado rápido\n    Scroll Playback Rate Over Video Player: Cambiar la velocidad de reproducción con el ratón\n    Max Video Playback Rate: Velocidad máxima de reproducción de vídeo\n    Video Playback Rate Interval: Intervalo de velocidad de reproducción de vídeo\n    Screenshot:\n      Folder Button: Seleccione una carpeta\n      Error:\n        Forbidden Characters: Caracteres prohibidos\n        Empty File Name: Nombre de archivo vacío\n      Enable: Habilitar capturas de pantalla\n      Quality Label: Calidad de las capturas de pantalla\n      Format Label: Formato de las capturas de pantalla\n      File Name Label: Patrón de nombre de archivo\n      Folder Label: Carpeta de capturas de pantalla\n      Ask Path: Pedir la Carpeta para Guardar\n      File Name Tooltip: Puede utilizar las siguientes variables. %Y Año 4 dígitos. %M Mes 2 dígitos. %D Día 2 dígitos. %H Hora 2 dígitos. %N Minuto 2 dígitos. %S Segundo 2 dígitos. %T Milisegundo 3 dígitos. %s Video Segundo. %t Video Milisegundo 3 dígitos. %i Video ID.\n    Enter Fullscreen on Display Rotate: Entrar en pantalla completa al girar la pantalla\n    Skip by Scrolling Over Video Player: Omitir al desplazarse sobre el reproductor de vídeo\n    Autoplay Interruption Timer: Temporizador de interrupción de reproducción automática\n    Default Viewing Mode:\n      Theater: Teatro\n      Default Viewing Mode: Vista predeterminada\n      External Player: Reproductor externo ({externalPlayerName})\n      Full Screen: Pantalla Completa\n      Picture in Picture: Imagen en imagen\n  Privacy Settings:\n    Privacy Settings: 'Privacidad'\n    Remember History: 'Guardar Historial'\n    Save Watched Progress: 'Guardar progreso reproducido'\n    Clear Search Cache: 'Borrar cache de búsqueda'\n    Are you sure you want to clear out your search cache?: '¿Seguro que quieres borrar el cache de búsqueda?'\n    Search cache has been cleared: 'Caché de búsqueda borrado'\n    Remove Watch History: 'Vaciar historial de reproducciones'\n    Are you sure you want to remove your entire watch history?: '¿Confirma que quiere vaciar el historial de reproducciones?'\n    Watch history has been cleared: 'Se vació el historial de reproducciones'\n    Remove All Subscriptions / Profiles: 'Borrar todas las suscripciones/perfiles'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: '¿Confirma que quieres borrar todas las suscripciones y perfiles? Esta operación es irreversible.'\n    Save Watched Videos With Last Viewed Playlist: Guardar vídeos vistos con la última lista de reproducción vista\n    All playlists have been removed: Se han eliminado todas las listas de reproducción\n    Remove All Playlists: Eliminar todas las listas de reproducción\n    Are you sure you want to remove all your playlists?: ¿Estás seguro de que quieres eliminar todas tus listas de reproducción?\n    Remember Search History: Guardar Historial de Búsquedas\n    Are you sure you want to clear out your search history and cache?: ¿Está seguro de que desea borrar su historial de búsqueda y la caché?\n    Search history and cache have been cleared: El historial de búsquedas y el cache han sido borrados\n    Clear Search History and Cache: Borrar Historial de Búsquedas y Cache\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Nunca\n        Auto: Automático\n        Semi-auto: Semi-automático\n      Tooltip: Automático = Guarda al salir de cada página de video, cuando el video termina y cuando ocurre un error (por ejemplo, límite de velocidad o sesión de reproducción expirada). Semiautomático = Igual que Automático, excepto que no guarda al salir de la página de video. Se puede guardar el progreso manualmente usando el botón \"Guardar progreso de visualización\", ubicado debajo del reproductor de video.\n  Subscription Settings:\n    Subscription Settings: 'Suscripción'\n    Fetch Feeds from RSS: 'Recuperar suministros desde RSS'\n    Fetch Automatically: Obtener los feed automáticamente\n    Confirm Before Unsubscribing: Evitar bajas accidentales\n    'Limit the number of videos displayed for each channel': Limitar el número de vídeos mostrados para cada canal\n    To: A\n  Data Settings:\n    Data Settings: 'Datos'\n    Select Export Type: 'Seleccionar tipo de exportación'\n    Import Subscriptions: 'Importar suscripciones'\n    Export Subscriptions: 'Exportar suscripciones'\n    Export FreeTube: 'Exportar FreeTube'\n    Export YouTube: 'Exportar YouTube'\n    Export NewPipe: 'Exportar NewPipe'\n    Import History: 'Importar historial'\n    Export History: 'Exportar historial'\n    Profile object has insufficient data, skipping item: 'Este perfil no tiene datos suficientes, omitiendo objeto'\n    All subscriptions and profiles have been successfully imported: 'Todas las suscripciones y perfiles han sido importados con éxito'\n    All subscriptions have been successfully imported: 'Todas las suscripciones han sido importadas con éxito'\n    Invalid subscriptions file: 'Archivo de suscripciones no válido'\n    Invalid history file: 'Archivo de historial no válido'\n    Subscriptions have been successfully exported: 'Las suscripciones han sido exportadas con éxito'\n    History object has insufficient data, skipping item: 'El historial no tiene datos suficientes, omitiendo objeto'\n    All watched history has been successfully imported: 'El historial de visionados ha sido importado con éxito'\n    All watched history has been successfully exported: 'El historial de visionados ha sido exportado con éxito'\n    Unable to read file: 'Imposible leer el archivo'\n    Unable to write file: 'Imposible escribir el archivo'\n    Unknown data key: 'Clave de datos desconocida'\n    How do I import my subscriptions?: '¿Cómo puedo importar mis suscripciones?'\n    Manage Subscriptions: Administrar suscripciones\n    Import Playlists: Importar listas de reproducción\n    Export Playlists: Exportar listas de reproducción\n    Playlist insufficient data: Datos insuficientes para la lista de reproducción «{playlist}», omitiendo el elemento\n    All playlists has been successfully imported: Todas las listas de reproducción se han importado con éxito\n    All playlists has been successfully exported: Todas las listas de reproducción se han exportado con éxito\n    Subscription File: Archivo de suscripción\n    Playlist File: Archivo de la lista de reproducción\n    History File: Archivo del historial\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Esta opción exporta vídeos de todas las listas de reproducción a una lista de reproducción llamada \\\"Favoritos\\\".\\nCómo exportar e importar vídeos en las listas de reproducción para una versión antigua de FreeTube:\\n1. Exporta tus listas de reproducción con esta opción activada.\\n2. Elimine todas sus listas de reproducción existentes utilizando la opción Eliminar todas las listas de reproducción en Configuración de privacidad.\\n3. Inicia la versión anterior de FreeTube e importa las listas de reproducción exportadas.\\\"\"\n      Label: Exportar listas de reproducción de versiones anteriores de FreeTube\n\n    Search history file: Archivo de historial de búsqueda\n    Search history: historial de búsqueda\n    Import search history: Importar historial de búsqueda\n    Export search history: Exportar historial de búsqueda\n    All search history has been successfully imported: Todo el historial de búsqueda se ha importado correctamente\n    All search history has been successfully exported: Todo el historial de búsqueda se ha exportado correctamente\n  Distraction Free Settings:\n    Hide Video Likes And Dislikes: Ocultar «likes» y «dislikes» de vídeos\n    Hide Video Views: Ocultar las vistas del vídeo\n    Hide Live Chat: Ocultar chat en vivo\n    Hide Popular Videos: Ocultar vídeos populares\n    Hide Trending Videos: Ocultar vídeos en tendencia\n    Hide Recommended Videos: Ocultar vídeos recomendados\n    Hide Comment Likes: Ocultar «likes» de comentarios\n    Hide Channel Subscribers: Ocultar suscriptores\n    Distraction Free Settings: Sin distracciones\n    Hide Active Subscriptions: Ocultar suscripciones activas\n    Hide Playlists: Ocultar listas de reproducción\n    Hide Video Description: Ocultar la descripción del vídeo\n    Hide Comments: Ocultar comentarios\n    Hide Live Streams: Ocultar transmisiones en directo\n    Hide Sharing Actions: Ocultar acciones de uso compartido\n    Hide Videos on Watch: 'Ocultar vídeos vistos'\n    Hide Chapters: Ocultar capítulos\n    Hide Upcoming Premieres: Ocultar los próximos estrenos\n    Hide Channels: Ocultar vídeos de los canales\n    Hide Channels Placeholder: ID del canal\n    Display Titles Without Excessive Capitalisation: Mostrar títulos sin mayúsculas ni signos de puntuación excesivos\n    Hide Featured Channels: Ocultar canales recomendados\n    Hide Channel Playlists: Ocultar la pestaña \"Listas de reproducción\" del canal\n    Hide Channel Shorts: Ocultar la pestaña \"Vídeos cortos\" del canal\n    Sections:\n      Side Bar: Barra lateral\n      Channel Page: Página del canal\n      Watch Page: Ver la página\n      General: General\n      Subscriptions Page: Página de suscripciones\n    Hide Channel Releases: Ocultar la pestaña \"Lanzamientos\" del canal\n    Hide Channel Podcasts: Ocultar la pestaña \"Podcasts\" del canal\n    Hide Subscriptions Shorts: Ocultar las suscripciones para shorts\n    Hide Subscriptions Videos: Ocultar las suscripciones de los Vídeos\n    Hide Subscriptions Live: Ocultar las suscripciones de los directos\n    Hide Profile Pictures in Comments: Ocultar fotos de perfil en comentarios\n    Hide Channels Invalid: El ID del canal proporcionado no es válido\n    Hide Channels Disabled Message: Algunos canales se bloquearon por ID y no se procesaron. La función está bloqueada mientras se actualizan esos ID\n    Hide Channels Already Exists: El ID del canal ya existe\n    Hide Channels API Error: Error al recuperar el usuario con el ID proporcionado. Por favor, compruebe de nuevo si el ID es correcto.\n    Hide Videos, Playlists and Channels Containing Text: Ocultar vídeos y listas de reproducción que contengan texto\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Palabra, fragmento o frase\n    Hide Channel Home: Ocultar la pestaña \"Inicio\" del canal\n    Show Added Items: Mostrar elementos añadidos\n    Hide Channel Courses: Ocultar la pestaña \"Cursos\" del canal\n    Hide Channel Posts: Ocultar pestaña \"Publicaciones\" del canal\n    Hide Subscriptions Posts: Ocultar publicaciones de las suscripciones\n  The app needs to restart for changes to take effect. Restart and apply change?: ¿Quieres reiniciar FreeTube ahora para aplicar los cambios?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Error al obtener información sobre la red. ¿Has configurado el proxy correctamente?\n    City: Ciudad\n    Region: Región\n    Country: País\n    Ip: IP\n    Your Info: Tu información\n    Test Proxy: Probar proxy\n    Clicking on Test Proxy will send a request to: Al hacer clic en «Probar proxy» se enviará una solicitud a\n    Proxy Port Number: Número de puerto del proxy\n    Proxy Host: Host del proxy\n    Proxy Protocol: Protocolo del proxy\n    Enable Tor / Proxy: Activar Tor o «proxy»\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube no tiene un proxy incorporado, pero puede conectarse a un proxy externo, como uno que se ejecuta en su máquina como Tor o un proxy externo como un proxy SOCKS5 proporcionado por algunas VPN. Si está habilitado, asegúrese de que su proxy/Tor esté configurado correctamente, o FreeTube no podrá recuperar ningún dato.\n    Proxy Password: Contraseña del proxy\n    Proxy Username: Nombre de Usuario del proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar cuando se salta un segmento de patrocinio\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL de la API de SponsorBlock (por defecto es https://sponsor.ajay.app)\n    Enable SponsorBlock: Activar SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Category Color: Color de categoría\n    Skip Options:\n      Show In Seek Bar: Mostrar en la barra de búsqueda\n      Do Nothing: No hacer nada\n      Skip Option: Omitir opción\n      Auto Skip: Salto automático\n      Prompt To Skip: Solicitar que se omita\n    UseDeArrowTitles: Utilizar los títulos para el vídeo de DeArrow\n    UseDeArrowThumbnails: Utiliza DeArrow para las miniaturas\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': La dirección url de la API del generador de miniaturas de DeArrow (por defecto es https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Argumentos adicionales del reproductor\n    Custom External Player Executable: Ruta alternativa del ejecutable del reproductor\n    Ignore Unsupported Action Warnings: Omitir advertencias sobre acciones no soportadas\n    External Player: Reproductor externo\n    External Player Settings: Reproductor externo\n    Players:\n      None:\n        Name: Ninguno\n    Ignore Default Arguments: Ignorar argumentos por defecto\n  Parental Control Settings:\n    Hide Unsubscribe Button: Ocultar botón de anular suscripción\n    Hide Search Bar: Ocultar barra de búsqueda\n    Parental Control Settings: Control parental\n    Show Family Friendly Only: Mostrar solo lo apto para las familias\n    Hide Uploader on Watch page: Ocultar Canal en la página de Reproducción\n  Experimental Settings:\n    Experimental Settings: Experimental\n    Warning: Estas configuraciones son experimentales, pueden causar fallos mientras están habilitadas. Es muy recomendable hacer copias de seguridad. ¡Úselo bajo su propio riesgo!\n    Replace HTTP Cache: Reemplazar la caché HTTP\n  Password Settings:\n    Password Settings: Contraseña\n    Set Password To Prevent Access: Establecer una contraseña para impedir el acceso a los ajustes\n    Set Password: Establecer contraseña\n    Remove Password: Eliminar contraseña\n  Password Dialog:\n    Password: Contraseña\n    Enter Password To Unlock: Introduce la contraseña para desbloquear los ajustes\n  Sort Settings Sections (A-Z): Ordenar secciones de configuración (A-Z)\n  Return to Settings Menu: Volver a los Ajustes\nAbout:\n  #On About page\n  About: 'Acerca de'\n  #& About\n  Donate: Donar\n  these people and projects: estas personas y proyectos\n  Credits: Créditos\n  Translate: Traducir\n  room rules: reglas de la sala\n  Chat on Matrix: Chat en Matrix\n  Mastodon: Mastodon (red social)\n  Email: Correo electrónico\n  Blog: Blog\n  Website: Sitio web\n  Please check for duplicates before posting: Por favor, antes de publicar asegúrate de no duplicar temas\n  GitHub issues: Sugerencias en GitHub\n  Report a problem: Informar de un problema\n  FAQ: Preguntas frecuentes\n  FreeTube Wiki: Wiki de FreeTube\n  Help: Ayuda\n  GitHub releases: Lanzamientos de GitHub\n  Downloads / Changelog: Descargas / Registro de cambios\n  Source code: Código fuente\n  Beta: Beta\n  Discussions: Debates\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licenciado bajo {licenseLink}\n  Please read the {roomRulesLink}: Por favor, lea el {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube es posible gracias a {creditsPageLink}\nProfile:\n  All Channels: 'Todos los canales'\n  Profile Manager: 'Administrador de perfiles'\n  Create New Profile: 'Crear nuevo perfil'\n  Edit Profile: 'Editar perfil'\n  Color Picker: 'Selector de color'\n  Custom Color: 'Color personalizado'\n  Profile Preview: 'Vista previa del perfil'\n  Create Profile: 'Crear perfil'\n  Update Profile: 'Actualizar perfil'\n  Make Default Profile: 'Hacer a este perfil el predeterminado'\n  Delete Profile: 'Borrar perfil'\n  Are you sure you want to delete this profile?: '¿Seguro de que quieres borrar este perfil?'\n  All subscriptions will also be deleted.: 'Las suscripciones también serán borradas.'\n  Your profile name cannot be empty: 'Tu nombre de perfil no puede estar vacío'\n  Profile has been created: 'Se ha creado el perfil'\n  Profile has been updated: 'El perfil se ha actualizado'\n  Your default profile has been set to {profile}: 'Tu perfil predeterminado se ha establecido como {profile}'\n  Removed {profile} from your profiles: 'Eliminado {profile} de tus perfiles'\n  Your default profile has been changed to your primary profile: 'Tu perfil predeterminado ha sido cambiado a tu perfil principal'\n  '{profile} is now the active profile': '{profile} es ahora el perfil activo'\n#On Channel Page\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ¿Está seguro de que desea eliminar los canales seleccionados? Esto no eliminará el canal de ningún otro perfil.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Este es tu perfil principal. ¿Está seguro de que desea eliminar los canales seleccionados? Los mismos canales se eliminarán en cualquier perfil en el que se encuentren.\n  No channel(s) have been selected: No se ha seleccionado ningún canal\n  Add Selected To Profile: Añadir seleccionados al perfil\n  Delete Selected: Eliminar seleccionados\n  Select None: No seleccionar nada\n  Select All: Seleccionar todo\n  '{number} selected': '{number} seleccionados'\n  Other Channels: Otros canales\n  Subscription List: Lista de suscripciones\n  Profile Select: Seleccionar perfil\n  Profile Filter: Filtro de perfil\n  Profile Settings: Perfil\n  Toggle Profile List: Alternar la lista de los perfiles\n  Open Profile Dropdown: Abrir el desplegable del Perfil\n  Close Profile Dropdown: Cerrar el desplegable del Perfil\n  Profile Name: Nombre del perfil\n  Edit Profile Name: Editar el nombre del perfil\n  Create Profile Name: Crear un nombre para el perfil\nChannel:\n  Subscribe: 'Suscribirse'\n  Unsubscribe: 'Anular suscripción'\n  Search Channel: 'Buscar en canal'\n  Your search results have returned 0 results: 'Su búsqueda no encontró resultados'\n  Videos:\n    Videos: 'Vídeos'\n    This channel does not currently have any videos: 'Este canal no tiene actualmente ningún vídeo'\n    Sort Types:\n      Newest: 'Más recientes'\n      Oldest: 'Más antiguos'\n      Most Popular: 'Más populares'\n  Playlists:\n    Playlists: 'Listas de reproducción'\n    This channel does not currently have any playlists: 'Este canal no tiene actualmente ninguna lista de reproducción'\n    Sort Types:\n      Last Video Added: 'Último vídeo añadido'\n      Newest: 'El más reciente'\n      Oldest: 'El más antiguo'\n  About:\n    About: 'Acerca de'\n    Channel Description: 'Descripción del canal'\n    Featured Channels: 'Canales destacados'\n    Tags:\n      Tags: Etiquetas\n      Search for: Buscar por «{tag}»\n    Details: Detalles\n    Joined: Ingresó en\n    Location: Ubicación\n  Added channel to your subscriptions: Canal añadido a tus suscripciones\n  Removed subscription from {count} other channel(s): Suscripción eliminada de {count} otros canales\n  Channel has been removed from your subscriptions: El canal ha sido eliminado de tus suscripciones\n  This channel does not exist: Este canal no existe\n  This channel does not allow searching: Este canal no permite realizar búsquedas\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Este canal tiene restricciones de edad y actualmente no puede verse en FreeTube.\n  Channel Tabs: Ficha del Canal\n  Posts:\n    This channel currently does not have any posts: Este canal no tiene actualmente ningún mensaje\n    Reveal Answers: Revelar las respuestas\n    Hide Answers: Ocultar las respuestas\n    votes: '{votes} votos'\n    Video hidden by FreeTube: Vídeo oculto por FreeTube\n    View Full Post: Ver toda la publicación\n    Viewing Posts Only Supported By Invidious: La visualización de mensajes solo es posible con Invidious. Ve a la pestaña de comunidad de un canal para ver el contenido sin Invidious.\n  Live:\n    Live: En directo\n    This channel does not currently have any live streams: Este canal no tiene actualmente ninguna retransmisión en directo\n  Shorts:\n    This channel does not currently have any shorts: Este canal no tiene actualmente ningún vídeo corto\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Este canal actualmente no tiene podcasts\n  Releases:\n    Releases: Publicaciones\n    This channel does not currently have any releases: Este canal no tiene actualmente ninguna publicación\n  Home:\n    Home: Inicio\n    View Playlist: Ver lista de reproducción\n  Courses:\n    Courses: Cursos\n    This channel does not currently have any courses: Este canal no tiene cursos en este momento\nVideo:\n  Mark As Watched: 'Marcar como visto'\n  Remove From History: 'Borrar del historial'\n  Video has been marked as watched: 'El vídeo ha sido marcado como visto'\n  Video has been removed from your history: 'El vídeo ha sido eliminado de tu historial'\n  Open in YouTube: 'Abrir en YouTube'\n  Copy YouTube Link: 'Copiar el enlace de YouTube'\n  Open YouTube Embedded Player: 'Abrir en el reproductor integrado de YouTube'\n  Copy YouTube Embedded Player Link: 'Copiar el enlace del reproductor integrado de YouTube'\n  Open in Invidious: 'Abrir en Invidious'\n  Copy Invidious Link: 'Copiar el enlace de Invidious'\n  Views: 'Vistas'\n  Watched: 'Visto'\n  Autoplay: 'Reproducción automática'\n  # As in a Live Video\n  Live: 'En directo'\n  Live Now: 'En directo ahora'\n  Live Chat: 'Chat en directo'\n  Enable Live Chat: 'Activar chat en directo'\n  Live Chat is currently not supported in this build.: 'El chat en directo no está soportado de momento en esta versión.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'El chat en directo está activado. Los mensajes aparecerán aquí en cuanto se envíen.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Actualmente el chat no funciona con la API de Invidious. Se requiere una conexión directa con YouTube.'\n  Published:\n    In less than a minute: En menos de un minuto\n  Published on: 'Publicado el'\n#& Videos\n  Previous: Anterior\n  Next: Siguiente\n  Reverse Playlist: Invertir orden\n  Shuffle Playlist: Reproducción aleatoria\n  Loop Playlist: Reproducción en bucle\n  Starting soon, please refresh the page to check again: Comenzará en breve. Por favor, recarga la página para comprobarlo\n  Copy Invidious Channel Link: Copiar enlace Invidious del canal\n  Open Channel in Invidious: Abrir el canal en Invidious\n  Copy YouTube Channel Link: Copiar enlace Youtube del canal\n  Open Channel in YouTube: Abrir canal en YouTube\n  Started streaming on: Comenzó a transmitir en\n  Streamed on: Transmitido en\n  Video has been removed from your saved list: El vídeo ha sido eliminado de tu lista de guardados\n  Video has been saved: El vídeo ha sido guardado\n  Save Video: Guardar el vídeo\n  Sponsor Block category:\n    music offtopic: No relacionado con la música\n    interaction: Interacción\n    self-promotion: Auto promoción\n    outro: Epílogo\n    intro: Introducción\n    sponsor: Patrocinador\n    recap: Recapitulación\n    filler: Relleno\n  External Player:\n    playlist: lista de reproducción\n    video: vídeo\n    OpenInTemplate: Abrir en {externalPlayer}\n    Unsupported Actions:\n      looping playlists: reproducir en bucle las listas de reproducción\n      shuffling playlists: aleatorizar las listas de reproducción\n      reversing playlists: invertir las listas de reproducción\n      opening specific video in a playlist (falling back to opening the video): abrir un vídeo específico en una lista de reproducción (regresando a abrir el vídeo)\n      opening playlists: abrir listas de reproducción\n      setting a playback rate: establecer una velocidad de reproducción\n      starting video at offset: iniciar el vídeo en un punto dado\n    UnsupportedActionTemplate: '{externalPlayer} no soporta: {action}'\n    OpeningTemplate: Abriendo {videoOrPlaylist} en {externalPlayer}...\n  Premieres: Estrenos\n  Show Super Chat Comment: Mostrar los comentarios del Super Chat\n  Scroll to Bottom: Desplazarse hacia abajo\n  Upcoming: Próximamente\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': El chat en vivo no está disponible para esta transmisión. Tal vez estaba deshabilitado antes de la retransmisión.\n  Unhide Channel: Mostrar el canal\n  Hide Channel: Ocultar el canal\n  More Options: Más opciones\n  Player:\n    TranslatedCaptionTemplate: '{language} (traducido de \"{originalLanguage}\")'\n    Exit Full Window: Salir de la pantalla completa\n    Take Screenshot: Hacer una captura de pantalla\n    Show Stats: Mostrar estadísticas\n    Hide Stats: Ocultar estadísticas\n    Stats:\n      Stats: Estadísticas\n      Video ID: 'ID del vídeo: {videoId}'\n      Media Formats: 'Formatos del medio: {formats}'\n      Resolution: 'Resolución: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensiones del reproductor: {width}x{height}'\n      Bitrate: 'Tasa de bits: {bitrate} kbps'\n      Volume: 'Volumen: {volumePercentage}%'\n      Bandwidth: 'Ancho de banda: {bandwidth} kbps'\n      Buffered: 'Almacenado en búfer: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Fotogramas eliminados: {droppedFrames} / Fotogramas totales: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Códecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Códecs: {videoCodec} / {audioCodec}'\n    You appear to be offline: Parece que no tienes conexión.\n    Playback will resume automatically when your connection comes back: La reproducción se reanudará automáticamente cuando se restablezca la conexión.\n    Skipped segment: Segmento {segmentCategory} omitido\n    Audio Tracks: Pistas de audio\n    Theatre Mode: Modo cine\n    Exit Theatre Mode: Salir del modo cine\n    Full Window: Pantalla completa\n    Autoplay is off: La reproducción automática está desactivada\n    Autoplay is on: La reproducción automática está activada\n  IP block: YouTube ha bloqueado tu dirección IP para ver vídeos. Por favor, intenta cambiar a otra VPN o proxy.\n  MembersOnly: Los videos solo para miembros no se pueden ver con FreeTube ya que requieren un inicio de sesión en Google y una membresía pagada al canal del cargador.\n  Unlisted: No listado\n  AgeRestricted: Los vídeos con restricciones de edad no se pueden ver con FreeTube ya que requieren iniciar sesión en Google y usar una cuenta de YouTube verificada por edad.\n  DeArrow:\n    Show Original Details: Mostrar detalles originales\n    Show Modified Details: Mostrar detalles modificados\n#& Playlists\n  DRMProtected: Los videos restringidos con DRM no pueden reproducirse en FreeTube, dado que requieren componentes propietarias de fuente cerrada. Si desea ver este video, por favor véalo en la página oficial de YouTube con un buscador que tenga DRM habilitado.\n  Watched Progress Saved: Progreso de visualización guardado\n  Save Watched Progress: Guardar progreso de visualización\n  Popout Live Chat: Chat popout\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Tiempo restante previo al anuncio: {remindingTimeSeconds} s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Tiempo restante de retroceso de SABR: {remindingTimeSeconds} s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Ver la lista de reproducción completa'\n  Last Updated On: 'Se actualizó por última vez el'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lista de reproducción\n  Sort By:\n    Custom: Personalizado\n    DateAddedNewest: Fecha de adición (Más reciente)\n    DateAddedOldest: Fecha de adición (Más antigua)\n    AuthorAscending: Autor (A-Z)\n    AuthorDescending: Autor (Z-A)\n    VideoTitleAscending: Título (A-Z)\n    VideoTitleDescending: Título (Z-A)\n    VideoDurationAscending: Duración (Más corta)\n    VideoDurationDescending: Duración (más larga)\n    PublishedNewest: Fecha de publicación (Más reciente)\n    PublishedOldest: Fecha de publicación (Más antigua)\nChange Format:\n  Change Media Formats: 'Cambiar formato de vídeo'\n  Use Dash Formats: 'Utilizar formatos DASH'\n  Use Legacy Formats: 'Usar formatos «Legacy»'\n  Use Audio Formats: 'Utilizar formatos de audio'\n  Audio formats are not available for this video: El formato solo audio no está disponible para este vídeo\n  Dash formats are not available for this video: Los formatos DASH no están disponibles para este vídeo\n  Legacy formats are not available for this video: Los formatos antiguos no están disponibles para este vídeo\nShare:\n  Share Video: 'Compartir vídeo'\n  Share Playlist: 'Compartir lista de reproducción'\n  Copy Link: 'Copiar enlace'\n  Open Link: 'Abrir enlace'\n  Copy Embed: 'Copiar código de incrustación'\n  Open Embed: 'Abrir código de incrustación'\n  # On Click\n  Invidious URL copied to clipboard: 'Se copió el URL de Invidious en el portapapeles'\n  Invidious Embed URL copied to clipboard: 'Se copió el URL de incrustación de Invidious en el portapapeles'\n  YouTube URL copied to clipboard: 'Se copió el URL de YouTube en el portapapeles'\n  YouTube Embed URL copied to clipboard: 'Se copió el URL de incrustación de YouTube en el portapapeles'\n  Include Timestamp: Incluir cronomarcador\n  YouTube Channel URL copied to clipboard: Se copió el URL del canal de YouTube en el portapapeles\n  Invidious Channel URL copied to clipboard: Se copió el URL al canal de Invidious en el portapapeles\n  Share Channel: Compartir el canal\n  Share Post: Compartir Publicación\nMini Player: 'Minirreproductor'\nComments:\n  Comments: 'Comentarios'\n  Click to View Comments: 'Pulse para ver comentarios'\n  Getting comment replies, please wait: 'Obteniendo las respuestas. Espere'\n  Hide Comments: 'Ocultar comentarios'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Aún no hay comentarios'\n  Load More Comments: 'Cargar más comentarios'\n  There are no more comments for this video: No hay más comentarios en este vídeo\n  Newest first: Los más recientes primero\n  Top comments: Mejores comentarios\n  Show More Replies: Mostrar más respuestas\n  Pinned by: Fijado por\n  Member: Miembro\n  Hearted: Corazón\n  View {replyCount} replies: Ver 1 respuesta | Ver {replyCount} respuestas\n  Subscribed: Suscrito\n  There are no comments available for this post: No hay comentarios disponibles para este tema\n  View 1 reply from {channelName}: Ver 1 respuesta de {channelName}\n  View {replyCount} replies from {channelName} and others: Ver {replyCount} respuesta de {channelName} y otros\n  Hide {replyCount} replies: Ocultar 1 respuesta | Ocultar {replyCount} respuestas\nUp Next: 'A continuación'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Error de la API local (Clic para copiar el código)'\nInvidious API Error (Click to copy): 'Error de la API de Invidious (Clic para copiar el código)'\nFalling back to Invidious API: 'Recurriendo a la API de Invidious'\nFalling back to Local API: 'Recurriendo a la API local'\nLoop is now disabled: 'Reproducción en bucle desactivada'\nLoop is now enabled: 'Reproducción en bucle activada'\nShuffle is now disabled: 'Reproducción aleatoria desactivada'\nShuffle is now enabled: 'Reproducción aleatoria activada'\nPlaying Next Video: 'Reproduciendo el vídeo siguiente'\nPlaying Previous Video: 'Reproduciendo el vídeo anterior'\nCanceled next video autoplay: 'La reproducción del vídeo siguiente se ha cancelado'\n'The playlist has ended. Enable loop to continue playing': 'Esta lista de reproducción ha finalizado. Activa la reproducción en bucle para continuar con ella'\n\nYes: 'Sí'\nNo: 'No'\nA new blog is now available, {blogTitle}. Click to view more: 'Nueva publicación del blog disponible, {blogTitle}. Haga clic para saber más'\nDownload From Site: Descargar desde el sitio web\nVersion {versionNumber} is now available!  Click for more details: ¡La versión {versionNumber} está disponible! Haz clic para saber más\nThe playlist has been reversed: Orden de lista de reproducción invertido\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Este vídeo no está disponible por no tener un formato válido. Esto puede suceder por la falta de acceso de este formato a tu región.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Cuando se activa, FreeTube utilizará RSS en lugar de su método por defecto para obtener su feed de suscripción. RSS es más rápido y evita el bloqueo de IP, pero no proporciona cierta información como la duración del vídeo, el estado en directo o los mensajes\n    Fetch Automatically: Cuando esté habilitado, FreeTube obtendrá automáticamente su feed de suscripciones al iniciar y cuando se abra una nueva ventana.\n  Player Settings:\n    Default Video Format: Selecciona el formato usado para reproducir vídeos. El formato DASH puede reproducir resoluciones más altas. El formato Legacy está limitado a 360p, pero requiere menos ancho de banda. El formato del audio se limita al reproducir solo audio.\n    Proxy Videos Through Invidious: Se conectará a Invidious para obtener vídeos en lugar de conectar directamente con YouTube.\n    Scroll Playback Rate Over Video Player: Cuando el cursor esté sobre el vídeo, presiona y mantén la tecla Control (Comando en Mac) y desplaza la rueda del ratón hacia arriba o abajo para cambiar la velocidad de reproducción. Presiona y mantén la tecla Control (Comando en Mac) y haz clic izquierdo para volver a la velocidad de reproducción por defecto (1x o la que hayas configurado en ajustes).\n    Skip by Scrolling Over Video Player: Use la rueda de desplazamiento para saltar el vídeo, estilo MPV.\n  General Settings:\n    Region for Trending: La región de las tendencias permite ver los vídeos más populares en un país determinado.\n    Invidious Instance: La instancia de Invidious por defecto a la que FreeTube se conectará para las llamadas a la API.\n    Thumbnail Preference: Todas las miniaturas en FreeTube se reemplazarán con un fotograma del vídeo, borroso o oculto, en lugar de la miniatura predeterminada.\n    Fallback to Non-Preferred Backend on Failure: Si la API primaria falla, FreeTube utilizará automáticamente la API secundaria cuando esté activada.\n    Preferred API Backend: Elija el motor que debe utilizar FreeTube para obtener datos. La API local es un extractor incorporado. La API de Invidious requiere de un servidor Invidious al cual conectarse.\n    External Link Handling: \"Elija el comportamiento predeterminado cuando se hace clic en un enlace que no se puede abrir en FreeTube.\\nPor defecto, FreeTube abrirá el enlace en el navegador predeterminado.\\n\"\n    Open Deep Links In New Window: Las URL que se pasan a FreeTube, por ejemplo mediante la redirección de extensiones del navegador o argumentos de la línea de comandos, se abren en una ventana nueva.\n  External Player Settings:\n    Custom External Player Executable: Por defecto, FreeTube buscará el reproductor externo seleccionado mediante la variable de entorno PATH, de no encontrarlo, podrás especificar una ruta personalizada aquí.\n    Custom External Player Arguments: Cualquier argumento personalizado de la línea de comandos que desee pasar al reproductor externo.\n    Ignore Warnings: Ocultar advertencias por argumentos incompatibles con el reproductor (ej. invertir listas de reproducción, etc.).\n    External Player: La elección de un reproductor externo mostrará un icono, para abrir el vídeo (lista de reproducción si es compatible) en el reproductor externo, en la miniatura. Atención, los ajustes de Invidious no afectan a los reproductores externos.\n    DefaultCustomArgumentsTemplate: '(Predeterminado: «{defaultCustomArguments}»)'\n    Ignore Default Arguments: No envíe ningún argumento predeterminado al reproductor externo aparte de la URL del vídeo (por ejemplo, velocidad de reproducción, URL de la lista de reproducción, etc.). Los argumentos personalizados se seguirán transmitiendo.\n  Experimental Settings:\n    Replace HTTP Cache: Desactiva la caché HTTP basada en Electron disk y habilite una caché para la imagen en la memoria personalizada. Esto aumentará el uso de la memoria RAM.\n  Distraction Free Settings:\n    Hide Channels: Introduzca un ID del canal para ocultar todos los vídeos, listas de reproducción y el propio canal para que no aparezcan en las búsquedas, tendencias, más populares y recomendados. El ID del canal introducido debe coincidir completamente y se debe distinguir entre mayúsculas y minúsculas.\n    Hide Subscriptions Live: Esta configuración se reemplaza por la configuración «{appWideSetting}» de toda la aplicación, en la sección «{subsection}» de «{settingsSection}»\n    Hide Videos, Playlists and Channels Containing Text: Introduzca una palabra, fragmento de palabra o frase (sin distinguir mayúsculas de minúsculas) para ocultar todos los vídeos y listas de reproducción cuyos títulos originales la contengan en todo FreeTube, excluyendo únicamente Historial, Tus listas de reproducción y los vídeos dentro de las listas de reproducción.\n    Hide Videos on Watch: Oculta los vídeos vistos de las pestañas de Vídeos, Shorts y En directo en las páginas de Suscripciones y Canales. Esto no afecta a la pestaña de inicio en las páginas de Canales\n  SponsorBlock Settings:\n    UseDeArrowTitles: Sustituye los títulos de los vídeos por títulos enviados por los usuarios desde DeArrow.\n    UseDeArrowThumbnails: Sustituye las miniaturas de vídeo por miniaturas de DeArrow.\nMore: Más\nUnknown YouTube url type, cannot be opened in app: Tipo de URL desconocido. No se puede abrir en la aplicación\nOpen New Window: Abrir ventana nueva\nPlaying Next Video Interval: Reproduciendo el vídeo a continuación. Haz clic para cancelar. | El siguiente vídeo se reproducirá en {nextVideoInterval} segundos. Haz clic para cancelar. | El siguiente vídeo se reproducirá en {nextVideoInterval} segundos. Haz clic para cancelar.\nDefault Invidious instance has been cleared: La instancia de Invidious predeterminada ha sido borrada\nDefault Invidious instance has been set to {instance}: La instancia de Invidious predeterminada ha sido establecida como {instance}\nSearch Bar:\n  Clear Input: Borrar entrada\n  Remove: Eliminar\nExternal link opening has been disabled in the general settings: Se ha desactivado la apertura de enlaces externos en la configuración general\nAre you sure you want to open this link?: ¿Estás seguro/a de que quieres abrir este enlace?\nScreenshot Success: Captura de pantalla guardada\nScreenshot Error: Captura de pantalla fallida. {error}\nNew Window: Nueva ventana\nChannels:\n  Channels: Canales\n  Title: Lista de canales\n  Search bar placeholder: Buscar canales\n  Count: '{number} canal(es) encontrado(s).'\n  Empty: Tu lista de canales está actualmente vacía.\n  Unsubscribe Prompt: ¿Está seguro/segura de querer desuscribirse de «{channelName}»?\nClipboard:\n  Copy failed: Error al copiar al portapapeles\n  Cannot access clipboard without a secure connection: No se puede acceder al portapapeles sin una conexión segura\nChapters:\n  Chapters: Capítulos\n  Key Moments: Momentos clave\nPreferences: Preferencias\nOk: De acuerdo\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Este hashtag no tiene actualmente ningún vídeo\nGo to page: Ir a la {page}\nChannel Hidden: '{channel} añadido al filtro de canales'\nChannel Unhidden: '{channel} eliminado del filtro de canales'\nTag already exists: La etiqueta \"{tagName}\" ya existe\nTrimmed input must be at least N characters long: La entrada recortada debe tener al menos 1 carácter | La entrada recortada debe tener al menos {length} caracteres\nClose Banner: Cerrar el banner\nAge Restricted:\n  This channel is age restricted: Este canal está restringido por edad\n  This video is age restricted: Este vídeo está restringido por edad\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nFeed:\n  Feed Last Updated: '{feedName} feed actualizado por última vez: {date}'\n  Refresh Feed: Actualizar {subscriptionName}\nMoments Ago: hace unos instantes\nYes, Open Link: Sí, abrir el enlace\nCancel: Cancelar\nYes, Restart: Sí, reiniciar\nYes, Delete: Sí, eliminar\nSearch character limit: La consulta de búsqueda supera el límite de {searchCharacterLimit} caracteres\nSearch Listing:\n  Label:\n    Subtitles: Subtítulos\n    Closed Captions: Subtítulos descriptivos\n    4K: 4K\n    360 Video: 360°\n    New: Nuevo\n    8K: 8K\n    VR180: VR180\n    3D: 3D\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: Clic con el botón derecho del ratón o mantén presionado para ver el historial\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Flecha hacia abajo\n  arrowleft: Flecha hacia la izquierda\n  arrowright: Flecha hacía la derecha\n  arrowup: Flecha hacia arriba\n  plus: Suma\n  enter: Intro\n  shift: Mayús\nAutoplay Interruption Timer: Reproducción automática cancelada debido a {autoplayInterruptionIntervalHours} horas de inactividad\nDescription:\n  Expand Description: '...más'\n  Collapse Description: Mostrar menos\nKeyboardShortcutPrompt:\n  New Window: Crear una nueva ventana\n  Captions: Activar/desactivar subtítulos\n  History Forward: Avanzar una página\n  Large Fast Forward: Avanzar 10 segundos / Avanzar video según la tasa de reproducción actual\n  Take Screenshot: Tomar captura de pantalla\n  Next Frame: Frame siguiente (mientras está pausado)\n  Sections:\n    App:\n      Situational: 'Aplicación: Situacional'\n      General: 'Aplicación: General'\n    Video:\n      General: 'Video: General'\n      Playback: 'Video: Reproducción'\n  Large Rewind: Rebobinar 10 segundos / Rebobinar video según la tasa de reproducción actual\n  Toggle Developer Tools: Activar/desactivar herramientas de desarrollador\n  Volume Up: Aumentar volumen\n  Small Fast Forward: Avanzar X segundos según el intervalo de avance rápido y la tasa de reproducción actual\n  Reset Zoom: Restablecer nivel de zoom / Escala de interfaz de usuario\n  Volume Down: Disminuir volumen\n  Keyboard Shortcuts: Atajos de teclado\n  History Backward: Retroceder una página\n  Stats: Mostrar estadísticas del video\n  Minimize Window: Minimizar ventana\n  Small Rewind: Rebobinar X segundos según el intervalo de rebobinado y la tasa de reproducción actual\n  Next Chapter: Próximo capítulo\n  Fullscreen: Activar/desactivar pantalla completa\n  Picture in Picture: Activar/desactivar modo Imagen en Imagen\n  Zoom In: Acercar\n  Zoom Out: Alejar\n  Focus Search: Centrarse en la barra de búsqueda\n  Search in New Window: Buscar en una nueva ventana\n  Last Frame: Frame anterior (mientras está pausado)\n  Last Chapter: Último capítulo\n  Focus Secondary Search: Centrarse en la barra de búsqueda secundaria (si está presente)\n  Play: Activar/desactivar reproducción/pausa\n  Theatre Mode: Activar/desactivar modo de cine\n  Mute: Activar/desactivar silencio\n  Decrease Video Speed: Disminuir velocidad de video según el intervalo de tasa de reproducción\n  Increase Video Speed: Aumentar velocidad de video según el intervalo de tasa de reproducción\n  Full Window: Activar/desactivar ventana completa\n  Show Keyboard Shortcuts: Mostrar atajos de teclado\n  Navigate to Settings: Ir a la página de configuración\n  Navigate to History: Ir a la página de historial\n  Skip by Tenths: Saltar en el video por porcentaje (3 saltos a 30% de la duración)\n  Refresh: Actualizar el feed con el contenido más reciente\n  Close Window: Cerrar ventana\n  Home: Saltar al inicio del vídeo\n  End: Saltar al final del vídeo\n  Skip to Next Video: Salta al siguiente vídeo en la lista de reproducción o al siguiente vídeo recomendado\n  Skip to Previous Video: Salta al vídeo anterior en la lista de reproducción\nshortcutLabelSeparator: ｜\nCompact side navigation: Navegación lateral compacta\nExpand side navigation: Expandir navegación lateral\n"
  },
  {
    "path": "static/locales/et.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'eesti keel'\n\n# Webkit Menu Bar\nFile: 'Fail'\nQuit: 'Välju'\nEdit: 'Muuda'\nUndo: 'Võta tagasi'\nRedo: 'Tee uuesti'\nCut: 'Lõika'\nCopy: 'Kopeeri'\nPaste: 'Aseta'\nDelete: 'Kustuta'\nSelect all: 'Vali kõik'\nToggle Developer Tools: 'Lülita arendustööriistad sisse/välja'\nActual size: 'Tegelik suurus'\nZoom in: 'Suurenda'\nZoom out: 'Suumi välja'\nToggle fullscreen: 'Lülita täisekraan sisse/välja'\nWindow: 'Aken'\nMinimize: 'Vähenda'\nClose: 'Sulge'\nBack: 'Tagasi'\nForward: 'Edasi'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videod'\n  Shorts: Lühivideod\n  Live: Otse\n  Posts: Postitused\n  Sort By: 'Järjestus'\n\n  Counts:\n    Video Count: 1 video | {count} videot\n    Channel Count: 1 kanal | {count} kanalit\n    Subscriber Count: 1 tellija | {count} tellijat\n    View Count: 1 vaatamine | {count} vaatamist\n    Watching Count: 1 vaatamas | {count} vaatamas\n    Like Count: 1 meeldimine | {count} meeldimist\n    Comment Count: 1 kommentaar | {count} kommentaari\nVersion {versionNumber} is now available!  Click for more details: 'Versioon {versionNumber} in nüüd saadaval! Lisateavet leiad siit'\nDownload From Site: 'Laadi veebisaidist alla'\nA new blog is now available, {blogTitle}. Click to view more: 'Uus blogiartikkel on saadaval. Loe siit {blogTitle}'\n\n# Search Bar\nSearch / Go to URL: 'Otsi aadressi või ava see'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Otsingufiltrid'\n  Sort By:\n    Most Relevant: 'Kõige asjakohasemad'\n    Rating: 'Hinnagud'\n    Upload Date: 'Üleslaadimise kuupäev'\n    View Count: 'Vaatamiste arv'\n  Time:\n    Time: 'Aeg'\n    Any Time: 'Millal iganes'\n    Last Hour: 'Viimase tunni kestel'\n    Today: 'Täna'\n    This Week: 'Sel nädalal'\n    This Month: 'Sel kuul'\n    This Year: 'Sel aastal'\n  Type:\n    Type: 'Tüüp'\n    All Types: 'Kõik tüübid'\n    Videos: 'Videod'\n    Channels: 'Kanalid'\n    #& Playlists\n    Movies: Filmid\n  Duration:\n    Duration: 'Kestus'\n    All Durations: 'Kõik kestused'\n    Short (< 4 minutes): 'Lühikesed (alla 4 minuti)'\n    Long (> 20 minutes): 'Pikad (üle 20 minuti)'\n  # On Search Page\n    Medium (4 - 20 minutes): Keskmine (4 - 20 minutit)\n  Search Results: 'Otsingutulemused'\n  Fetching results. Please wait: 'Laadin tulemusi. Palun oota üks hetk'\n  Fetch more results: 'Laadi veel andmeid'\n# Sidebar\n  There are no more results for this search: Sellel otsingul pole rohkem vastuseid\n  Features:\n    Creative Commons: Litsentseeritud Creative Commonsi alusel\n    3D: 3D-sisu\n    HD: 'Kõrgresolutsiooniga video: HD'\n    4K: 'Kõrgresolutsiooniga video: 4K'\n    360 Video: 360 Video\n    HDR: HDR-video\n    Features: Videote omadused\n    Subtitles: Subtiitrid\n    Live: Otseeeter\n    Location: Asukoht\n    VR180: VR180-video\n  Clear Filters: Eemalda filtrid\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Tellimused'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Sinu tellimuste loend on hetkel tühi. Kui sa soovid importida oma tellimusi, siis ava seadistustest „Andmehaldus“ ja vali „Impordi tellimused“, aga samuti võid kanaleid lihtsalt otsida ning seejärel tellida.'\n  Load More Videos: Laadi veel videosid\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Sellel profiilil on väga palju tellimusi. Vältimaks serveripoolseid piiranguid teeme RSS-voo päringud harvemini\n  Error Channels: Vigadega kanalid\n  Disabled Automatic Fetching: Sa oled lülitanud välja automaatse tellimuste laadimise. Uuendatud teabe nägemiseks laadi vaade uuesti.\n  Empty Channels: Sinu tellitud kanalites hetkel pole ühtegi videot.\n  Subscriptions Tabs: Tellimuste vahekaardid\n  All Subscription Tabs Hidden: Kõik tellimuse vahekaardid on peidetud. Siinse sisu nägemiseks palun eemalda kaartide peitmine jaotises „{subsection}“ / „{settingsSection}“.\n  Load More Posts: Lisa järgmised postitused\n  Empty Posts: Sinu tellitud kanalites hetkel pole ühtegi postitust.\nTrending:\n  Trending: 'Populaarsust koguvad videod'\n  Trending Tabs: Populaarsust koguvad kaardid\n  Gaming: Arvutimängud\n  Sports: Sport\nMost Popular: 'Populaarseimad'\nPlaylists: 'Esitusloendid'\nUser Playlists:\n  Your Playlists: 'Sinu esitusloendid'\n  Search bar placeholder: Otsi esindusloendeid\n  Empty Search Message: Selles esitusloendis pole sinu otsingule vastavaid videosid\n  You have no playlists. Click on the create new playlist button to create a new one.: Sul pole esitusloendeid. Uue esitusloendi loomiseks vajuta nuppu „Uus esitusloend“.\n  Remove from Playlist: Eemalda esitusloendist\n  Save Changes: Salvesta muudatused\n  This playlist currently has no videos.: Selles esitusloendis pole hetkel videosid.\n  Add to Playlist: Lisa esitusloendisse\n  Move Video Down: Liiguta video allapoole\n  Playlist Name: Esitusloendi nimi\n  Remove Watched Videos: Eemalda vaadatud videod\n  Move Video Up: Liiguta video ülespoole\n  Cancel: Katkesta\n  Delete Playlist: Kustuta esitusloend\n  Create New Playlist: Loo uus esitusloend\n  Edit Playlist Info: Muuda esitusloendi teavet\n  Copy Playlist: Kopeeri esitusloend\n  Playlist Description: Esitusloendi kirjeldus\n  AddVideoPrompt:\n    Search in Playlists: Otsi esindusloenditest\n    Save: Salvesta\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Video(d) onlisatud ühte esitusloendisse | Video(d) on lisatud esitusloendistesse: {playlistCount} tk\"\n      You haven't selected any playlist yet.: Sa pole veel ühtegi esitusloendit valinud.\n    Select a playlist to add your N videos to: Vali esitusloend, kuhu soovid oma video lisada | Vali esitusloend, kuhu soovid oma {videoCount} videot lisada\n    N playlists selected: '{playlistCount} valitud'\n    Added {count} Times: Juba lisatud {count} kord(a)\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": Lisame {videoCount}/{totalVideoCount} videot\n    Allow Adding Duplicate Video(s): Luba topeltvideo(te) lisamist\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videot on juba lisatud'\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Ei leidnud ühtegi videot, mida saaks eemaldada.\n      Video has been removed: Video on eemaldatud\n      Playlist has been updated.: Esitusloendi andmed on uuendatud.\n      There was an issue with updating this playlist.: Esitusloendi andmete uuendamisel tekkis viga.\n      This video cannot be moved up.: Seda videot ei saa ülespoole liigutada.\n      This playlist is protected and cannot be removed.: Esitusloend on kaitstud ja seda ei saa eemaldada.\n      Playlist {playlistName} has been deleted.: Esitusloend „{playlistName}“ on kustutatud.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Mõned esitusloendi videod on veel laadimata. Kui ikkagi soovid neid kopeerida, klõpsi siia.\n      This playlist does not exist: Sellist esitusloendit ei leidu\n      Playlist name cannot be empty. Please input a name.: Esitusloendi nimi ei saa olla tühi. Palun sisesta nimi.\n      There was a problem with removing this video: Video eemaldamisel tekkis viga\n      \"{videoCount} video(s) have been removed\": 1 video on eemaldatud | {videoCount} videot on eemaldatud\n      This video cannot be moved down.: Seda videot ei saa allapoole liigutada.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: '{oldPlaylistName} asemel on nüüd see esitusloend kasutusel kiirjärjehoidjate jaoks. Selle otsuse tühistamiseks klõpsi siin'\n      This playlist is now used for quick bookmark: See esitusloend on kasutusel kiirjärjehoidjate jaoks\n      Reverted to use {oldPlaylistName} for quick bookmark: Võtsime {oldPlaylistName} uuesti kasutusele kiirjärjehoidjate jaoks\n      This playlist is already being used for quick bookmark.: See esitusloend juba on kasutusel kiirjärjehoidjate jaoks.\n      This playlist has a video with a duration error: Selles esitusloendis on vähemalt üks video, millel puudub kestus. Järjestamisel me sel puhul arvestame kestuseks nulli.\n      Video has been removed. Click here to undo.: Video on eemaldatud. Tagasipööramiseks klõpsi siin.\n    Search for Videos: Otsi videoid\n  Are you sure you want to delete this playlist? This cannot be undone: Kas sa oled kindel, et soovid selle esitusloendi kustutada? Seda tegevust ei saa tagasi pöörata.\n  Sort By:\n    LatestPlayedFirst: Esitamiskuupäev (viimatine esimesena)\n    EarliestCreatedFirst: Loomisaeg (vanim esimesena)\n    LatestCreatedFirst: Loomisaeg (viimatine esimesena)\n    EarliestUpdatedFirst: Uuendamisaeg (vanim esimesena)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Esitamiskuupäev (vanim esimesena)\n    LatestUpdatedFirst: Uuendamisaeg (viimatine esimesena)\n    NameAscending: A-Z\n  CreatePlaylistPrompt:\n    Create: Loo uus esitusloend\n    Toast:\n      There was an issue with creating the playlist.: Esitusloendi loomisel tekkis viga.\n      Playlist {playlistName} has been successfully created.: Esitusloendi „{playlistName}“ loomine õnnestus.\n      There is already a playlist with this name. Please pick a different name.: Sellise nimega esitusloend on juba olemas. Palun sisesta muu nimi.\n    New Playlist Name: Esitusloendi uus nimi\n  Add to Favorites: Lisa esitusloendisse {playlistName}\n  Remove from Favorites: Eemalda esitusloendist {playlistName}\n  Enable Quick Bookmark With This Playlist: Võimalda kiirjärjehoidjate kasutamist selle esitusloendiga\n  Playlists with Matching Videos: Sobivate videotega esitusloendid\n  Quick Bookmark Enabled: Kasuta kiirjärjehoidjaid\n  Cannot delete the quick bookmark target playlist.: Ei saa kustutada esitusloendit, mis on kasutusel kiirjärjehoidjate jaoks.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Kas sa oled kindel, et soovid sellest esitusloendist eemaldada 1 topeltvideo? Seda tegevust ei saa tagasi pöörata. | Kas sa oled kindel, et soovid sellest esitusloendist eemaldada {playlistItemCount} topeltvideot? Seda tegevust ei saa tagasi pöörata.\n  Remove Duplicate Videos: Eemalda topeltvideod\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Kas sa oled kindel, et soovid sellest esitusloendist eemaldada 1 vaadatud video? Seda tegevust ei saa tagasi pöörata. | Kas sa oled kindel, et soovid sellest esitusloendist eemaldada {playlistItemCount} vaadatud videot? Seda tegevust ei saa tagasi pöörata.\n  Export Playlist: Ekspordi see esitusloend\n  The playlist has been successfully exported: Esitusloendi eksportimine õnnestus\n  TotalTimePlaylist: 'Kestus kokku: {duration}'\n  Export list of URLs: Ekspordi võrguaadresside loend\nHistory:\n  # On History Page\n  History: 'Ajalugu'\n  Watch History: 'Vaatamiste ajalugu'\n  Your history list is currently empty.: 'Sinu ajalugu on hetkel tühi.'\n  Search bar placeholder: Otsi ajaloost\n  Empty Search Message: Sinu ajaloos pole sinu otsingule vastavaid videosid\n  Case Sensitive Search: Tõstutundlik otsing\n  DateOldestHistory: Vaatamisaeg (vanim esimesena)\n  DateNewestHistory: Vaatamisaeg (viimatine esimesena)\nSettings:\n  # On Settings Page\n  Settings: 'Seadistused'\n  General Settings:\n    General Settings: 'Üldist'\n    Check for Updates: 'Kontrolli uuendusi'\n    Check for Latest Blog Posts: 'Vaata viimaseid blogipostitusi'\n    Fallback to Non-Preferred Backend on Failure: 'Luba vigade korral kasutada teist taustateenust'\n    Enable Search Suggestions: 'Kasuta otsingusoovitusi'\n    Default Landing Page: 'Vaikimisi avaleht'\n    Locale Preference: 'Lokaadi eelistus'\n    Preferred API Backend:\n      Preferred API Backend: 'Eelistatud taustateenuste API'\n      Local API: 'API kohalikus arvutis'\n      Invidious API: 'API Invidious''e veebirakenduses'\n    Video View Type:\n      Video View Type: 'Kasutatav videote vaade'\n      Grid: 'Ruudustik'\n      List: 'Loend'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Pisipiltide eelistus'\n      Default: 'Vaikimisi'\n      Beginning: 'Alguses'\n      Middle: 'Keskel'\n      End: 'Lõpus'\n      Hidden: Peidetud\n      Blur: Hägusta pildid\n    Region for Trending: 'Mis geograafia alusel tuvastame hetkel menukad ehk populaarsust koguvad videod'\n        #! List countries\n    System Default: Arvuti vaikeseadistused\n    View all Invidious instance information: Vaata kõike teavet kasutatava Invidious'e veebirakenduse kohta\n    Clear Default Instance: Eemalda vaikimisi teenus\n    Set Current Instance as Default: Vali praegune teenus vaikimisi teenuseks\n    Current instance will be randomized on startup: Hetkel kasutatav vaikimisi teenus valitakse rakenduse käivitamisel juhuslikult\n    No default instance has been set: Vaikimisi kasutatav teenus on seadistamata\n    The currently set default instance is {instance}: Hetkel kehtiv vaikimisi teenus on {instance}\n    Current Invidious Instance: Hetkel kasutusel olev Invidious'e teenuse server\n    External Link Handling:\n      No Action: Tegevus puudub\n      External Link Handling: Rakenduseväline lingikäsitlus\n      Open Link: Ava link\n      Ask Before Opening Link: Küsi enne lingi avamist\n    Auto Load Next Page:\n      Label: Laadi järgmine leht automaatselt\n      Tooltip: Laadi järgmised lehed ja kommentaarid automaatselt.\n    Open Deep Links In New Window: Ava FreeTube'ile antud võrguaadressid uues aknas\n    Minimize to system tray: Minimeeri süsteemisalve\n  Theme Settings:\n    Theme Settings: 'Kujundus'\n    Match Top Bar with Main Color: 'Kasuta ülaribal põhivärvi'\n    Base Theme:\n      Base Theme: 'Põhiteema'\n      Black: 'Must'\n      Dark: 'Tume'\n      Light: 'Hele'\n      Dracula: 'Dracula'\n      System Default: Süsteemi vaikeseadistus\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastelne roosa\n      Hot Pink: Säravroosa\n      Nordic: Põhjala\n      Solarized Dark: Tume päikesekuma\n      Solarized Light: Hele päikesekuma\n      Gruvbox Dark: Gruuvimasina tume\n      Gruvbox Light: Gruuvimasina hele\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Low: Lahja ja tume alatine mets (Everforest Dark Low)\n      Everforest Light Hard: Tõsine ja hele alatine mets (Everforest Light Hard)\n      Everforest Light Low: Lahja ja hele alatine mets (Everforest Light Low)\n      Everforest Dark Hard: Tõsine ja tume alatine mets (Everforest Dark Hard)\n      Everforest Light Medium: Keskmine ja hele alatine mets (Everforest Light Medium)\n      Everforest Dark Medium: Keskmine ja tume alatine mets (Everforest Dark Medium)\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Põhiline värviteema'\n      Red: 'Punane'\n      Pink: 'Roosa'\n      Purple: 'Purpurpunane'\n      Deep Purple: 'Sügavpurpurpunane'\n      Indigo: 'Indigosinine'\n      Blue: 'Sinine'\n      Light Blue: 'Helesinine'\n      Cyan: 'Rohekassinine'\n      Teal: 'Sinakasroheline'\n      Green: 'Roheline'\n      Light Green: 'Heleroheline'\n      Lime: 'Kollakasroheline'\n      Yellow: 'Kollane'\n      Amber: 'Merevaigukollane'\n      Orange: 'Oranž'\n      Deep Orange: 'Sügavoranž'\n      Dracula Cyan: 'Dracula rohekassinine'\n      Dracula Green: 'Dracula roheline'\n      Dracula Orange: 'Dracula oranž'\n      Dracula Pink: 'Dracula roosa'\n      Dracula Purple: 'Dracula purpurpunane'\n      Dracula Red: 'Dracula punane'\n      Dracula Yellow: 'Dracula kollane'\n      Catppuccin Mocha Blue: Catppuccin Mocha Sinine\n      Catppuccin Mocha Maroon: Catppuccin Mocha Kastanipunane\n      Catppuccin Mocha Pink: Catppuccin Mocha Roosa\n      Catppuccin Mocha Mauve: Catppuccin Mocha Lillakas\n      Catppuccin Mocha Green: Catppuccin Mocha Roheline\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavendel\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Roosivesi\n      Catppuccin Mocha Red: Catppuccin Mocha Punane\n      Catppuccin Mocha Peach: Catppuccin Mocha Oranž\n      Catppuccin Mocha Yellow: Catppuccin Mocha Kollane\n      Catppuccin Mocha Teal: Catppuccin Mocha Rohekassinine\n      Catppuccin Mocha Sky: Catppuccin Mocha Helesinine\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Safiir\n      Solarized Orange: Oranž päikesekuma\n      Solarized Red: Punane päikesekuma\n      Solarized Magenta: Fuksiapunane päikesekuma\n      Solarized Violet: Punakassinine päikesekuma\n      Solarized Blue: Sinine päikesekuma\n      Solarized Cyan: Rohekassinine päikesekuma\n      Solarized Green: Roheline päikesekuma\n      Solarized Yellow: Kollane päikesekuma\n      Gruvbox Dark Blue: Gruuvimasina tumesinine\n      Gruvbox Light Blue: Gruuvimasina helesinine\n      Gruvbox Dark Green: Gruuvimasina tumeroheline\n      Gruvbox Light Red: Gruuvimasina helepunane\n      Gruvbox Dark Purple: Gruuvimasina tume purpurpunane\n      Gruvbox Dark Orange: Gruuvimasina tumeoranž\n      Gruvbox Dark Yellow: Gruuvimasina kollane\n      Gruvbox Dark Aqua: Gruuvimasina tume veesinine\n      Gruvbox Light Purple: Gruuvimasina hele purpurpunane\n      Gruvbox Light Orange: Gruuvimasina heleoranž\n      Catppuccin Frappe Red: Catppuccin Frappe punane\n      Catppuccin Frappe Maroon: Catppuccin Frappe pruun\n      Catppuccin Frappe Peach: Catppuccin Frappe virsikukarva\n      Catppuccin Frappe Flamingo: Catppuccin Frappe flamingo\n      Catppuccin Frappe Green: Catppuccin Frappe roheline\n      Catppuccin Frappe Pink: Catppuccin Frappe roosa\n      Catppuccin Frappe Teal: Catppuccin Frappe sinakasroheline\n      Catppuccin Frappe Sky: Catppuccin Frappe taevasinine\n      Catppuccin Frappe Sapphire: Catppuccin Frappe safiirsinine\n      Catppuccin Frappe Blue: Catppuccin Frappe sinine\n      Catppuccin Frappe Lavender: Catppuccin Frappe lavendlikarva\n      Catppuccin Frappe Rosewater: Catppuccin Frappe roosivesi\n      Catppuccin Frappe Yellow: Catppuccin Frappe kollane\n      Catppuccin Frappe Mauve: Catppuccin Frappe lillakas\n      Everforest Dark Red: Tumepunane alatine mets (Everforest Dark Red)\n      Everforest Dark Orange: Tumeoranž alatine mets (Everforest Dark Orange)\n      Everforest Dark Yellow: Tumekollane alatine mets (Everforest Dark Yellow)\n      Everforest Dark Green: Tumeroheline alatine mets (Everforest Dark Green)\n      Everforest Dark Blue: Tumesinine alatine mets (Everforest Dark Blue)\n      Everforest Light Red: Helepunane alatine mets (Everforest Light Red)\n      Everforest Light Yellow: Helekollane alatine mets (Everforest Light Yellow)\n      Everforest Light Green: Heleroheline alatine mets (Everforest Light Green)\n      Everforest Light Purple: Hele purpurpunane alatine mets (Everforest Light Purple)\n      Everforest Light Aqua: Hele veesinine alatine mets (Everforest Light Aqua)\n      Everforest Light Orange: Heleoranž alatine mets (Everforest Light Orange)\n      Everforest Light Blue: Helesinine alatine mets (Everforest Light Blue)\n      Everforest Dark Purple: Tume purpurpunane alatine mets (Everforest Dark Purple)\n      Everforest Dark Aqua: Tume veesinine alatine mets (Everforest Dark Aqua)\n      Catppuccin Latte Mauve: Catppuccin Latte lillakas\n      Catppuccin Latte Red: Catppuccin Latte punane\n    Secondary Color Theme: 'Värvide alamteema'\n        #* Main Color Theme\n    UI Scale: Kasutajaliidese suurus\n    Disable Smooth Scrolling: Ära kasuta sujuvat kerimist\n    Expand Side Bar by Default: Vaikimisi näita külgriba laiana\n    Hide Side Bar Labels: Peida külgriba sildid\n    Hide FreeTube Header Logo: Peida FreeTube'i päise logo\n  Player Settings:\n    Player Settings: 'Meediamängija'\n    Play Next Video: 'Esita soovitatud videoid automaatselt'\n    Turn on Subtitles by Default: 'Vaikimisi näita subtiitreid'\n    Autoplay Videos: 'Alusta videote esitust automaatselt'\n    Proxy Videos Through Invidious: 'Puhverda videosid Invidious''e veebiteenuse kaudu'\n    Autoplay Playlists: 'Mängi esitusloendi videoid automaatselt'\n    Enable Theatre Mode by Default: 'Vaikimisi kasuta teatrivaadet (laia vaadet)'\n    Default Volume: 'Vaikimisi helivaljus'\n    Default Playback Rate: 'Vaikimisi videoesituse kiirus'\n    Default Video Format:\n      Default Video Format: 'Vaikimisi videovorming'\n      Dash Formats: 'DASH-vormingud'\n      Legacy Formats: 'Pärandvormingud'\n      Audio Formats: 'Helivormingud'\n    Default Quality:\n      Default Quality: 'Vaikimisi videokvaliteet'\n      Auto: 'Vali automaatselt'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Viivituse taimer järgmise video esitamisel\n    Display Play Button In Video Player: Kuva videomängijas esitamise nuppu\n    Scroll Volume Over Video Player: Muuda helivaljust videovaate kohal kerides\n    Fast-Forward / Rewind Interval: Kiirkerimise välp\n    Scroll Playback Rate Over Video Player: Videomängija kohal saad muuta taasesituskiirust\n    Max Video Playback Rate: Video suurim taasesituskiirus\n    Video Playback Rate Interval: Video taasesituskiiruse intervall\n    Screenshot:\n      Ask Path: Küsi salvestuskausta\n      Folder Label: Kuvatõmmise kaust\n      Format Label: Kuvatõmmise vorming\n      Quality Label: Kuvatõmmise kvaliteet\n      Folder Button: Vali kaust\n      File Name Label: Failinime muster\n      Error:\n        Forbidden Characters: Keelatud tähemärgid\n        Empty File Name: Puuduv failinimi\n      Enable: Luba kuvatõmmise tegemine\n      File Name Tooltip: Võid kasutada allpool näidatud muutujaid. %Y 4-numbriline aasta. %M 2-numbriline kuu. %D 2-numbriline päev. %H 2-numbriline tund 2. %N 2-numbriline minut. %S 2-numbriline sekund. %T 3-numbriline millisekund. %s 2-numbriline videosekund. %t 3-numbriline video millisekund. %i video tunnus.\n    Skip by Scrolling Over Video Player: Jäta vahele, kerides üle videopleieri\n    Enter Fullscreen on Display Rotate: Ekraani pööramisel ava täisekraanivaade\n    Autoplay Interruption Timer: Viivituse taimer järgmise video esitamise katkestamisel\n    Default Viewing Mode:\n      Full Screen: Täisekraanivaade\n      External Player: Väline meediamängija ({externalPlayerName})\n      Theater: Teatrivaade\n      Default Viewing Mode: Vaikimisi vaade\n      Picture in Picture: Pilt pildis vaade\n  Privacy Settings:\n    Privacy Settings: 'Privaatsus'\n    Remember History: 'Jäta vaatamiste ajalugu meelde'\n    Save Watched Progress: 'Salvesta vaatamise järg'\n    Clear Search Cache: 'Kustuta otsingute ajalugu'\n    Are you sure you want to clear out your search cache?: 'Kas sa oled kindel, et soovid kustutada sinu otsingute ajaloo?'\n    Search cache has been cleared: 'Otsingute ajalugu on nüüd kustutatud'\n    Remove Watch History: 'Kustuta vaatamiste ajalugu'\n    Are you sure you want to remove your entire watch history?: 'Kas sa oled kindel, et soovid kustutada kogu sinu vaatamiste ajaloo?'\n    Watch history has been cleared: 'Vaatamiste ajalugu on nüüd kustutatud'\n    Remove All Subscriptions / Profiles: 'Kustuta kõik tellimused / profiilid'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Kas sa oled kindel, et soovid kustutada kõik tellimused/profiilid? Seda tegevust ei saa tagasi pöörata.'\n    Save Watched Videos With Last Viewed Playlist: Salvesta vaadatud videod viimati vaadatud videote esitusloendisse\n    All playlists have been removed: Kõik esitusloendid on eemaldatud\n    Remove All Playlists: Eemalda kõik esitusloendid\n    Are you sure you want to remove all your playlists?: Kas sa oled kindel, et soovid kõik esitusloendid eemaldada?\n    Clear Search History and Cache: Kustuta otsinguajalugu ja sellega seotud puhverdatud andmed\n    Remember Search History: Jäta otsinguajalugu meelde\n    Are you sure you want to clear out your search history and cache?: Kas sa oled kindel, et soovid kustutada otsinguajaloo ja sellega seotud puhverdatud andmed?\n    Search history and cache have been cleared: Otsinguajalugu ja sellega seotud puhverdatud andmed on kustutatud\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automaatne\n        Semi-auto: Poolautomaatne\n        Never: Mitte kunagi\n      Tooltip: Automaatne = Kui video lõppes või tekkis viga (nt tehnilise piirangu või vaatamissessiooni aegumisel), siis salvesta. Poolautomaatne = Sama, nagu automaatne, välja arvatud videovaatest väljumisel ning lisaks saad käsitsi salvestamiseks kasutada videoesitaja all asuvat nuppu „Salvesta vaatamise järg“.\n  Subscription Settings:\n    Subscription Settings: 'Tellimused'\n    Fetch Feeds from RSS: 'Laadi RSS-uudisvood'\n    Fetch Automatically: Laadi tellimuste voog automaatselt\n    Confirm Before Unsubscribing: Väldi ekslikku ja juhuslikku tellimusest loobumist\n    To: Kuni\n    'Limit the number of videos displayed for each channel': Piira igas kanalis näidatavate videote arvu\n  Data Settings:\n    Data Settings: 'Andmehaldus'\n    Select Export Type: 'Vali eksporditava faili vorming'\n    Import Subscriptions: 'Impordi tellimused'\n    Export Subscriptions: 'Ekspordi tellimused'\n    Export FreeTube: 'Ekspordi FreeTube vormingus'\n    Export YouTube: 'Ekspordi YouTube vormingus'\n    Export NewPipe: 'Ekspordi NewPipe vormingus'\n    Import History: 'Impordi ajalugu'\n    Export History: 'Ekspordi ajalugu'\n    Profile object has insufficient data, skipping item: 'Osal profiilis pole piisavalt andmeid ja selle jätan vahele'\n    All subscriptions and profiles have been successfully imported: 'Kõikide tellimuste ja profiilide import õnnestus'\n    All subscriptions have been successfully imported: 'Kõikide tellimuste import õnnestus'\n    Invalid subscriptions file: 'Vigane tellimuste fail'\n    Invalid history file: 'Vigane ajaloofail'\n    Subscriptions have been successfully exported: 'Tellimuste eksportimine õnnestus'\n    History object has insufficient data, skipping item: 'Jätan vahele puuduliku ajalookirje importimise'\n    All watched history has been successfully imported: 'Kogu vaatamiste ajalugu on edukalt imporditud'\n    All watched history has been successfully exported: 'Kogu vaatamiste ajalugu on edukalt eksporditud'\n    Unable to read file: 'Faili lugemine ei õnnestu'\n    Unable to write file: 'Faili kirjutamine ei õnnestu'\n    Unknown data key: 'Tundmatu andmevõti'\n    How do I import my subscriptions?: 'Kuidas ma saan oma tellimusi importida?'\n    Manage Subscriptions: Halda tellimusi\n    Export Playlists: Ekspordi esitusloendeid\n    All playlists has been successfully imported: Kõikide esitusloendite import õnnestus\n    All playlists has been successfully exported: Kõikide esitusloendite eksport õnnestus\n    Import Playlists: Impordi esitusloendeid\n    Playlist insufficient data: „{playlist}“ esitusloendi kohta pole piisavalt andmeid, jätame vahele\n    Subscription File: Tellimuse fail\n    History File: Ajaloo fail\n    Playlist File: Esitusloendi fail\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Selle valikuga ekspordid kõik esitusloendid ühte esitusloendisse „Lemmikud“.\\n Kuidas saad seda eksportimise ja importimise valikut kasutada vanemate FreeTube'i versioonidega:\\n1. Ekspordi kõik oma esitusloendid kasutades seda valikut.\\n 2. Kustuta kõik oma esitusloendid Privaatsusseadistustest kasutades valikut „Kustuta kõik esitusloendid“.\\n3. Käivita vanem FreeTube'i versioon ja impordi esimeses sammus eksporditud esitusloendid.\"\n      Label: Ekspordi esitusloendid vanemate FreeTube'i versioonide jaoks\n    Search history file: Otsinguajaloo fail\n    Search history: Otsinguajalugu\n    Import search history: Impordi otsinguajalugu\n    Export search history: Ekspordi otsinguajalugu\n    All search history has been successfully imported: Kogu otsinguajaloo importimine õnnestus\n    All search history has been successfully exported: Kogu otsinguajaloo eksportimine õnnestus\n  Distraction Free Settings:\n    Hide Active Subscriptions: Peida aktiivsed tellimused\n    Hide Live Chat: Peida veebivestlused\n    Hide Playlists: Peida esitusloendid\n    Hide Popular Videos: Peida enimvaadatud videod\n    Hide Trending Videos: Peida hetkel menukad ehk populaarsust koguvad videod\n    Hide Recommended Videos: Peida soovitatud videod\n    Hide Comment Likes: Peida kommentaaride meeldimised\n    Hide Channel Subscribers: Peida kanalite tellijad\n    Hide Video Likes And Dislikes: Peida videote meeldimiste ja mittemeeldimiste arvud\n    Hide Video Views: Peida videote vaatamiskordade arv\n    Distraction Free Settings: Rahulik vaade\n    Hide Video Description: Peida video kirjeldus\n    Hide Comments: Peida kommentaarid\n    Hide Live Streams: Peida otseülekanded\n    Hide Sharing Actions: Peida jagamisega seotud toimingud\n    Hide Videos on Watch: 'Vaatamisel peida videod'\n    Hide Upcoming Premieres: Peida tulevased esilinastused\n    Hide Chapters: Peida peatükid\n    Hide Channels: Peida kanalites leiduvad videod\n    Hide Channels Placeholder: Kanali tunnus\n    Display Titles Without Excessive Capitalisation: Näita pealkirju ilma liigsete suurtähtede ja kirjavahemärkideta\n    Sections:\n      General: Üldist\n      Side Bar: Külgpaan\n      Channel Page: Kanali vaade\n      Watch Page: Videovaade\n      Subscriptions Page: Tellimuste vaade\n    Hide Featured Channels: Peaida soovitatud kanalid\n    Hide Channel Playlists: Peida kanalite vahekaart „Esitusloendid“\n    Hide Channel Shorts: Peida kanalite vahekaart „Lühivideod“\n    Hide Channel Podcasts: Peida kanalite vahekaart „Taskuhäälingud“\n    Hide Channel Releases: Peida kanalite vahekaart „Väljalasked“\n    Hide Subscriptions Videos: Peida tellimuste videod\n    Hide Subscriptions Shorts: Peida tellimuste lühivideod\n    Hide Subscriptions Live: Peida tellimuste otse-eetrid\n    Hide Profile Pictures in Comments: Peida kommentaaride profiilipildid\n    Hide Channels Invalid: Sisestatud kanali tunnus on vigane\n    Hide Channels Disabled Message: Mõned kanalid on blokeeritud nende tunnuste alusel ja nende andmeid ei töödelda. See funktsionaalsus pole kasutusel, kui nendes kanalites toimub muutusi\n    Hide Channels Already Exists: Selline kanali tunnus juba on sul kirjas\n    Hide Channels API Error: Selle kanali tunnus alusel andmete või kasutaja andmete laadimine ei õnnestunud. Palun kontrolli, et kanali tunnus oleks õige.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Sõna, sõnaosa või fraas\n    Hide Videos, Playlists and Channels Containing Text: Peida videod ja esitusloendid, kus leidub sellist teksti\n    Hide Channel Home: Peida kanalite vahekaart „Avaleht“\n    Show Added Items: Näita lisatud kirjeid\n    Hide Channel Courses: Peida kanalite vahekaart „Kursused“\n    Hide Subscriptions Posts: Peida tellimuste postitused\n    Hide Channel Posts: Peida kanalite vahekaart „Postitused“\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Võrguteavet ei õnnestu leida. Kas sa oled puhverserveri ikka korralikult seadistanud?\n    City: Linn\n    Region: Piirkond\n    Country: Riik\n    Ip: IP-aadress\n    Your Info: Sinu andmed\n    Clicking on Test Proxy will send a request to: Puhverserveri testimisel saadame päringu aadressile\n    Test Proxy: Testi puhverserverit\n    Proxy Port Number: Puhverserveri pordi number\n    Proxy Host: Puhverserveri aadress\n    Proxy Protocol: Puhverserveri protokoll\n    Enable Tor / Proxy: Kasuta Tor'i või puhverserverit\n    Proxy Settings: Puhverserver\n    Proxy Warning: FreeTube'is pole sisseehitatud proksilahendust, kuid ta võib luua ühenduse välise proksi kaudu. Näiteks kasutades sellist, mis töötab sinu arvutis või nutiseadmes, olgu selleks Tor või mõne VPNi poolt pakutav SOCKS5. Kui sa selle eelistuse sisse lülitad, palun jälgi et selline väline proksi on korralikult seadistatud. Vastasel juhul võrguühendus ei toimi ja FreeTube ei saa andmeid laadida.\n    Proxy Username: Puhverserveri kasutajanimi\n    Proxy Password: Puhverserveri salasõna\n  The app needs to restart for changes to take effect. Restart and apply change?: See rakendus vajab muudatuste jõustamiseks uuesti käivitamist. Kas teeme seda nüüd?\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Anna teada, kui toetajate vaade jääb vahele\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Sponsorite blokeerija API URL (vaikimisi https://sponsor.ajay.app)\n    Enable SponsorBlock: Kasuta sponsorite blokeerijat\n    SponsorBlock Settings: Sponsorite blokeerija\n    Skip Options:\n      Auto Skip: Automaatne vahelejätmine\n      Show In Seek Bar: Näita otsinguribal\n      Prompt To Skip: Paku vahelejätmise võimalust\n      Skip Option: Jäta valik vahele\n      Do Nothing: Ära tee midagi\n    Category Color: Kategooria värv\n    UseDeArrowTitles: Laadi video pealkirjad DeArrow teenusest\n    UseDeArrowThumbnails: Pisipiltide jaoks kasuta DeArrow teenust\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow pisipiltide loomise teenuse API url (Vaikimisi on see https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    External Player: Väline meediamängija\n    External Player Settings: Väline meediamängija\n    Custom External Player Arguments: Välise meediamängija rakenduse argumendid\n    Custom External Player Executable: Välise meediamängija rakenduse asukoht\n    Ignore Unsupported Action Warnings: Eira mittetoetatud toimingute hoiatusi\n    Players:\n      None:\n        Name: Puudub\n    Ignore Default Arguments: Eira vaikimisi käsureaargumente\n  Parental Control Settings:\n    Parental Control Settings: Vanemlik järelevalve\n    Hide Unsubscribe Button: Peida tellimuse tühistamise nupp\n    Show Family Friendly Only: Näita ainult peresõbralikku sisu\n    Hide Search Bar: Peida otsinguriba\n    Hide Uploader on Watch page: Peida üleslaadija videovaate lehelt\n  Experimental Settings:\n    Experimental Settings: Katsed\n    Warning: Tegemist on katseliste seadistustega ja sisselülitamisel võivad põhjustada rakenduse kokkujooksmist. Kindlasti ära unusta oma andmete varundamist. Jätka omal vastutusel!\n    Replace HTTP Cache: Asenda HTTP vahemälu\n  Password Dialog:\n    Enter Password To Unlock: Seadistuste avamiseks sisesta salasõna\n    Password: Salasõna\n  Password Settings:\n    Password Settings: Salasõnad\n    Remove Password: Eemalda salasõna\n    Set Password: Määra salasõna\n    Set Password To Prevent Access: Vältimaks ligipääsu seadistustele määra salasõna\n  Sort Settings Sections (A-Z): Järjesta seadistused (A-Z)\n  Return to Settings Menu: Tagasi seadistuste menüü juurde\nAbout:\n  #On About page\n  About: 'Teave'\n  #& About\n  Email: E-post\n  Donate: Toeta meid\n  these people and projects: tänu nendele inimestele ja projektidele\n  Credits: Tänuavaldused\n  Translate: Tõlgi\n  room rules: jututoa reeglitega\n  Chat on Matrix: Vestle meiega Matrixi võrgus\n  Mastodon: Mikroblogiteenus Mastodon\n  Blog: Blogi\n  Website: Veebisait\n  Please check for duplicates before posting: Enne uue veateate tegemist palun kontrolli, kas sellest on juba meile teada antud\n  GitHub issues: Teata vigadest GitHub'i vahendusel\n  Report a problem: Vead ja probleemid\n  FAQ: KKK\n  FreeTube Wiki: FreeTube viki\n  Help: Abiteave\n  GitHub releases: GitHub'is avaldatud versioonid\n  Downloads / Changelog: Allalaadimised ja muudatuste logi\n  Source code: Lähtekood\n  Beta: beetaversioon\n  Discussions: Arutelud\n  AGPLv3: AGPLv3 alusel\n  FreeTube is made possible by {creditsPageLink}: 'FreeTube on loodud järgnevate arendajate poolt: {creditsPageLink}'\n  Please read the {roomRulesLink}: 'Palun loe: {roomRulesLink}'\n  Licensed under the {licenseLink}: 'Kasutusel litsents: {licenseLink}'\nProfile:\n  Profile Select: 'Vali profiil'\n  All Channels: 'Kõik kanalid'\n  Profile Manager: 'Profiilihaldur'\n  Create New Profile: 'Loo uus profiil'\n  Edit Profile: 'Muuda profiili'\n  Color Picker: 'Vali värv'\n  Custom Color: 'Vali täpne värv'\n  Profile Preview: 'Profiili eelvaade'\n  Create Profile: 'Loo profiil'\n  Update Profile: 'Uuenda profiili'\n  Make Default Profile: 'Määra vaikimisi profiiliks'\n  Delete Profile: 'Kustuta profiil'\n  Are you sure you want to delete this profile?: 'Kas sa kindlasti soovid selle profiili kustutada?'\n  All subscriptions will also be deleted.: 'Samaga kustutame ka kõik tellimused.'\n  Your profile name cannot be empty: 'Profiilil peab olema nimi'\n  Profile has been created: 'Profiili loomine õnnestus'\n  Profile has been updated: 'Profiili uuendamine õnnestus'\n  Your default profile has been set to {profile}: 'Määrasin {profile} sinu vaikimisi profiiliks'\n  Removed {profile} from your profiles: 'Kustutasin {profile} sinu profiilide loendist'\n  Your default profile has been changed to your primary profile: 'Muutsin sinu esmase profiili vaikimisi kasutatavaks profiiliks'\n  '{profile} is now the active profile': '{profile} on nüüd kasutusel olev profiil'\n  Subscription List: 'Tellimuste loend'\n  Other Channels: 'Muud kanalid'\n  '{number} selected': '{number} on valitud'\n  Select All: 'Vali kõik'\n  Select None: 'Ära vali mitte midagi'\n  Delete Selected: 'Kustuta valik'\n  Add Selected To Profile: 'Lisa valik profiilile'\n  No channel(s) have been selected: 'Sa pole kanaleid valinud'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'See on sinu algne profiil. Kas sa kindlasti soovid kustutada valitud kanalid? Me kustutame nad sel juhul ka kõikidest profiilidest.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Kas sa kindlasti soovid kustutada valitud kanalid? Sellega me ei kustuta neid teistest profiilidest.'\n#On Channel Page\n  Profile Filter: Sirvi profiile\n  Profile Settings: Profiil\n  Toggle Profile List: Lülita profiilide loend sisse/välja\n  Profile Name: Profiili nimi\n  Edit Profile Name: Muuda profiili nime\n  Create Profile Name: Loo profiilile nimi\n  Open Profile Dropdown: Ava profiili rippmenüü\n  Close Profile Dropdown: Sulge profiili rippmenüü\nChannel:\n  Subscribe: 'Telli'\n  Unsubscribe: 'Lõpeta tellimus'\n  Channel has been removed from your subscriptions: 'Kustutasin kanali sinu tellimustest'\n  Removed subscription from {count} other channel(s): 'Kustutasin tellimuse ka {count}''st muust kanalist'\n  Added channel to your subscriptions: 'Lisasin kanali sinu tellimuste hulka'\n  Search Channel: 'Otsi kanalit'\n  Your search results have returned 0 results: 'Otsingul on 0 tulemust'\n  Videos:\n    Videos: 'Videod'\n    This channel does not currently have any videos: 'Sellel kanalik pole hetkel ühtegi videot'\n    Sort Types:\n      Newest: 'Uusimad'\n      Oldest: 'Vanimad'\n      Most Popular: 'Kõike populaarsemad'\n  Playlists:\n    Playlists: 'Esitusloendid'\n    This channel does not currently have any playlists: 'Sellel kanalil pole hetkel ühtegi esitusloendit'\n    Sort Types:\n      Last Video Added: 'Viimati lisatud video'\n      Newest: 'Uusimad'\n      Oldest: 'Vanimad'\n  About:\n    About: 'Kanali teave'\n    Channel Description: 'Kanali kirjeldus'\n    Featured Channels: 'Soovitatud kanalid'\n    Details: Üksikasjad\n    Location: Asukoht\n    Tags:\n      Search for: Otsi silti „{tag}“\n      Tags: Sildid\n    Joined: Liitunud\n  This channel does not allow searching: See kanal ei luba otsingu kasutamist\n  Channel Tabs: Kanali kaardid\n  Shorts:\n    This channel does not currently have any shorts: Sellel kanalil pole lühivideosid\n  Live:\n    Live: Otseeeter\n    This channel does not currently have any live streams: Sellel kanalil pole hetkel ühtegi otseeetrit\n  Posts:\n    This channel currently does not have any posts: Sellel kanalil pole hetkel postitusi\n    Reveal Answers: Näita vastuseid\n    Hide Answers: Peida vastused\n    votes: '{votes} häält'\n    Video hidden by FreeTube: FreeTube'i poolt peidetud video\n    View Full Post: Vaata kogu postitust\n    Viewing Posts Only Supported By Invidious: Postituste vaatamine toimib vaid Invidiouse liidestusega. Ilma selleta saad lugeda sisu, mida näed kanali kogukonna vaatest.\n  This channel does not exist: Sellist kanalit ei leidu\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Sellel kanalil on vanusega seotud piirangud ja teda ei saa hetkel FreeTube'i vahendusel vaadata.\n  Podcasts:\n    Podcasts: Taskuhäälingud\n    This channel does not currently have any podcasts: Sellel kanalil hetkel pole taskuhäälinguid\n  Releases:\n    This channel does not currently have any releases: Sellel kanalil pole hetkel ühtegi väljalaset\n    Releases: Väljalasked\n  Home:\n    Home: Avaleht\n    View Playlist: Vaata esitusloendit\n  Courses:\n    Courses: Kursused\n    This channel does not currently have any courses: Sellel kanalil pole hetkel kursuseid\nVideo:\n  Mark As Watched: 'Märgi vaadatuks'\n  Remove From History: 'Kustuta ajaloost'\n  Video has been marked as watched: 'Video on märgitud vaadatuks'\n  Video has been removed from your history: 'Video on kustutatud sinu vaatamiste ajaloost'\n  Open in YouTube: 'Ava YouTube''is'\n  Copy YouTube Link: 'Kopeeri YouTube''i link'\n  Open YouTube Embedded Player: 'Ava YouTube''i lõimitud meediamängija'\n  Copy YouTube Embedded Player Link: 'Kopeeri YouTube''i lõimitud meediamängija link'\n  Open in Invidious: 'Ava Invidious''e veebirakenduses'\n  Copy Invidious Link: 'Kopeeri Invidious''e veebirakenduse link'\n  Views: 'Vaatamist'\n  Loop Playlist: 'Korda esitusloendit'\n  Shuffle Playlist: 'Sega esitusloend'\n  Reverse Playlist: 'Pööra esitusloend tagurpidi'\n  Previous: 'Eelmine'\n  Next: 'Järgmine'\n  Watched: 'Vaadatud'\n  Autoplay: 'Automaatne esitus'\n  Starting soon, please refresh the page to check again: 'Kuvamine algab varsti, vajadusel värskenda uuesti kontrollimiseks lehte'\n  # As in a Live Video\n  Live: 'Otse eetris'\n  Live Now: 'Hetkel otseeetris'\n  Live Chat: 'Vestlus reaalajas'\n  Enable Live Chat: 'Luba reaalajas vestlust'\n  Live Chat is currently not supported in this build.: 'Reaalajas vestlus ei ole selles versioonis toetatud.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Reaalajas vestlus on kasutusel. Sõnumid on nähtaval kohe pärast saatmist.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Kui kasutad Invidious''e veebiteenuse-põhist API''t, siis reaalajas vestlus ei ole toetatud. Selleks on vajalik otseliidestus YouTube''ga.'\n  Published:\n    In less than a minute: Vähem kui minuti pärast\n  Published on: 'Avaldatud'\n#& Videos\n  Copy Invidious Channel Link: Kopeeri kanali link Invidious'e veebirakenduses\n  Open Channel in Invidious: Ava kanal Invidious'e veebirakenduses\n  Copy YouTube Channel Link: Kopeeri YouTube'i kanali link\n  Open Channel in YouTube: Ava kanal YouTube'is\n  Video has been removed from your saved list: Video on kustutatud sinu salvestatud videote loendist\n  Video has been saved: Video on salvestatud\n  Save Video: Salvesta video\n  Started streaming on: Voogedastus algas\n  Streamed on: Voogedastatud\n  Sponsor Block category:\n    music offtopic: Esitatava muusika teemaväline teave\n    self-promotion: Enesereklaam\n    interaction: Suhtlus\n    intro: Sissejuhatus\n    outro: Lõputiitrid\n    sponsor: Sponsor\n    filler: Täitevideo\n    recap: Kokkuvõte\n  External Player:\n    UnsupportedActionTemplate: 'Rakenduses {externalPlayer} puudub tugi: {action}'\n    OpeningTemplate: Avan {videoOrPlaylist} {externalPlayer} rakendusega...\n    playlist: esitusloend\n    video: video\n    OpenInTemplate: Ava rakendusega {externalPlayer}\n    Unsupported Actions:\n      looping playlists: esitusloendi kordamine\n      shuffling playlists: esitusloendi segamine\n      reversing playlists: esitusloendi järjekorra pööramine\n      opening specific video in a playlist (falling back to opening the video): esitusloendis asuva video avamine (või selle asemel video avamine)\n      opening playlists: esitusloendite avamine\n      setting a playback rate: taasesituskiiruse määramine\n      starting video at offset: video esitamine ajanihkega\n  Premieres: Esilinastus\n  Show Super Chat Comment: Näita Super Chat'i kommentaare\n  Scroll to Bottom: Keri alla\n  Upcoming: Tulemas\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Otsevestlus pole selle videovoo puhul saadaval. Võib-olla on üleslaadija vestluse keelanud.\n  Unhide Channel: Näita kanalit\n  Hide Channel: Peida kanal\n  More Options: Lisavalikud\n  Player:\n    Audio Tracks: Heliribad\n    Theatre Mode: Teatrivaade\n    Exit Theatre Mode: Välju teatrivaatest\n    Full Window: Täisekraanivaade\n    Take Screenshot: Tee ekraanitõmmis\n    Show Stats: Näita statistikat\n    Stats:\n      Video ID: 'Video tunnus: {videoId}'\n      Media Formats: 'Meediavormingud: {formats}'\n      Bitrate: 'Bitikiirus: {bitrate} kbps'\n      Volume: 'Valjus: {volumePercentage}%'\n      Bandwidth: 'Ribalaius: {bandwidth} kbps'\n      Buffered: 'Puhverdatud: {bufferedPercentage}%'\n      CodecAudio: 'Koodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Koodekid: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Koodekid: {videoCodec} / {audioCodec}'\n      Stats: Statistika\n      Resolution: 'Mõõdud ja kaadrisagedus: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Meediamängija mõõdud: {width}x{height}'\n      Dropped Frames / Total Frames: 'Vahelejäetud kaadreid: {droppedFrames} / Kaadreid kokku: {totalFrames}'\n    Skipped segment: Vahelejäetud {segmentCategory} segment\n    TranslatedCaptionTemplate: '{language} (algne keel „{originalLanguage}“)'\n    Exit Full Window: Välju täisekraanivaatest\n    Hide Stats: Peida statistika\n    Playback will resume automatically when your connection comes back: Taasesitus jätkub automaatselt niipea, kui sinu seadme võrguühendus taastub.\n    You appear to be offline: Sa ei tundu olema võrgus.\n    Autoplay is off: Automaatne esitamine on kasutusel\n    Autoplay is on: Automaatne esitamine pole kasutusel\n  IP block: YouTube on blokeerinud sinu nutiseadme IP-aadressilt videote vaatamise. Palun kasuta mõnda muud lahendust, nagu VPN-teenust või puhverserverit.\n  MembersOnly: Kuna vajalik on sisselogimine Google'i kontoga ja tasuline liikmelisus üleslaadija kanalis, siis ainult liikmetele mõeldud videoid ei saa FreeTube'is vaadata.\n  AgeRestricted: Kuna vajalik on sisselogimine Google'i kontoga, kus vanus on kontrollitud, siis vanusepiiranguga videoid ei saa FreeTube'is vaadata.\n  Unlisted: Registriväline\n  DeArrow:\n    Show Original Details: Näita algseid üksikasju\n    Show Modified Details: Näita muudetud üksikasju\n  DRMProtected: Kuna vajalikud on suletud lähtekoodil põhinevad komponendid, siis DRMiga kaitstud videoid FreeTube esitada ei saa. Kui soovid seda videot vaadata, siis tee seda otse YouTube'i saidis kasutades DRMi-suutlikku brauserit.\n#& Playlists\n  Save Watched Progress: Salvesta vaatamise järg\n  Watched Progress Saved: Vaatamise järg on salvestatud\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Järelejäänud sisueelse reklaami aeg: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Järelejäänud aeg SABR-protokollist loobumiseks: {remindingTimeSeconds}s'\n  Popout Live Chat: Vestlus hüpikaknas\nPlaylist:\n  #& About\n  View Full Playlist: 'Näita kogu esitusloendit'\n  Last Updated On: 'Viimati uuendatud'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Esitusloend\n  Sort By:\n    Custom: Kohandatud\n    DateAddedNewest: Lisamisaeg (viimatine esimesena)\n    DateAddedOldest: Lisamisaeg (vanim esimesena)\n    AuthorAscending: Autori alusel (A-Z)\n    AuthorDescending: Autori alusel (Z-A)\n    VideoTitleAscending: Pealkirja alusel (A-Z)\n    VideoTitleDescending: Pealkirja alusel (Z-A)\n    VideoDurationAscending: Kestus (esmalt lühemad)\n    VideoDurationDescending: Kestus (esmalt pikemad)\n    PublishedOldest: Avaldamisaeg (vanim esimesena)\n    PublishedNewest: Avaldamisaeg (viimatine esimesena)\nChange Format:\n  Change Media Formats: 'Muuda videovorminguid'\n  Use Dash Formats: 'Kasuta DASH-vorminguid'\n  Use Legacy Formats: 'Kasuta pärandvorminguid'\n  Use Audio Formats: 'Kasuta helivorminguid'\n  Dash formats are not available for this video: 'DASH-vormingud ei ole selle video jaoks saadaval'\n  Audio formats are not available for this video: 'Helivormingud ei ole selle video jaoks saadaval'\n  Legacy formats are not available for this video: Pärandvormingud pole selle video jaoks saadaval\nShare:\n  Share Video: 'Jaga videot'\n  Share Playlist: 'Jaga esitusloendit'\n  Include Timestamp: 'Lisa ajale järjehoidja'\n  Copy Link: 'Kopeeri link'\n  Open Link: 'Ava link'\n  Copy Embed: 'Kopeeri lõiming'\n  Open Embed: 'Ava lõiming'\n  # On Click\n  Invidious URL copied to clipboard: 'Kopeerisin Invidious''e API aadressi lõikelauale'\n  Invidious Embed URL copied to clipboard: 'Kopeerisin Invidious''e API aadressi lõikelauale'\n  YouTube URL copied to clipboard: 'Kopeerisin YouTube''i aadressi lõikelauale'\n  YouTube Embed URL copied to clipboard: 'Kopeerisin YouTube''i lõimingu aadressi lõikelauale'\n  YouTube Channel URL copied to clipboard: Kopeerisin YouTube'i kanali aadressi lõikelauale\n  Invidious Channel URL copied to clipboard: Kopeerisin kanali aadressi Invidious'e API'st lõikelauale\n  Share Channel: Jaga kanalit\n  Share Post: Jaga postitust\nMini Player: 'Kompaktne vaade'\nComments:\n  Comments: 'Kommentaarid'\n  Click to View Comments: 'Kommentaaride vaatamiseks klõpsi'\n  Getting comment replies, please wait: 'Laadin kommentaari vastuseid, palun oota'\n  There are no more comments for this video: 'Sellel videol ei ole rohkem kommentaare'\n  Hide Comments: 'Peida kommentaarid'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Seda videot pole veel kommenteeritud'\n  Load More Comments: 'Laadi veel kommentaare'\n  Newest first: Uuemad esimesena\n  Top comments: Parimad esimesena\n  Show More Replies: Näita järgmisi vastuseid\n  Pinned by: Esiplaanile tõstja\n  Member: Liige\n  Hearted: Südamlik\n  View {replyCount} replies: Näita üht vastust | Näita {replyCount} vastust\n  Subscribed: Tellitud\n  There are no comments available for this post: Sellel postitusel pole ühtegi kommentaari\n  Hide {replyCount} replies: Peida üks vastus | Peida {replyCount} vastust\n  View 1 reply from {channelName}: Vaata üht vastust kanalist {channelName}\n  View {replyCount} replies from {channelName} and others: Vaata {replyCount} vastust kanalist {channelName} ja muudest allikatest\nUp Next: 'Järgmisena'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Kohaliku API viga (kopeerimiseks klõpsi)'\nInvidious API Error (Click to copy): 'Invidious''e API viga (kopeerimiseks klõpsi)'\nFalling back to Invidious API: 'Varuvariandina kasutan Invidious''e API''t'\nFalling back to Local API: 'Varuvariandina kasutan kohalikku API''t'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Kuna vajalikke vorminguid ei leidu, siis see video pole saadaval. Niisugune viga võib juhtuda ka maapiirangute tõttu.'\nLoop is now disabled: 'Esituse kordamine ei ole nüüd kasutusel'\nLoop is now enabled: 'Esituse kordamine on nüüd kasutusel'\nShuffle is now disabled: 'Juhuslik esitus ei ole nüüd kasutusel'\nShuffle is now enabled: 'Juhuslik esitus on nüüd kasutusel'\nThe playlist has been reversed: 'Esitusloendi järjekord on nüüd teistpidi'\nPlaying Next Video: 'Esitan järgmist videot'\nPlaying Previous Video: 'Esitan eelmist videot'\nCanceled next video autoplay: 'Tühistasin järgmise video automaatse esituse'\n'The playlist has ended. Enable loop to continue playing': 'Esitusloend on läbi. Esituse jätkamiseks luba lugude kordamine'\n\nYes: 'Jah'\nNo: 'Ei'\nMore: Veel\nOpen New Window: Ava uus aken\nUnknown YouTube url type, cannot be opened in app: Tundmatu YouTube'i urli tüüp, mida ei saa rakenduses avada\nTooltips:\n  External Player Settings:\n    Custom External Player Executable: Vaikimisi eeldab FreeTube, et väline meediamängija on leitav PATH keskkonnamuutuja alusel. Aga kui vaja, siis saad siin seadistada muu asukoha.\n    Ignore Warnings: Kui väline meediamängija antud funktsionaalsust (näiteks esitusloendi järjekorra pööramine) ei toeta, siis ära näita hoiatusi.\n    Custom External Player Arguments: Misiganes käsurea argumendid, mida sa soovid välisele meediamängijale saata.\n    External Player: \"Seadistades välise meediamängija kuvame pisipildil ikooni video (või esitusloendi) esitamiseks välises meediamängijas. Hoiatus: Invidious'e seadistused ei mõjuta välise meediamängija kasutamist.\"\n    DefaultCustomArgumentsTemplate: \"(Vaikimisi: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Ära edasta välisele meediamängijale ühtegi vaikimisi määratud argumenti peale video urli (näiteks taasesituse kiirus, esitusloend jne). Sinu enda määratud argumendid edastatakse vaatamata sellele seadistusele.\n  Subscription Settings:\n    Fetch Feeds from RSS: Selle valiku kasutamisel FreeTube pruugib tellimuste andmete laadimisel vaikimisi meetodi asemel RSS-uudisvoogu. RSS on kiirem ja välistab IP-aadressi blokeerimise, kuid ei sisalda video kestust, otseesituse olekut ja postitusi\n    Fetch Automatically: Kui see valik on kasutusel, siis FreeTube automaatselt laadib rakenduse käivitamisel ja uue akna avamisel sinu tellimuste loendi.\n  General Settings:\n    Region for Trending: Piirkond, mille alusel kuvame hetkel menukad ehk populaarsust koguvad videod.\n    Thumbnail Preference: Vaikimisi pisipildi asemel kuvab FreeTube kõikjal läbi rakenduse kaadrit videost ja seda hägusena ja peidetuna.\n    Fallback to Non-Preferred Backend on Failure: Kui sinu eelistatud APi ei toimi, siis kui vähegi võimalik, FreeTube üritab kasutada alternatiivi.\n    Preferred API Backend: Vali taustateenus, mida FreeTube kasutab andmete laadimisel. Kohalik API on rakenduses olemas ja Invidious'e API eeldab välise teenuseserveri kasutamist.\n    Invidious Instance: Invidious'e teenuse server, mida FreeTube kasutab API kutse tegemisel.\n    External Link Handling: \"Vali vaikekäitumine, kui vajutatakse linki, mida ei saa avada FreeTubes.\\nVaikimisi avaneb link kasutaja vaikebrauseris.\\n\"\n    Open Deep Links In New Window: FreeTube'ile brauseritest või käsurealt antud võrguaadressid avatakse uues aknas.\n  Player Settings:\n    Default Video Format: Vali kasutatavad videovormingud. DASH-vormingutel on üldjuhul parem kvaliteet. Pärandvormingute kvaliteedi ülempiir on 360p ja seetõttu kasutavad nad vähem ribalaiust. Helivormingud kehtivad vaid helifailide jaoks.\n    Proxy Videos Through Invidious: Kasutab videote esitamiseks Invidious'e teenust ega tee päringuid otse YouTube serveri pihta.\n    Scroll Playback Rate Over Video Player: Kui kursor on video kohal, siis vajuta Ctrl klahvi (Mac'is ⌘ klahvi) ja taasesituse kiiruse muutmiseks keri hiireratast edasi ja tagasi. Tavakiiruse taastamiseks (kui sa seda seadistustest pole muutnud, siis on see 1x) hoia all Ctrl klahvi (Mac'is ⌘ klahvi) ja klõpsi hiire vasakut nuppu.\n    Skip by Scrolling Over Video Player: MPV-stiilis video läbilappamiseks kasuta hiire ratast.\n  Distraction Free Settings:\n    Hide Channels: Sisesta kanali tunnus, et kõik videod, esitusloendid ja kanal ise ei oleks nähtav otsingus, soovitatavate videote, populaarsete videote ja populaarsust koguvate videote vaates. Sisestatud kanali tunnus peab otsingule vastama täpselt ja on tõstutundlik.\n    Hide Subscriptions Live: Selle seadistuse tühistab rakenduseülene „{appWideSetting}“ seadistus „{subsection}“/„{settingsSection}“\n    Hide Videos, Playlists and Channels Containing Text: Sisesta sõna, sõnaosa või fraas (tõstutundetuna), mille alusel peidetakse läbivalt FreeTube'is kõik videod või esitusloendid, kus see leidub algses pealkirjas. Peitmine ei toimi ajaloos, sinu loodud esitusloendites ja esitusloendi sees olevate videote puhul.\n    Hide Videos on Watch: Peidab vaadatud sisu videote, lühivideote ja otseeetri kaartidelt tellimuste ja kanalite lehtedelt. Ei mõjuta avakaarti kanalite lehtedel\n  Experimental Settings:\n    Replace HTTP Cache: Sellega lülitatakse välja Electron'i standardne kettal paiknev http-puhver ja võetakse kasutusele rakenduse mälupõhine puhver. Üheks tulemuseks saab olema suurem mälukasutus.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Asenda video nimi kasutajate poolt DeArrow teenusesse lisatud nimega (pealkirjaga).\n    UseDeArrowThumbnails: Asenda video pisipildid DeArrow teenuse loodud pisipiltidega.\nPlaying Next Video Interval: Kohe esitan järgmist videot. Tühistamiseks klõpsi. | {nextVideoInterval} sekundi möödumisel esitan järgmist videot. Tühistamiseks klõpsi. | {nextVideoInterval} sekundi möödumisel esitan järgmist videot. Tühistamiseks klõpsi.\nDefault Invidious instance has been cleared: Vaikimisi kasutatav Invidious'e teenus on kustutatud\nDefault Invidious instance has been set to {instance}: Vaikimisi kasutatav Invidious'e teenus on {instance}\nSearch Bar:\n  Clear Input: Kustuta sisend\n  Remove: Eemalda\nExternal link opening has been disabled in the general settings: Väliste linkide avamine on üldistes seadistustes keelatud\nAre you sure you want to open this link?: Oled kindel, et soovid seda linki avada?\nNew Window: Uus aken\nScreenshot Error: Kuvatõmmise tegemine ei õnnestunud. {error}\nChannels:\n  Channels: Kanalid\n  Title: Kanalite loend\n  Search bar placeholder: Otsi kanaleid\n  Count: Leidsime {number} kanali(t).\n  Empty: Sinu kanalite loend on praegu tühi.\n  Unsubscribe Prompt: Kas oled kindel, et soovid „{channelName}“ tellimusest loobuda?\nScreenshot Success: Ekraanitõmmis on salvestatud\nClipboard:\n  Copy failed: Lõikelauale kopeerimine ei õnnestunud\n  Cannot access clipboard without a secure connection: Ilma turvalise ühenduseta ei pääse ligi lõikelauale\nChapters:\n  Chapters: Peatükid\n  Key Moments: Olulised hetked\nOk: Sobib\nPreferences: Eelistused\nHashtag:\n  Hashtag: Teemaviide\n  This hashtag does not currently have any videos: Selle teemaviite ehk haaksõna alusel ei leidu hetkel ühtegi videot\nChannel Hidden: '{channel} on lisatud kanalite filtrisse'\nGo to page: 'Ava leht: {page}'\nChannel Unhidden: '{channel} on eemaldatud kanalite filtrist'\nTag already exists: Silt „{tagName}“ on juba olemas\nTrimmed input must be at least N characters long: Kärbitud sisend peab olema vähemalt 1 tähemärgi pikkune | Kärbitud sisend peab olema vähemalt {length} tähemärgi pikkune\nAge Restricted:\n  This channel is age restricted: Kanali vaatamisel on vanusepiirang\n  This video is age restricted: Video vaatamisel on vanusepiirang\nClose Banner: Sulge rekaampilt\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nFeed:\n  Feed Last Updated: 'Tellimustevoo „{feedName}“ viimane uuendus: {date}'\n  Refresh Feed: Uuenda {subscriptionName} andmed\nMoments Ago: hetk tagasi\nYes, Restart: Jah, käivita uuesti\nCancel: Katkesta\nSearch character limit: Otsingupäring on lubatud {searchCharacterLimit}-tähemärgisest piirist pikem\nYes, Delete: Jah, kustuta\nYes, Open Link: Jah, ava link\nSearch Listing:\n  Label:\n    Subtitles: Subtiitrid\n    Closed Captions: Subtiitrid\n    4K: 4K\n    New: Uus\n    3D: 3D-sisu\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nKeys:\n  arrowup: Nool üles\n  alt: Alt\n  ctrl: Ctrl\n  arrowleft: Nool vasakule\n  arrowright: Nool paremale\n  arrowdown: Nool alla\n  plus: Plus\n  shift: Shift\n  enter: Enter\nRight-click or hold to see history: Ajaloo nägemiseks klõpsa parema hiireklahviga ja hoia klahvi all\nAutoplay Interruption Timer: Automaatne esitamine katkes peale {autoplayInterruptionIntervalHours} tundi jõudeolekut\nDescription:\n  Expand Description: '...vaata lisaks'\n  Collapse Description: Näita vähem\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Klaviatuuri kiirklahvid\n  Sections:\n    Video:\n      General: 'Video: Üldine'\n      Playback: 'Video: taasesitus'\n    App:\n      Situational: 'Rakendus: Olukorrateadlik'\n      General: 'Rakendus: Üldine'\n  Show Keyboard Shortcuts: Näita kiirklahve\n  History Backward: Tagasi ühe lehe võrra\n  History Forward: Edasi ühe lehe võrra\n  New Window: Loo uus aken\n  Navigate to Settings: Ava seadistuste leht\n  Refresh: Värskenda meediavoo andmed\n  Focus Secondary Search: Aseta fookus teisele otsinguribale (kui ta on olemas)\n  Captions: Lülita subtiitrid sisse/välja\n  Stats: Näita video statistikat\n  Picture in Picture: Lülita pilt-pildis vaade sisse/välja\n  Large Rewind: Keri videot tagasi 10 sekundit / Keri videot tagasi hetkel kasutatava taasesituskiiruse alusel\n  Play: Esita/peata\n  Mute: Lülita summutamine sisse/välja\n  Decrease Video Speed: Vähenda video kiirust hetkel kasutatava taasesituskiiruse alusel\n  Full Window: Lülita täisekraanivaade sisse/välja\n  Theatre Mode: Lülita teatrivaade sisse/välja\n  Take Screenshot: Tee ekraanitõmmis\n  Minimize Window: Minimeeri aken\n  Close Window: Sulge aken\n  Toggle Developer Tools: Lülita arendaja tarvikud sisse/välja\n  Reset Zoom: Lähtesta suumitase / kasutajaliidese mõõtkava\n  Zoom Out: Suumi välja\n  Focus Search: Aseta fookus otsinguribale\n  Search in New Window: Otsi uues aknas\n  Last Frame: Eelmine kaader (kui video on peatatud)\n  Next Frame: Järgmine kaader (kui video on peatatud)\n  Volume Up: Keera heli valjemaks\n  Small Rewind: Keri tagasi X sekundit hetkel kasutatava kerimiskiiruse ja taasesituskiiruse alusel\n  Last Chapter: Viimane peatükk\n  Next Chapter: Järgmine peatükk\n  Skip by Tenths: Kalpsa läbi video protsendisammudega (3 kalpsab 30% kestuseni)\n  Navigate to History: Ava ajaloo leht\n  Fullscreen: Lülita täisekraan sisse/välja\n  Large Fast Forward: Keri videot edasi 10 sekundit / Keri videot edasi hetkel kasutatava taasesituskiiruse alusel\n  Increase Video Speed: Suurenda video kiirust hetkel kasutatava taasesituskiiruse alusel\n  Zoom In: Suumi sisse\n  Volume Down: Keera heli vaiksemaks\n  Small Fast Forward: Keri edasi X sekundit hetkel kasutatava kerimiskiiruse ja taasesituskiiruse alusel\n  End: Keri video lõppu\n  Home: Keri video algusesse\n  Skip to Next Video: Hüppa esitusloendi järgmise video või järgmise soovituse juurde\n  Skip to Previous Video: Hüppa esitusloendi eelmise video juurde\nshortcutLabelSeparator: ｜\nCompact side navigation: Näita külgpaani kompaktsena\nExpand side navigation: Näita külgpaani avatuna\n"
  },
  {
    "path": "static/locales/eu.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Euskara'\n\n# Webkit Menu Bar\nFile: 'Fitxategia'\nQuit: 'Irten'\nEdit: 'Editatu'\nUndo: 'Desegin'\nRedo: 'Berregin'\nCut: 'Moztu'\nCopy: 'Kopiatu'\nPaste: 'Itsatsi'\nDelete: 'Ezabatu'\nSelect all: 'Hautatu guztia'\nToggle Developer Tools: 'Erakutsi/Ezkutatu garatzaile-tresnak'\nActual size: 'Uneko tamaina'\nZoom in: 'Handiagotu'\nZoom out: 'Txikiagotu'\nToggle fullscreen: 'Aldatu pantaila osora'\nWindow: 'Leihoa'\nMinimize: 'Minimizatu'\nClose: 'Itxi'\nBack: 'Atzera'\nForward: 'Aurrera'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Bideoak'\n\n  Counts:\n    Subscriber Count: Harpidedun 1 | {count} harpidedun\n    Watching Count: Ikusle 1 | {count} ikusle\n    Channel Count: Kanal 1 ! {count} kanal\n    Video Count: Bideo 1 | {count} bideo\n    View Count: Ikustaldi 1 | {count} ikustaldi\n    Like Count: Atsegite 1 | {count} atsegite\n    Comment Count: Iruzkin 1 | {count} iruzkin\n  Live: Zuzenean\n  Shorts: Laburrak\n  Posts: Argitalpenak\n  Sort By: Ordenatu honen arabera\nVersion {versionNumber} is now available!  Click for more details: '{versionNumber} bertsioa erabilgarri! Klikatu azalpen gehiagorako'\nDownload From Site: 'Jaitsi webgunetik'\nA new blog is now available, {blogTitle}. Click to view more: 'Blog berri bat erabilgarri dago, {blogTitle}. Klikatu gehiagorako'\n\n# Search Bar\nSearch / Go to URL: 'Bilatu / Joan URLra'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Bilaketa iragazkiak'\n  Sort By:\n    Most Relevant: 'Garrantzitsuenak'\n    Rating: 'Balorazioa'\n    Upload Date: 'Igoera-data'\n    View Count: 'Ikustaldi kopurua'\n  Time:\n    Time: 'Denbora'\n    Any Time: 'Edozein unekoa'\n    Last Hour: 'Azken ordukoa'\n    Today: 'Gaur'\n    This Week: 'Aste honetan'\n    This Month: 'Hilabete honetan'\n    This Year: 'Aurten'\n  Type:\n    Type: 'Mota'\n    All Types: 'Mota guztietakoak'\n    Videos: 'Bideoak'\n    Channels: 'Kanalak'\n    #& Playlists\n    Movies: Filmak\n  Duration:\n    Duration: 'Iraupena'\n    All Durations: 'Edozein iraupen'\n    Short (< 4 minutes): 'Laburra (<4 minutu)'\n    Long (> 20 minutes): 'Luzea (> 20 minutu)'\n  # On Search Page\n    Medium (4 - 20 minutes): Tartekoa (4 - 20 minutu)\n  Search Results: 'Bilaketa-emaitzak'\n  Fetching results. Please wait: 'Emaitzak ekartzen. Itxaron faborez'\n  Fetch more results: 'Ekarri emaitza gehiago'\n  There are no more results for this search: 'Ez da emaitza gehiagorik bilaketa honentzat'\n# Sidebar\n  Features:\n    Features: Funtzioak\n    HD: HD\n    Subtitles: Azpitituluak\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Zuzenean\n    4K: 4K\n    360 Video: 360 bideoa\n    Location: Kokapena\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Garbitu iragazkiak\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Harpidetzak'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Profil honek harpidetza anitz ditu. RSSak abiadura muga saihestu dezan behartzen'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Zure harpidetza-zerrenda hutsik dago. Zure harpidetzak inportatu nahi badituzu, Datuen konfigurazioa atalera joan eta Inportaziorako harpidetzak aukera ditzakezu, edo kanal bat bilatu eta harpidetza egin dezakezu.'\n  Load More Videos: 'Kargatu bideo gehiago'\n  Error Channels: Akatsak dituzten kanalak\n  Disabled Automatic Fetching: Harpidetza-bilaketa automatikoa desgaitu duzu. Freskatu harpidetzak hemen ikusteko.\n  Empty Channels: Harpidetutako kanalek ez dute bideorik.\n  Empty Posts: Harpidetutako kanalek ez dute argitalpenik.\n  Load More Posts: Kargatu mezu gehiago\n  Subscriptions Tabs: Harpidetzen fitxak\n  All Subscription Tabs Hidden: Harpidetza fitxa guztiak ezkutatuta daude. Hemen edukia ikusteko, erakutsi fitxa batzuk \"{subsection}\" ataleko \"{settingsSection}\"-ean.\nMore: 'Gehiago'\nTrending:\n  Trending: 'Joerak'\n  Gaming: Jokoak\n  Trending Tabs: Joeren fitxak\n  Sports: Kirolak\nMost Popular: 'Ikusienak'\nPlaylists: 'Erreprodukzio-zerrendak'\nUser Playlists:\n  Your Playlists: 'Zure erreprodukzio-zerrendak'\n  Search bar placeholder: Bilatu erreprodukzio-zerrendak\n  Empty Search Message: Erreprodukzio-zerrenda honetan ez dago zure bilaketarekin bat datorren bideorik\n  Remove Watched Videos: Kendu ikusitako bideoak\n  You have no playlists. Click on the create new playlist button to create a new one.: Ez duzu erreprodukzio-zerrendarik. Egin klik sortu erreprodukzio-zerrenda berria botoian berri bat sortzeko.\n  This playlist currently has no videos.: Erreprodukzio-zerrenda honek ez du bideorik.\n  Create New Playlist: Sortu erreprodukzio-zerrenda berria\n  Add to Playlist: Gehitu erreprodukzio-zerrendara\n  Add to Favorites: Gehitu {playlistName} zerrendara\n  Remove from Favorites: Kendu {playlistName} zerrendatik\n  Move Video Up: Mugitu bideoa gora\n  Move Video Down: Mugitu bideoa behera\n  Remove from Playlist: Kendu erreprodukzio-zerrendatik\n  Playlist Name: Erreprodukzio-zerrendaren izena\n  Playlist Description: Erreprodukzio-zerrendaren deskribapena\n  Save Changes: Gorde aldaketak\n  Cancel: Utzi\n  Edit Playlist Info: Editatu erreprodukzio-zerrendaren informazioa\n  Copy Playlist: Kopiatu erreprodukzio-zerrenda\n  CreatePlaylistPrompt:\n    New Playlist Name: Erreprodukzio-zerrendaren izen berria\n    Toast:\n      Playlist {playlistName} has been successfully created.: '{playlistName} erreprodukzio-zerrenda behar bezala sortu da.'\n      There was an issue with creating the playlist.: Arazo bat izan da erreprodukzio-zerrenda sortzean.\n      There is already a playlist with this name. Please pick a different name.: Badago dagoeneko izen honekin erreprodukzio-zerrenda bat. Mesedez, aukeratu beste izen bat.\n    Create: Sortu\n  Enable Quick Bookmark With This Playlist: Gaitu laster-marka azkarra erreprodukzio-zerrenda honekin\n  Sort By:\n    NameDescending: Z-A\n    LatestCreatedFirst: Sorrera-dataren arabera (berriena)\n    EarliestCreatedFirst: Sorrera-dataren arabera (zaharrena)\n    LatestPlayedFirst: Erreprodukzio-dataren arabera (Berriena)\n    EarliestPlayedFirst: Erreprodukzio-dataren arabera (Zaharrena)\n    NameAscending: A-Z\n    EarliestUpdatedFirst: Eguneratze-dataren arabera (Zaharrena)\n    LatestUpdatedFirst: Eguneratze-dataren arabera (Berriena)\n  Delete Playlist: Ezabatu erreprodukzio-zerrenda\n  Are you sure you want to delete this playlist? This cannot be undone: Ziur erreprodukzio-zerrenda ezabatu nahi duzula? Hau ezin da desegin.\n  SinglePlaylistView:\n    Toast:\n      Playlist has been updated.: Erreprodukzio-zerrenda eguneratu da.\n      \"{videoCount} video(s) have been removed\": Bideo 1 kendu da | {videoCount} bideo kendu dira\n      This video cannot be moved up.: Bideo hau ezin da gora eraman.\n      This video cannot be moved down.: Bideoa ezin da behera eraman.\n      Video has been removed: Bideoa kendu da\n      There was a problem with removing this video: Arazo bat izan da bideoa kentzean\n      This playlist is now used for quick bookmark: Erreprodukzio-zerrenda hau laster-markak egiteko erabiltzen da orain\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Erreprodukzio-zerrenda hau laster-marketarako erabiltzen da orain {oldPlaylistName} zerrendaren ordez. Egin klik hemen desegiteko\n      Reverted to use {oldPlaylistName} for quick bookmark: '{oldPlaylistName} erabili da berriro azkar markatzeko'\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Erreprodukzio-zerrendako bideo batzuk oraindik ez dira kargatu. Egin klik hemen kopiatzeko hala ere.\n      Playlist name cannot be empty. Please input a name.: Erreprodukzio-zerrendaren izena ezin da hutsik egon. Mesedez, idatzi izena.\n      There was an issue with updating this playlist.: Arazo bat izan da erreprodukzio-zerrenda eguneratzean.\n      There were no videos to remove.: Ez zegoen kentzeko bideorik.\n      This playlist is protected and cannot be removed.: Erreprodukzio-zerrenda hau babestuta dago eta ezin da kendu.\n      Playlist {playlistName} has been deleted.: '{playlistName} erreprodukzio-zerrenda ezabatu da.'\n      This playlist does not exist: Erreprodukzio-zerrenda hau ez da existitzen\n      This playlist is already being used for quick bookmark.: Erreprodukzio-zerrenda hau laster-markak egiteko erabiltzen ari da dagoeneko.\n      This playlist has a video with a duration error: Erreprodukzio-zerrenda honek iraupenik ez duen bideo bat du gutxienez. Hortaz, zero balitz bezala sailkatuko da.\n      Video has been removed. Click here to undo.: Bideoa kendu da. Egin klik hemen desegiteko.\n    Search for Videos: Bilatu bideoak\n  AddVideoPrompt:\n    Added {count} Times: Jadanik | {count} aldiz gehitu da\n    Toast:\n      You haven't selected any playlist yet.: Oraindik ez duzu erreprodukzio-zerrendarik hautatu.\n      \"Video(s) added to {playlistCount} playlists\": \"Bideoa(k) erreprodukzio-zerrenda 1era gehitu da | Bideoa(k) {playlistCount} erreprodukzio-zerrendetara gehitu da\"\n    Select a playlist to add your N videos to: Hautatu erreprodukzio-zerrenda zure bideoa bertara gehitzeko | Hautatu erreprodukzio-zerrenda zure {videoCount} bideo bertara gehitzeko\n    N playlists selected: '{playlistCount} hautatuta'\n    Search in Playlists: Bilatu erreprodukzio-zerrendetan\n    Save: Gorde\n    Allow Adding Duplicate Video(s): Baimendu bideo bikoiztuak gehitzea\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} bideo gehituko dira'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} gehitu dira'\n  Playlists with Matching Videos: Bat datozen bideoak dituzten erreprodukzio-zerrendak\n  Remove Duplicate Videos: Kendu bideo bikoiztuak\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Ziur bikoiztutako bideo bat erreprodukzio-zerrenda honetatik kendu nahi duzula? Hau ezin da desegin. | Ziur {playlistItemCount} bideo bikoiztu erreprodukzio-zerrenda honetatik kendu nahi dituzula? Hau ezin da desegin.\n  Quick Bookmark Enabled: Laster-marka azkarra gaituta\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Ziur ikusitako bideo bat erreprodukzio-zerrenda honetatik kendu nahi duzula? Hau ezin da desegin. | Ziur ikusitako {playlistItemCount} bideo erreprodukzio-zerrenda honetatik kendu nahi dituzula? Hau ezin da desegin.\n  Cannot delete the quick bookmark target playlist.: Ezin da laster-marken helburuko erreprodukzio-zerrenda azkarra ezabatu.\n  Export Playlist: Esportatu erreprodukzio-zerrenda hau\n  The playlist has been successfully exported: Erreprodukzio-zerrenda ongi esportatu da\n  TotalTimePlaylist: 'Denbora guztira: {duration}'\n  Export list of URLs: Esportatu URLen zerrenda\nHistory:\n  # On History Page\n  History: 'Historikoa'\n  Watch History: 'Historikoa ikusi'\n  Your history list is currently empty.: 'Zure historia-zerrenda hutsik dago une honetan.'\n  Empty Search Message: Ez dago historikoan zure bilaketarekin bat datorren bideorik\n  Search bar placeholder: Bilatu historikoan\n  Case Sensitive Search: Maiuskulak eta minuskulak bereizten ditu\n  DateOldestHistory: Ikuste-dataren arabera (Zaharrena)\n  DateNewestHistory: Ikuste-dataren arabera (Berriena)\nSettings:\n  # On Settings Page\n  Settings: 'Ezarpenak'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Aplikazioa berrabiarazi behar da aldaketek eragina izan dezaten. Berrabiarazi eta aldaketa aplikatu?'\n  General Settings:\n    General Settings: 'Orokorra'\n    Check for Updates: 'Bilatu eguneraketak'\n    Check for Latest Blog Posts: 'Egiaztatu blogeko azken argitalpenak'\n    Fallback to Non-Preferred Backend on Failure: 'Hutsegitean, joan hobetsi gabeko motorrera'\n    Enable Search Suggestions: 'Gaitu bilaketa-iradokizunak'\n    Default Landing Page: 'Lehenetsitako hasierako orria'\n    Locale Preference: 'Tokiko hobespena'\n    Preferred API Backend:\n      Preferred API Backend: 'API motor hobetsia'\n      Local API: 'Tokiko APIa'\n      Invidious API: 'Invidious APIa'\n    Video View Type:\n      Video View Type: 'Bideo-ikuspegi mota'\n      Grid: 'Sareta'\n      List: 'Zerrenda'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatura-hobespena'\n      Default: 'Lehenetsia'\n      Beginning: 'Hasiera'\n      Middle: 'Erdia'\n      End: 'Bukaera'\n      Hidden: Ezkutatuta\n      Blur: Lausotzea\n    View all Invidious instance information: 'Ikusi Invidious instantzia guztien informazioa'\n    Region for Trending: 'Joeren eskualdea'\n        #! List countries\n    The currently set default instance is {instance}: 'Une honetan ezarritako instantzia lehenetsia {instance} da'\n    Current Invidious Instance: Oraingo Invidious instantzia\n    External Link Handling:\n      External Link Handling: Kanpo esteken kudeaketa\n      Open Link: Ireki esteka\n      Ask Before Opening Link: Galdetu esteka ireki aurretik\n      No Action: Ekintzarik ez\n    Set Current Instance as Default: Ezarri uneko instantzia lehenetsi gisa\n    System Default: Sistemak lehenetsitakoa\n    No default instance has been set: Ez da instantzia lehenetsirik ezarri\n    Current instance will be randomized on startup: Uneko instantzia ausaz banatuko da abiaraztean\n    Clear Default Instance: Garbitu lehenetsitako instantzia\n    Auto Load Next Page:\n      Tooltip: Kargatu orri eta iruzkin gehigarriak automatikoki.\n      Label: Kargatu automatikoki hurrengo orria\n    Open Deep Links In New Window: Ireki FreeTubera pasatu diren URLak leiho berri batean\n    Minimize to system tray: Minimizatu sistemaren erretiluan\n  Theme Settings:\n    Theme Settings: 'Gaia'\n    Match Top Bar with Main Color: 'Lotu goiko barra kolore nagusiarekin'\n    Expand Side Bar by Default: 'Zabaldu alboko barra lehenespenez'\n    Disable Smooth Scrolling: 'Desgaitu korritze leuna'\n    UI Scale: 'Erabiltzaile interfazearen eskala'\n    Base Theme:\n      Base Theme: 'Oinarrizko gaia'\n      Black: 'Beltza'\n      Dark: 'Iluna'\n      Light: 'Argia'\n      Dracula: Drakula\n      System Default: Sistemak lehenetsia\n      Catppuccin Mocha: Kaputxino Moka\n      Nordic: Nordikoa\n      Pastel Pink: Pastel arrosa\n      Hot Pink: Arrosa beroa\n      Solarized Dark: Solarizatu iluna\n      Solarized Light: Solarizatu argia\n      Gruvbox Dark: Gruvbox iluna\n      Gruvbox Light: Gruvbox argia\n      Catppuccin Frappe: Kaputxino Frappe\n      Everforest Dark Medium: Everforest ilun tartekoa\n      Everforest Light Medium: Everforest argi tartekoa\n      Everforest Light Low: Everforest argi arina\n      Everforest Dark Hard: Everforest ilun gogorra\n      Everforest Dark Low: Everforest ilun arina\n      Everforest Light Hard: Everforest argi gogorra\n      Catppuccin Latte: Kaputxino Latte\n    Main Color Theme:\n      Main Color Theme: 'Oinarrizko koloreen gaia'\n      Red: 'Gorria'\n      Pink: 'Arrosa'\n      Purple: 'Ubela'\n      Deep Purple: 'Ubel bizia'\n      Indigo: 'Indigo kolorea'\n      Blue: 'Urdina'\n      Light Blue: 'Urdin argia'\n      Cyan: 'Ziana'\n      Teal: 'Berde-urdina'\n      Green: 'Berdea'\n      Light Green: 'Berde argia'\n      Lime: 'Lima'\n      Yellow: 'Horia'\n      Amber: 'Anbar-kolorekoa'\n      Orange: 'Laranja'\n      Deep Orange: 'Laranja bizia'\n      Dracula Pink: Drakula larrosa\n      Dracula Cyan: Drakula ziana\n      Dracula Orange: Drakula laranja\n      Dracula Purple: Drakula ubela\n      Dracula Red: Drakula gorria\n      Dracula Green: Drakula berdea\n      Dracula Yellow: Drakula horia\n      Catppuccin Mocha Flamingo: Kaputxino Moka flamingoa\n      Catppuccin Mocha Pink: Kaputxino Moka arrosa\n      Catppuccin Mocha Sapphire: Kaputxino Moka zafiroa\n      Catppuccin Mocha Lavender: Kaputxino Moka izpilikua\n      Catppuccin Mocha Blue: Kaputxino Moka urdina\n      Catppuccin Mocha Rosewater: Kaputxino Moka urlarrosa\n      Catppuccin Mocha Mauve: Kaputxino Moka ubela\n      Catppuccin Mocha Red: Kaputxino Moka gorria\n      Catppuccin Mocha Maroon: Kaputxino Moka marroia\n      Catppuccin Mocha Peach: Kaputxino Moka mertxika\n      Catppuccin Mocha Yellow: Kaputxino Moka horia\n      Catppuccin Mocha Green: Kaputxino Moka berdea\n      Catppuccin Mocha Teal: Kaputxino Moka berde-urdinxka\n      Catppuccin Mocha Sky: Kaputxino Moka zerua\n      Solarized Yellow: Hori solarizatua\n      Solarized Orange: Laranja solarizatua\n      Solarized Red: Gorri solarizatua\n      Solarized Magenta: Magenta solarizatua\n      Solarized Blue: Urdin solarizatua\n      Solarized Cyan: Zian solarizatua\n      Solarized Violet: Violeta solarizatua\n      Solarized Green: Berde solarizatua\n      Gruvbox Dark Yellow: Gruvbox hori Iluna\n      Gruvbox Dark Purple: Gruvbox ubel Iluna\n      Gruvbox Dark Orange: Gruvbox laranja Iluna\n      Gruvbox Light Red: Gruvbox gorri argia\n      Gruvbox Light Blue: Gruvbox urdin argia\n      Gruvbox Light Orange: Gruvbox laranja argia\n      Gruvbox Dark Aqua: Gruvbox Aqua Iluna\n      Gruvbox Light Purple: Gruvbox ubel argia\n      Gruvbox Dark Blue: Gruvbox urdin Iluna\n      Gruvbox Dark Green: Gruvbox berde Iluna\n      Catppuccin Frappe Flamingo: Kaputxino Frappe flamingoa\n      Catppuccin Frappe Red: Kaputxino Frappe gorria\n      Catppuccin Frappe Peach: Kaputxino Frappe mertxika\n      Catppuccin Frappe Green: Kaputxino Frappe berdea\n      Catppuccin Frappe Teal: Kaputxino Frappe berde-urdinxka\n      Catppuccin Frappe Sky: Kaputxino Frappe zerua\n      Catppuccin Frappe Sapphire: Kaputxino Frappe zafiroa\n      Catppuccin Frappe Blue: Kaputxino Frappe urdina\n      Catppuccin Frappe Lavender: Kaputxino Frappe izpilikua\n      Catppuccin Frappe Rosewater: Kaputxino Frappe urlarrosa\n      Catppuccin Frappe Mauve: Kaputxino Frappe ubela\n      Catppuccin Frappe Pink: Kaputxino Frappe larrosa\n      Catppuccin Frappe Maroon: Kaputxino Frappe marroia\n      Catppuccin Frappe Yellow: Kaputxino Frappe horia\n      Everforest Dark Red: Everforest ilun gorria\n      Everforest Dark Orange: Everforest ilun laranja\n      Everforest Dark Yellow: Everforest ilun horia\n      Everforest Dark Green: Everforest ilun berdea\n      Everforest Dark Aqua: Everforest ilun aqua\n      Everforest Dark Blue: Everforest ilun urdina\n      Everforest Dark Purple: Everforest ilun morea\n      Everforest Light Red: Everforest argi gorria\n      Everforest Light Orange: Everforest argi laranja\n      Everforest Light Green: Everforest argi berdea\n      Everforest Light Aqua: Everforest argi aqua\n      Everforest Light Blue: Everforest argi urdina\n      Everforest Light Purple: Everforest argi ubela\n      Everforest Light Yellow: Everforest argi horia\n      Catppuccin Latte Mauve: Kaputxino Latte malba\n      Catppuccin Latte Red: Kaputxino Latte gorria\n    Secondary Color Theme: 'Gaiaren bigarren mailako kolorea'\n        #* Main Color Theme\n    Hide Side Bar Labels: Ezkutatu alboko barraren etiketak\n    Hide FreeTube Header Logo: Ezkutatu FreeTube goiburuko logotipoa\n  Player Settings:\n    Player Settings: 'Erreproduzitzailea'\n    Play Next Video: 'Automatikoki erreproduzitu gomendatutako bideoak'\n    Turn on Subtitles by Default: 'Gaitu azpitituluak lehenespenez'\n    Autoplay Videos: 'Hasi bideoak erreproduzitzen automatikoki'\n    Proxy Videos Through Invidious: 'Erabili Invidious proxy gisa'\n    Autoplay Playlists: 'Automatikoki erreproduzitu erreprodukzio-zerrendak'\n    Enable Theatre Mode by Default: 'Gaitu antzerki modua lehenespenez'\n    Default Volume: 'Lehenetsitako bolumena'\n    Default Playback Rate: 'Lehenetsitako erreprodukzio-tasa'\n    Default Video Format:\n      Default Video Format: 'Lehenetsitako bideo-formatua'\n      Dash Formats: 'DASH formatuak'\n      Legacy Formats: 'Formatu zaharrak'\n      Audio Formats: 'Audio-formatuak'\n    Default Quality:\n      Default Quality: 'Lehenetsitako kalitatea'\n      Auto: 'Automatikoa'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: Aurrera / atzera egiteko tartea\n    Scroll Volume Over Video Player: Aldatu bolumena bideo-erreproduzitzailean\n    Next Video Interval: Automatikoki erreproduzitzeko tenporizadorea\n    Screenshot:\n      Enable: Gaitu pantaila-argazkia\n      Error:\n        Empty File Name: Fitxategi izena hutsik\n        Forbidden Characters: Debekatutako karaktereak\n      Format Label: Pantaila-argazkiaren formatua\n      Quality Label: Pantaila-argazkiaren kalitatea\n      Ask Path: Galdetu zein karpetan gordeko den\n      Folder Label: Pantaila-argazkien karpeta\n      Folder Button: Hautatu karpeta\n      File Name Label: Fitxategi-izenen eredua\n      File Name Tooltip: Hurrengo aldagaiak balia ditzakezu. %U Urtea 4 digitu. %H Hilabetea 2 digitu. %E Eguna 2 digitu. %O Ordua 2 digitu. %M Minutu 2 digitu. %S segundo 2 digitu. %T milisegundo 3 digitu. %s Bideoaren segundoa. %t Bideoaren milisegundoa 3 digitu. %i Bideoaren Identifikatzailea.\n    Scroll Playback Rate Over Video Player: Aldatu erreprodukzio-tasa bideo-erreproduzitzailean\n    Display Play Button In Video Player: Bistaratu erreproduzitzeko botoia bideo-erreproduzitzailean\n    Max Video Playback Rate: Bideoen gehieneko erreprodukzio-tasa\n    Video Playback Rate Interval: Bideoen erreprodukzio-tasaren tartea\n    Skip by Scrolling Over Video Player: Saltatu bideo-erreproduzitzailean korrituz\n    Enter Fullscreen on Display Rotate: Sartu pantaila osoan pantaila biratzean\n    Autoplay Interruption Timer: Erreprodukzio automatikoa eteteko tenporizadorea\n    Default Viewing Mode:\n      Default Viewing Mode: Ikusteko modu lehenetsia\n      Full Screen: Pantaila osoa\n      Picture in Picture: Irudiz irudi\n      External Player: Kanpoko erreproduzitzailea ({externalPlayerName})\n      Theater: Antzokia\n  Privacy Settings:\n    Privacy Settings: 'Pribatutasuna'\n    Remember History: 'Gogoratu ikusitakoaren historikoa'\n    Save Watched Progress: 'Gorde ikusitakoaren aurrerapena'\n    Clear Search Cache: 'Bilaketen cachea ezabatu'\n    Are you sure you want to clear out your search cache?: 'Ziur al zaude bilaketa-cachea garbitu nahi duzula?'\n    Search cache has been cleared: 'Bilaketa cachea ezabatu berri da'\n    Remove Watch History: 'Ezabatu ikusitakoaren historikoa'\n    Are you sure you want to remove your entire watch history?: 'Ziur al zaude ikusitakoaren historiko osoa ezabatu nahi duzula?'\n    Watch history has been cleared: 'Ikusitakoaren historikoa ezabatu berri da'\n    Remove All Subscriptions / Profiles: 'Kendu harpidetza / profil guztiak'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Ziur al zaude zure profil eta harpidetza guztiak ezabatu nahi dituzula? Ezingo duzu atzera egin.'\n    All playlists have been removed: Erreprodukzio-zerrenda guztiak kendu dira\n    Save Watched Videos With Last Viewed Playlist: Gorde ikusitako bideoak ikusitako azken erreprodukzio-zerrendarekin\n    Remove All Playlists: Kendu erreprodukzio-zerrenda guztiak\n    Are you sure you want to remove all your playlists?: Ziur erreprodukzio-zerrenda guztiak kendu nahi dituzula?\n    Clear Search History and Cache: Garbitu bilaketen historikoa eta cache-a\n    Remember Search History: Gogoratu bilatutakoaren historikoa\n    Are you sure you want to clear out your search history and cache?: Ziur al zaude bilaketen historikoa eta cache-a garbitu nahi dituzula?\n    Search history and cache have been cleared: Bilaketen historikoa eta cache-a garbitu berri dira\n    Watched Progress Saving Mode:\n      Modes:\n        Semi-auto: Semi-automatikoa\n        Auto: Automatikoa\n        Never: Inoiz ez\n      Tooltip: Automatikoa = Gorde bideo-orriaren irteera guztietan, bideoa amaitzen denean eta errorea aurkitu denean (adibidez, tasa mugatua eta ikusi-saioa iraungi zenean). Erdi automatikoa = Auto bezala bideo-orriaren irteeran izan ezik, eta aurrerapena eskuz gorde dezakezu Gorde ikusitako aurrerapena izeneko botoi baten bidez, bideo erreproduzitzailearen azpian dagoena.\n  Subscription Settings:\n    Subscription Settings: 'Harpidetza'\n    Fetch Feeds from RSS: 'Eskuratu RSS jarioak'\n    Fetch Automatically: Eskuratu jarioa automatikoki\n    Confirm Before Unsubscribing: Berretsi harpidetza kendu baino lehen\n    'Limit the number of videos displayed for each channel': Mugatu kanal bakoitzeko bistaratzen den bideo kopurua\n    To: Hona\n  Distraction Free Settings:\n    Distraction Free Settings: 'Arreta-galerarik gabea'\n    Hide Video Views: 'Ezkutatu bideoen ikustaldi kopurua'\n    Hide Video Likes And Dislikes: 'Ezkutatu bideoen atsegiteak eta desatsegiteak'\n    Hide Channel Subscribers: 'Ezkutatu kanalaren harpidedun kopurua'\n    Hide Comment Likes: 'Ezkutatu iruzkinen atsegiteak'\n    Hide Recommended Videos: 'Ezkutatu gomendatutako bideoak'\n    Hide Trending Videos: 'Ezkutatu bideo ikusienak'\n    Hide Popular Videos: 'Ezkutatu bideo ospetsuak'\n    Hide Playlists: 'Ezkutatu erreprodukzio-zerrendak'\n    Hide Live Chat: 'Ezkutatu zuzeneko txata'\n    Hide Active Subscriptions: 'Ezkutatu harpidetza aktiboak'\n    Hide Sharing Actions: Ezkutatu partekatze-ekintzak\n    Hide Videos on Watch: 'Ezkutatu ikusten ari zaren bideoak'\n    Hide Video Description: Ezkutatu bideoaren deskribapena\n    Hide Comments: Ezkutatu iruzkinak\n    Hide Live Streams: Ezkutatu zuzeneko emanaldiak\n    Sections:\n      Side Bar: Alboko barra\n      Subscriptions Page: Harpidetzen orria\n      Channel Page: Kanalaren orria\n      General: Orokorra\n      Watch Page: Ikusien orria\n    Hide Profile Pictures in Comments: Ezkutatu profileko argazkiak iruzkinetan\n    Display Titles Without Excessive Capitalisation: Bistaratu izenburuak gehiegizko letra larriz eta puntuaziorik gabe\n    Hide Channels Placeholder: Kanalaren IDa\n    Hide Channel Playlists: Ezkutatu kanaleko \"erreprodukzio-zerrendak\" fitxa\n    Hide Channel Podcasts: Ezkutatu kanaleko \"podcastak\" fitxa\n    Hide Videos, Playlists and Channels Containing Text: Ezkutatu testua duten bideoak eta erreprodukzio-zerrendak\n    Hide Channels: Ezkutatu bideoak kanaletatik\n    Hide Upcoming Premieres: Ezkutatu datozen estreinaldiak\n    Hide Subscriptions Videos: Ezkutatu harpidetza-bideoak\n    Hide Subscriptions Shorts: Ezkutatu bideo laburren harpidetzak\n    Hide Channel Releases: Ezkutatu kanalen \"Argitalpenak\" fitxa\n    Hide Chapters: Ezkutatu kapituluak\n    Hide Channels Invalid: Emandako kanalaren IDa baliogabea da\n    Hide Channels API Error: Errore bat gertatu da emandako IDa duen erabiltzailea berreskuratzean. Mesedez, egiaztatu berriro IDa zuzena den.\n    Hide Channels Already Exists: Kanalaren IDa badago jada\n    Hide Channel Shorts: Ezkutatu kanalaren \"bideo laburrak\" fitxa\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Hitza, hitz-zatia edo esaldia\n    Hide Subscriptions Live: Ezkutatu zuzenekoen harpidetzak\n    Hide Featured Channels: Ezkutatu nabarmendutako kanalak\n    Hide Channels Disabled Message: Kanal batzuk IDa erabiliz blokeatu dira eta ez dira prozesatu. Eginbidea blokeatuta dago ID horiek eguneratzen ari diren bitartean\n    Hide Channel Home: Ezkutatu kanala \"Hasierako\" fitxa\n    Show Added Items: Erakutsi gehitutako elementuak\n    Hide Channel Courses: Ezkutatu kanala \"Ikastaroak\" fitxa\n    Hide Channel Posts: Ezkutatu kanalaren \"Argitalpenak\" fitxa\n    Hide Subscriptions Posts: Ezkutatu harpidetza-argitalpenak\n  Data Settings:\n    Data Settings: 'Datuak'\n    Select Export Type: 'Hautatu esportazio mota'\n    Import Subscriptions: 'Inportatu harpidetzak'\n    Export Subscriptions: 'Esportatu harpidetzak'\n    Export FreeTube: 'Esportatu Freetube'\n    Export YouTube: 'Esportatu Youtube'\n    Export NewPipe: 'Esportatu Newpipe'\n    Import History: 'Inportatu historikoa'\n    Export History: 'Esportatu historikoa'\n    Profile object has insufficient data, skipping item: 'Profil-objektuak ez du datu nahikorik, elementua saltatzen'\n    All subscriptions and profiles have been successfully imported: 'Profil eta harpidetza guztiak ongi inportatu dira'\n    All subscriptions have been successfully imported: 'Harpidetza guztiak ongi inportatu dira'\n    Invalid subscriptions file: 'Harpidetzen fitxategi baliogabea'\n    Invalid history file: 'Historikoaren fitxategi baliogabea'\n    Subscriptions have been successfully exported: 'Harpidetzak ongi esportatu dira'\n    History object has insufficient data, skipping item: 'Historiako objektuak ez du datu nahikorik, elementua saltatzen'\n    All watched history has been successfully imported: 'Ikusitakoaren historikoa ongi inportatu da'\n    All watched history has been successfully exported: 'Ikusitakoaren historikoa ongi esportatu da'\n    Unable to read file: 'Ezin da fitxategia irakurri'\n    Unable to write file: 'Ezin da fitxategia idatzi'\n    Unknown data key: 'Datu-gako ezezaguna'\n    How do I import my subscriptions?: 'Nola inporta ditzaket nire harpidetzak?'\n    Manage Subscriptions: 'Kudeatu harpidetzak'\n    Import Playlists: Inportatu erreprodukzio-zerrendak\n    Export Playlists: Esportatu erreprodukzio-zerrendak\n    All playlists has been successfully imported: Erreprodukzio-zerrenda guztiak ongi inportatu dira\n    All playlists has been successfully exported: Erreprodukzio-zerrenda guztiak ongi esportatu dira\n    Playlist insufficient data: Ez dago datu nahikorik \"{playlist}\" erreprodukzio-zerrendarentzat, elementua saltatzen\n    History File: Historikoaren fitxategia\n    Playlist File: Erreprodukzio-zerrendaren fitxategia\n    Export Playlists For Older FreeTube Versions:\n      Label: Esportatu erreprodukzio zerrendak FreeTube bertsio zaharretarako\n      Tooltip: \"Aukera honek erreprodukzio-zerrenda guztietako bideoak \\\"Gogokoak\\\" izeneko erreprodukzio-zerrenda batera esportatzen ditu.\\nNola esportatu eta inportatu bideoak erreprodukzio-zerrendetan FreeTube-ren bertsio zaharrago baterako:\\n 1. Esportatu zure erreprodukzio zerrendak aukera hau gaituta.\\n 2. Ezabatu lehendik dituzun erreprodukzio-zerrenda guztiak Pribatutasun-ezarpenetan dagoen Kendu zerrenda guztiak aukera erabiliz.\\n 3. Abiarazi FreeTube-ren bertsio zaharra eta inportatu esportatutako erreprodukzio-zerrendak.\\\"\"\n    Subscription File: Harpidetza-fitxategia\n    Search history file: Bilaketa-historiaren fitxategia\n    Search history: Bilaketa-historia\n    Import search history: Inportatu bilaketa-historia\n    Export search history: Esportatu bilaketa-historia\n    All search history has been successfully imported: Bilaketa-historia guztia behar bezala inportatu da\n    All search history has been successfully exported: Bilaketa-historia guztia behar bezala esportatu da\n  Proxy Settings:\n    Proxy Settings: 'Proxy-a'\n    Enable Tor / Proxy: 'Gaitu Tor / Proxy-a'\n    Proxy Protocol: 'Proxy protokoloa'\n    Proxy Host: 'Proxy ostalaria'\n    Proxy Port Number: 'Proxy-aren ataka-zenbakia'\n    Clicking on Test Proxy will send a request to: 'Test Proxy-n klik eginez gero, eskaera bat bidaliko da'\n    Test Proxy: 'Probatu proxy-a'\n    Your Info: 'Zure informazioa'\n    Ip: 'Ip'\n    Country: 'Herrialdea'\n    Region: 'Eskualdea'\n    City: 'Hiria'\n    Error getting network information. Is your proxy configured properly?: 'Errore bat gertatu da sareko informazioa eskuratzean. Zure proxy-a behar bezala konfiguratuta al dago?'\n    Proxy Warning: FreeTubek ez du proxy-rik, baina kanpoko proxy batera konekta daiteke, adibidez, zure makinan Tor gisa exekutatzen den bat edo kanpoko proxy bat, VPN batzuek emandako proxy bat bezala. Aktibatuta badago, ziurtatu proxy/Tor behar bezala konfiguratuta dagoela, edo FreeTubek ezingo du daturik lortu.\n    Proxy Username: Proxy-aren erabiltzailea\n    Proxy Password: Proxy-aren pasahitza\n  External Player Settings:\n    Ignore Unsupported Action Warnings: Ez ikusiarena egin onartu gabeko ekintzen abisuei\n    External Player Settings: Kanpoko erreproduzitzailea\n    External Player: Kanpoko erreproduzitzailea\n    Custom External Player Executable: Lehenetsitako kanpo-erreproduzitzailearen exekutagarria\n    Custom External Player Arguments: Lehenetsitako kanpo-erreproduzitzailearen argumentuak\n    Ignore Default Arguments: Ez ikusiarena egin lehenetsitako argumentuei\n    Players:\n      None:\n        Name: Bat ere ez\n  SponsorBlock Settings:\n    Skip Options:\n      Prompt To Skip: Saltatzeko abisua\n      Show In Seek Bar: Erakutsi bilaketa-barran\n      Do Nothing: Ez egin ezer\n      Skip Option: Saltatu aukera\n      Auto Skip: Saltatze automatikoa\n    Category Color: Kategoriaren kolorea\n    Notify when sponsor segment is skipped: Jakinarazi babesleen segmentua saltatzen denean\n    Enable SponsorBlock: Gaitu babesleak blokeatzea\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Babesleak blokeatzeko API Url (lehenetsia https://sponsor.ajay.app da)\n    SponsorBlock Settings: Babesleak blokeatu\n    UseDeArrowTitles: Erabili DeArrow bideo-izenburuak\n    UseDeArrowThumbnails: Erabili DeArrow irudi txikietarako\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Thumbnail Generator API URLa (lehenetsia https://dearrow-thumb.ajay.app da)\n  Parental Control Settings:\n    Show Family Friendly Only: Erakutsi familientzat aproposa dena bakarrik\n    Hide Unsubscribe Button: Ezkutatu harpidetza kentzeko botoia\n    Parental Control Settings: Gurasoen kontrola\n    Hide Search Bar: Ezkutatu bilaketa-barra\n    Hide Uploader on Watch page: Ezkutatu igotzailea ikusitakoen orrian\n  Password Dialog:\n    Password: Pasahitza\n    Enter Password To Unlock: Sartu pasahitza ezarpenak desblokeatzeko\n  Experimental Settings:\n    Replace HTTP Cache: Ordeztu HTTP cachea\n    Experimental Settings: Esperimentala\n    Warning: Ezarpen hauek esperimentalak dira, aktibatuta dauden bitartean hutsegiteak eragin ditzakete. Oso gomendagarria da babeskopiak egitea. Erabili zure ardurapean!\n  Password Settings:\n    Password Settings: Pasahitza\n    Set Password To Prevent Access: Ezarri pasahitz bat ezarpenetara sarbidea galarazteko\n    Remove Password: Kendu pasahitza\n    Set Password: Ezarri pasahitza\n  Sort Settings Sections (A-Z): Ordenatu ezarpenen atalak (A-Z)\n  Return to Settings Menu: Itzuli ezarpenen menura\nAbout:\n  #On About page\n  About: 'Honi buruz'\n  Beta: 'Beta'\n  Source code: 'Iturburu-kodea'\n  Downloads / Changelog: 'Deskargak / Aldaketen erregistroa'\n  GitHub releases: 'Github-eko argitalpenak'\n  Help: 'Laguntza'\n  FreeTube Wiki: 'Freetuberen wikia'\n  FAQ: 'Ohiko galderak'\n  Report a problem: 'Arazo baten berri eman'\n  GitHub issues: 'Github-en gaiak'\n  Please check for duplicates before posting: 'Mesedez, egiaztatu bikoiztutakoak ote dauden argitaratu aurretik'\n  Website: 'Webgunea'\n  Blog: 'Bloga'\n  Email: 'Posta elektronikoa'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Matrix-en txata'\n  room rules: 'Gelaren arauak'\n  Translate: 'Itzuli'\n  Credits: 'Kredituak'\n  these people and projects: 'Hurrengo pertsonak eta proiektuak'\n  Donate: 'Diruz lagundu'\n\n  Discussions: Eztabaidak\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: '{licenseLink} lizentziapekoa'\n  Please read the {roomRulesLink}: Mesedez, irakurri {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube {creditsPageLink}-ri esker posible da\nProfile:\n  Profile Select: 'Hautatu profila'\n  Profile Filter: 'Profil-iragazkia'\n  All Channels: 'Kanal guztiak'\n  Profile Manager: 'Profil-kudeatzailea'\n  Create New Profile: 'Sortu profil berria'\n  Edit Profile: 'Editatu profila'\n  Color Picker: 'Kolore-hautatzailea'\n  Custom Color: 'Kolore lehenetsia'\n  Profile Preview: 'Profilaren aurreikuspena'\n  Create Profile: 'Sortu profila'\n  Update Profile: 'Eguneratu profila'\n  Make Default Profile: 'Bihurtu profil lehenetsi'\n  Delete Profile: 'Ezabatu profila'\n  Are you sure you want to delete this profile?: 'Ziur al zaude profil hau ezabatu nahi duzula?'\n  All subscriptions will also be deleted.: 'Harpidetza guztiak ere ezabatuko dira.'\n  Your profile name cannot be empty: 'Zure profilaren izena ezin da hutsik egon'\n  Profile has been created: 'Profila ongi sortu da'\n  Profile has been updated: 'Profila ongi eguneratu da'\n  Your default profile has been set to {profile}: 'Zure lehenetsitako profila {profile} gisa ezarri da'\n  Removed {profile} from your profiles: '{profile} ezabatu berri da zure profiletatik'\n  Your default profile has been changed to your primary profile: 'Profil lehenetsia zure profil nagusi gisa ezarri da'\n  '{profile} is now the active profile': '{profile} da profil aktibo berria'\n  Subscription List: 'Harpidetzen zerrenda'\n  Other Channels: 'Beste kanalak'\n  '{number} selected': '{number} hautatu da'\n  Select All: 'Denak hautatu'\n  Select None: 'Bat ere ez hautatu'\n  Delete Selected: 'Ezabatu hautatutakoa'\n  Add Selected To Profile: 'Gehitu hautatutakoa profilera'\n  No channel(s) have been selected: 'Kanal bat ere ez da hautatu'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Hau da zure profil nagusia. Ziur al zaude hautatutako kanalak ezabatu nahi dituzula? Kanal hauek ageri diren profil guztietan ezabatuko dira.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ziur al zaude hautatutako kanalak ezabatu nahi dituzula? Honek ez du kanala beste profil batetik ezabatuko.'\n#On Channel Page\n  Profile Settings: Profila\n  Close Profile Dropdown: Itxi profilen goitibeherakoa\n  Open Profile Dropdown: Ireki profilen goitibeherakoa\n  Toggle Profile List: Aldatu profilen zerrenda\n  Edit Profile Name: Editatu profil-izena\n  Create Profile Name: Sortu profil-izena\n  Profile Name: Profil-izena\nChannel:\n  Subscribe: 'Harpidetu'\n  Unsubscribe: 'Kendu harpidetza'\n  Channel has been removed from your subscriptions: 'Kanala zure harpidetzetatik kendu da'\n  Removed subscription from {count} other channel(s): 'Harpidetza beste {count} kanaletatik ezabatu da'\n  Added channel to your subscriptions: 'Kanala zure harpidetzetara gehitu da'\n  Search Channel: 'Bilatu kanalean'\n  Your search results have returned 0 results: 'Zure bilaketak 0 emaitza lortu ditu'\n  Videos:\n    Videos: 'Bideoak'\n    This channel does not currently have any videos: 'Kanal honek ez du bideorik'\n    Sort Types:\n      Newest: 'Berrienak'\n      Oldest: 'Zaharrenak'\n      Most Popular: 'Jarraituenak'\n  Playlists:\n    Playlists: 'Erreprodukzio-zerrendak'\n    This channel does not currently have any playlists: 'Kanal honek ez du erreprodukzio-zerrendarik'\n    Sort Types:\n      Last Video Added: 'Gehitutako azken bideoak'\n      Newest: 'Berrienak'\n      Oldest: 'Zaharrenak'\n  About:\n    About: 'Honi buruz'\n    Channel Description: 'Kanalaren deskribapena'\n    Featured Channels: 'Nabarmendutako kanalak'\n    Joined: Bat eginda\n    Location: Kokapena\n    Tags:\n      Tags: Etiketak\n      Search for: Bilatu \"{tag}\"\n    Details: Xehetasunak\n  This channel does not exist: Kanal hau ez da existitzen\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Kanal hau adin mugatuta dago eta une honetan ezin da ikusi FreeTuben.\n  Shorts:\n    This channel does not currently have any shorts: Une honetan kanal honek ez du bideo laburrik\n  Releases:\n    This channel does not currently have any releases: Une honetan kanal honek ez du argitalpenik\n    Releases: Argitalpenak\n  Posts:\n    Hide Answers: Ezkutatu erantzunak\n    votes: '{votes} boto'\n    This channel currently does not have any posts: Une honetan kanal honek ez du argitalpenik\n    Reveal Answers: Erakutsi erantzunak\n    Video hidden by FreeTube: FreeTubek ezkutatutako bideoa\n    View Full Post: Ikusi mezu osoa\n    Viewing Posts Only Supported By Invidious: Argitalpenak ikustea Invidious-ek soilik onartzen du. Zoaz kanal baten komunitatearen fitxara bertan edukia ikusteko Invidious gabe.\n  Channel Tabs: Kanalaren fitxak\n  This channel does not allow searching: Kanal honek ez du bilaketarik onartzen\n  Live:\n    Live: Zuzenekoak\n    This channel does not currently have any live streams: Kanal honek ez du zuzeneko erreprodukziorik\n  Podcasts:\n    Podcasts: Podcastak\n    This channel does not currently have any podcasts: Une honetan kanal honek ez du podcastik\n  Home:\n    Home: Menu nagusia\n    View Playlist: Ikusi erreprodukzio-zerrenda\n  Courses:\n    Courses: Ikastaroak\n    This channel does not currently have any courses: Une honetan kanal honek ez du ikastarorik\nVideo:\n  Mark As Watched: 'Ikusitako gisa jarri'\n  Remove From History: 'Ezabatu historikotik'\n  Video has been marked as watched: 'Bideoa ikusia gisa ezarri da'\n  Video has been removed from your history: 'Bideoa zure historikotik ezabatu da'\n  Save Video: 'Gorde bideoa'\n  Video has been saved: 'Bideoa ongi gorde da'\n  Video has been removed from your saved list: 'Bideoa gordetakoen zerrendatik kendu da'\n  Open in YouTube: 'Ireki Youtuben'\n  Copy YouTube Link: 'Kopiatu Youtuberen esteka'\n  Open YouTube Embedded Player: 'Ireki Youtuberen erreproduzitzaile integratua'\n  Copy YouTube Embedded Player Link: 'Kopiatu Youtuberen erreproduzitzaile integratuaren esteka'\n  Open in Invidious: 'Ireki Invidiousen'\n  Copy Invidious Link: 'Kopiatu Invidiousen esteka'\n  Open Channel in YouTube: 'Ireki kanala Youtuben'\n  Copy YouTube Channel Link: 'Kopiatu Youtubeko kanalaren esteka'\n  Open Channel in Invidious: 'Ireki kanala Invidiousen'\n  Copy Invidious Channel Link: 'Kopiatu Invidiouseko kanalaren esteka'\n  Views: 'Ikustaldiak'\n  Loop Playlist: 'Erreprodukzio-zerrenda begiztan'\n  Shuffle Playlist: 'Erreprodukzio-zerrendaren nahastea'\n  Reverse Playlist: 'Erreprodukzio-zerrenda alderantziz'\n  Previous: 'Aurrekoa'\n  Next: 'Hurrengoa'\n  Watched: 'Ikusitakoak'\n  Autoplay: 'Automatikoki ikusi'\n  Starting soon, please refresh the page to check again: 'Laster hasiko da, freskatu orria berriro egiaztatzeko'\n  # As in a Live Video\n  Live: 'Zuzenekoak'\n  Live Now: 'Uneko zuzenekoak'\n  Live Chat: 'Zuzenekoaren txata'\n  Enable Live Chat: 'Gaitu zuzeneko txata'\n  Live Chat is currently not supported in this build.: 'Zuzeneko txata ez da oraindik onartzen konpilazio honetan.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Zuzeneko txata gaituta dago. Txat-mezuak bidalitakoan hemen agertuko dira.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Zuzeneko txata ez da onartzen Invidious APIarekin. Beharrezkoa da  YouTubera zuzenean konektatzea.'\n  Published:\n    In less than a minute: Minutu bat baino gutxiagoan\n  Published on: 'Noiz argitaratua'\n  Streamed on: 'Noiz zuzenean emana'\n  Started streaming on: 'Noiz hasi zen zuzenekoa'\n#& Videos\n  External Player:\n    Unsupported Actions:\n      opening playlists: erreprodukzio-zerrendak irekitzen\n      shuffling playlists: erreprodukzio-zerrendak nahasten\n      setting a playback rate: erreprodukzio-tasa ezartzen\n      reversing playlists: erreprodukzio-zerrendak alderantzizkatzen\n      starting video at offset: bideoa desplazamenduarekin abiarazten\n      opening specific video in a playlist (falling back to opening the video): erreprodukzio zerrenda batean bideoa irekitzen (bideoa berriz ere irekitzen)\n      looping playlists: erreprodukzio-zerrendak begiztan erreproduzitzen\n    OpenInTemplate: 'Ireki {externalPlayer} erreproduzitzailean'\n    video: bideoa\n    OpeningTemplate: '{videoOrPlaylist} irekitzen {externalPlayer}-an...'\n    UnsupportedActionTemplate: '{externalPlayer}-k ez du onartzen: {action}'\n    playlist: erreprodukzio-zerrenda\n  Sponsor Block category:\n    music offtopic: Gaiaz kanpoko musika\n    interaction: Elkarrekintza\n    sponsor: Babeslea\n    outro: Bukaera\n    self-promotion: Autosustapena\n    recap: Laburpena\n    filler: Betegarria\n    intro: Sarrera\n  Hide Channel: Ezkutatu kanala\n  Unhide Channel: Erakutsi kanala\n  Premieres: Estreinaldiak\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Zuzeneko txata ez dago erabilgarri zuzeneko honentzat. Baliteke igo duenak desgaitu izana.\n  Show Super Chat Comment: Erakutsi Super txat iruzkina\n  More Options: Aukera gehiago\n  Upcoming: Datozenak\n  Scroll to Bottom: Joan beheraino\n  Player:\n    Stats:\n      Media Formats: 'Multimedia-formatuak: {formats}'\n      Stats: Estatistikak\n      Video ID: 'Bideoaren IDa: {videoId}'\n      Bandwidth: 'Banda-zabalera: {bandwidth} kbps'\n      Buffered: 'Bufferrean: {bufferedPercentage}%'\n      CodecAudio: 'Kodeka: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Jaregindako fotogramak: {droppedFrames} / Total Frames: {totalFrames}'\n      Volume: 'Bolumena: {volumePercentage}%'\n      CodecsVideoAudio: 'Kodekak: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Resolution: 'Bereizmena: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Erreproduzitzailearen neurriak: {width}x{height}'\n      Bitrate: 'Bit-emaria: {bitrate} kbps'\n      CodecsVideoAudioNoItags: 'Kodekak: {videoCodec} / {audioCodec}'\n    Show Stats: Erakutsi estatistikak\n    Hide Stats: Ezkutatu estatistikak\n    TranslatedCaptionTemplate: '{language} (\"{originalLanguage}\"-tik itzulia)'\n    Audio Tracks: Audio-pistak\n    Theatre Mode: Antzoki modua\n    Exit Theatre Mode: Irten antzoki modutik\n    Exit Full Window: Irten pantaila osotik\n    Take Screenshot: Egin pantaila-argazkia\n    Skipped segment: '{segmentCategory} segmentua saltatu da'\n    You appear to be offline: Lineaz kanpo zaudela dirudi.\n    Playback will resume automatically when your connection comes back: Erreprodukzioa automatikoki berrekingo da konexioa itzultzen denean.\n    Full Window: Leiho osoa\n    Autoplay is off: Autoerreprodukzioa desaktibatuta dago\n    Autoplay is on: Autoerreprodukzioa aktibatuta dago\n  MembersOnly: Kideentzat baino ez diren bideoak ezin dira FreeTuberekin ikusi, Googleren saioa hastea eta eduki sortzailearen kanalari ordaindutako bazkidetza eskatzen baitute.\n  Unlisted: Zerrendatu gabeak\n  AgeRestricted: Adin muga duten bideoak ezin dira FreeTuberekin ikusi, Googlen saioa hasi eta adinak egiaztatutako YouTubeko kontu bat erabili behar delako.\n  IP block: YouTubek bideoak ikusteko zure IP helbidea blokeatu du. Mesedez, saiatu VPN edo proxy desberdin batera aldatzen.\n  DeArrow:\n    Show Original Details: Erakutsi jatorrizko xehetasunak\n    Show Modified Details: Erakutsi aldatutako xehetasunak\n  DRMProtected: DRM babestutako bideoak ezin dira erreproduzitu FreeTuben, kode itxiko osagai jabedunak behar baitituzte. Bideo hau ikusi nahi baduzu, ikusi YouTube webgune ofizialean DRM gaituta duen web arakatzaile batean.\n#& Playlists\n  Save Watched Progress: Gorde ikusitako aurrerapena\n  Watched Progress Saved: Ikusitako aurrerapena gordeta\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Aurre-iragarkiaren gainerako denbora: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'SABR atzerapen denbora geratzen da: {remindingTimeSeconds}s'\n  Popout Live Chat: Erakutsi txata\nPlaylist:\n  #& About\n  View Full Playlist: 'Ikusi erreprodukzio-zerrenda osoa'\n  Last Updated On: 'Azkenengoz eguneratua'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Erreprodukzio-zerrenda\n  Sort By:\n    DateAddedNewest: Gehitutako dataren arabera (Berriena)\n    Custom: Pertsonalizatua\n    DateAddedOldest: Gehitutako dataren arabera (Zaharrena)\n    VideoTitleAscending: Izenburua (A-Z)\n    VideoTitleDescending: Izenburua (Z-A)\n    AuthorAscending: Egilea (A-Z)\n    AuthorDescending: Egilea (Z-A)\n    VideoDurationDescending: Iraupena (luzeena)\n    VideoDurationAscending: Iraupena (Laburrena)\n    PublishedNewest: Argitaratutako dataren arabera (Berriena)\n    PublishedOldest: Argitaratutako dataren arabera (Zaharrena)\nChange Format:\n  Change Media Formats: 'Aldatu multimedia-formatuak'\n  Use Dash Formats: 'Erabili DASH formatuak'\n  Use Legacy Formats: 'Erabili formatu zaharrak'\n  Use Audio Formats: 'Erabili audio-formatuak'\n  Dash formats are not available for this video: 'DASH formatuak ez daude eskuragarri bideo honentzat'\n  Audio formats are not available for this video: 'Audio-formatuak ez daude eskuragarri bideo honentzat'\n  Legacy formats are not available for this video: Formatu zaharrak ez daude bideo honetarako erabilgarri\nShare:\n  Share Video: 'Partekatu bideoa'\n  Share Playlist: 'Partekatu erreprodukzio-zerrenda'\n  Include Timestamp: 'Erantsi denbora-zigilua'\n  Copy Link: 'Kopiatu esteka'\n  Open Link: 'Ireki esteka'\n  Copy Embed: 'Kopiatu integratuta'\n  Open Embed: 'Ireki integratuta'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidiousen URLa arbelean kopiatu da'\n  Invidious Embed URL copied to clipboard: 'Invidiousen URL integratua arbelera kopiatu da'\n  Invidious Channel URL copied to clipboard: 'Invidiousen kanalaren URLa arbelera kopiatu da'\n  YouTube URL copied to clipboard: 'Youtuberen URLa arbelean kopiatu da'\n  YouTube Embed URL copied to clipboard: 'Youtuberen URL integratua arbelean kopiatu da'\n  YouTube Channel URL copied to clipboard: 'Youtuberen kanalaren URLa arbelean kopiatu da'\n\n  Share Channel: Partekatu kanala\n  Share Post: Partekatu argitalpena\nMini Player: 'Erreproduzitzaile txikia'\nComments:\n  Comments: 'Iruzkinak'\n  Click to View Comments: 'Egin klik iruzkinak ikusteko'\n  Getting comment replies, please wait: 'Iruzkinen erantzunak eskuratzen. Itxaron mesedez'\n  There are no more comments for this video: 'Ez dago iruzkin gehiagorik bideo honentzat'\n  Hide Comments: 'Ezkutatu iruzkinak'\n  Top comments: 'Iruzkin nagusiak'\n  Newest first: 'Berrienak lehenik'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Ez da iruzkin eskuragarririk bideo honentzat'\n  Load More Comments: 'Kargatu iruzkin gehiago'\n  Member: Kidea\n  Show More Replies: Erakutsi erantzun gehiago\n  Pinned by: Honengatik ainguratuta\n  Hearted: Bihotzez\n  View {replyCount} replies: Ikusi erantzun 1 | Ikusi {replyCount} erantzun\n  Subscribed: Harpidetuta\n  There are no comments available for this post: Ez dago iruzkinik eskuragarri mezu honetarako\n  Hide {replyCount} replies: Ezkutatu erantzun 1 | Ezkutatu {replyCount} erantzun\n  View 1 reply from {channelName}: Ikusi {channelName}-ren erantzun bat\n  View {replyCount} replies from {channelName} and others: Ikusi {channelName} eta beste batzuen {replyCount} erantzunak\nUp Next: 'Hurrengoa'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Aukeratu FreeTubek datuak lortzeko erabiltzen duen motorra. Tokiko APIa integratutako erauzgailua da. Invidious APIak Invidious zerbitzari bat behar du konektatzeko.'\n    Fallback to Non-Preferred Backend on Failure: 'Zure hobetsitako APIak arazoren bat duenean, FreeTube automatikoki saiatuko da hobetsi ez den APIa erabiltzen ordezko metodo gisa, posible denean.'\n    Thumbnail Preference: 'FreeTubeko miniatura guztiak bideoaren fotograma batekin ordezkatuko dira, lausotuta edo ezkutatuta, lehenetsitako miniaturaren ordez.'\n    Invidious Instance: 'API deietan Freetube konektatuko den Individious instantzia.'\n    Region for Trending: 'Joeren eskualdeak aukera ematen dizu bistaratu nahi dituzun herrialdeko joerako bideoak hautatzeko.'\n    External Link Handling: \"Lehenetsitako portaera hautatu, Freetuben ireki ezin den esteka bat klikatua izan denean.\\nLehentasunez, Freetubek lehenetsitako nabigatazailean irekiko du klikatutako esteka.\\n\"\n    Open Deep Links In New Window: FreeTubera pasatzen diren URLak, birbideratzeko arakatzailearen luzapenek edo komando-lerroko argumentuek, leiho berri batean irekiko dira.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Bideoak hornitzeko Invidiousera konektatuko da, YouTubera zuzeneko konexioa egin beharrean.'\n    Default Video Format: 'Ezarri bideo bat erreproduzitzean erabiliko diren formatuak. DASH formatuek kalitate handiagoak erreproduzi ditzakete. Legatu diren formatuek gehienez 360p-ra mugatuta daude, baina banda-zabalera gutxiago erabiltzen dute. Audio formatuak audio-jarioak soilik dira.'\n    Scroll Playback Rate Over Video Player: Kursorea bideoaren gainean denean, kontrol tekla sakatu eta mantendu (Komando tekla MACetan) eta saguaren gurpila aurrera eta atzera mugiarazi erreprodukzio tasa kontrolatzeko. Kontrol tekla sakatu eta mantendu (Komando tekla MACetan) eta ondoren saguaren ezkerreko botoia sakatu, lehenetsitako erreprodukzio tasara itzultzeko (1x baldin eta ezarpenetan aldaketarik egin ez bada).\n    Skip by Scrolling Over Video Player: Erabili korritze-gurpila bideoa saltatzeko, MPV estiloa.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Gaituta dagoenean, FreeTubek RSS erabiliko du bere metodo lehenetsiaren ordez zure harpidetza-jarioa lortzeko. RSS azkarragoa da eta IP blokeatzea eragozten du, baina ez du informazio jakin bat ematen, hala nola bideoaren iraupena, zuzeneko egoera edo argitalpenak'\n    Fetch Automatically: Gaituta dagoenean, FreeTubek automatikoki eskuratuko du zure harpidetza-jarioa abiaraztean eta leiho berri bat irekitzen denean.\n\n# Toast Messages\n  External Player Settings:\n    Custom External Player Executable: Lehentasunez, Freetubek uste izango du hautatutako kanpo erreproduzitzailea aurkitu dezakeela PATH ingurune aldagaiari esker. Beharrezkoa balitz, ohiko PATHa ezarri ahalko litzateke.\n    DefaultCustomArgumentsTemplate: \"(Lehenetsia: '{defaultCustomArguments}')\"\n    Ignore Warnings: Jakinarazpenak kendu, uneko kanpo erreproduzitzaileak uneko ekintza onartzen ez duenean (esaterako, alderantzizko erreprodukzio zerrendak, etab.).\n    External Player: Kanpo erreproduzitzaile bat hautatuz gero, bideoa edo erreproduzkio zerrenda (posible bada) irekitzerakoan, ikono bat agertuko da miniaturan. Kontuz, Individiousen ezarpenek ez dituzte kanpo erreproduzitzaileak trabatzen.\n    Custom External Player Arguments: Komando-lerroko argumentu pertsonalizatuak, kanpoko erreproduzitzailera pasatzea nahi duzu.\n    Ignore Default Arguments: Ez bidali argumentu lehenetsirik kanpoko erreproduzitzaileari bideoaren URLaz gain (adibidez, erreprodukzio-tasa, erreprodukzio-zerrendaren URLa, etab.). Argumentu pertsonalizatuak transmitituko dira oraindik.\n  Distraction Free Settings:\n    Hide Channels: Sartu kanalaren ID bat bideo, erreprodukzio-zerrenda eta kanala bera bilaketetan, joeran, ezagunenetan eta gomendagarrienetan ager ez dadin ezkutatzeko. Sartutako kanalaren IDak guztiz bat etorri behar du eta maiuskulak eta minuskulak bereizten ditu.\n    Hide Videos, Playlists and Channels Containing Text: Idatzi hitz bat, hitz-zati bat edo esaldi bat (maiuskulak eta minuskulak bereizten ez diren) jatorrizko izenburuak FreeTube osoan duten bideo eta erreprodukzio-zerrenda guztiak ezkutatzeko, historia, zure erreprodukzio-zerrendak eta erreprodukzio-zerrenden barneko bideoak soilik kenduta.\n    Hide Subscriptions Live: Ezarpen hau aplikazio osorako \"{appWideSetting}\" ezarpenak ordezkatzen du, \"{settingsSection}\" ataleko \"{subsection}\" atalean\n    Hide Videos on Watch: Ikusitako bideoak ezkutatzen ditu Harpidetza eta Kanalen orrialdeetako Bideoak, Laburpenak eta Zuzeneko fitxetatik. Honek ez dio eragiten Kanalen orrialdeetako Hasiera fitxari\n  Experimental Settings:\n    Replace HTTP Cache: Electron-en diskoan oinarritutako HTTP cachea desgaitzen du eta memoriako irudien cache pertsonalizatua gaitu. RAM erabilera handitzea ekarriko du.\n  SponsorBlock Settings:\n    UseDeArrowThumbnails: Ordeztu bideoaren miniaturak DeArrow-en miniaturaz.\n    UseDeArrowTitles: Ordeztu bideoen izenburuak DeArrow-en erabiltzaileek bidalitako tituluekin.\nLocal API Error (Click to copy): 'Tokiko APIak huts egin du (klikatu kopiatzeko)'\nInvidious API Error (Click to copy): 'Individious APIak huts egin du (klikatu kopiatzeko)'\nFalling back to Invidious API: 'Individious APIra itzultzen'\nFalling back to Local API: 'Tokiko APIra itzultzen'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Bideo hau ez dago erabilgarri, zenbait formatu eskas baitira. Honakoa zure herrialdean erabilgarri ez dagoelako gerta daiteke.'\nLoop is now disabled: 'Etengabeko erreprodukzioa desaktibatu egin da'\nLoop is now enabled: 'Etengabeko ereprodukzioa aktibatu egin da'\nShuffle is now disabled: 'Erreprodukzioen nahasketak desaktibatu egin dira'\nShuffle is now enabled: 'Erreprodukzioen nahasketak aktibatu egin dira'\nThe playlist has been reversed: 'Erreprodukzio-zerrenda alderantzizkatua izan da'\nPlaying Next Video: 'Hurrengo bideoa erreproduzitzen'\nPlaying Previous Video: 'Aurreko bideoa erreproduzitzen'\nPlaying Next Video Interval: 'Denbora gutxi barru hurrengo bideoa erreproduzituko da. Klikatu deuseztatzeko. | Hurrengo bideoa {nextVideoInterval} segundu barru erreproduzitzen. Klikatu deuseztatzeko. | Hurrengo bideoa {nextVideoInterval} segundu barru erreproduzitzen. Klikatu deuseztatzeko.'\nCanceled next video autoplay: 'Hurrengo bideoa automatikoki erreproduzituko da'\n'The playlist has ended. Enable loop to continue playing': 'Erreprodukzio-zerrenda bukatu da. Etengabeko erreprodukzioa aktibatu erreproduzitzen jarraitzeko'\n\nYes: 'Bai'\nNo: 'Ez'\nSearch Bar:\n  Clear Input: Garbitu sarrera\n  Remove: Kendu\nAre you sure you want to open this link?: Ziur al zaude esteka hau ireki nahi duzula?\nOpen New Window: Ireki leiho berria\nDefault Invidious instance has been set to {instance}: 'Lehenetsitako Individious instantzia {instance} gisa ezarri da'\nDefault Invidious instance has been cleared: Lehenetsitako Individious instantzia ezabatu egin da\nExternal link opening has been disabled in the general settings: Kanpo estekak irekitzea desaktibatu egin da ezarpen orokorretan\nUnknown YouTube url type, cannot be opened in app: Youtubeko URL mota ezezaguna, ezin da aplikazioan ireki\nScreenshot Success: Pantaila-argazkia gorde da\nScreenshot Error: Pantaila-argazkiak huts egin du. {error}\nNew Window: Leiho berria\nChannels:\n  Channels: Kanalak\n  Title: Kanalen zerrenda\n  Search bar placeholder: Bilatu kanalak\n  Unsubscribe Prompt: Ziur al zaude \"{channelName}\"-ren harpidetza kendu nahi duzula?\n  Count: '{number} kanal aurkitu dira.'\n  Empty: Zure kanalen zerrenda hutsik da.\nPreferences: Hobespenak\nGo to page: Joan {page}-ra\nClose Banner: Itxi iragarkia\nAge Restricted:\n  This channel is age restricted: Kanal honek adin-muga du\n  This video is age restricted: Bideo honek adin-muga du\nChannel Unhidden: '{channel} kanalaren iragazkitik kendu da'\nClipboard:\n  Cannot access clipboard without a secure connection: Ezin da arbelera sartu konexio segururik gabe\n  Copy failed: Ezin izan da kopiatu arbelean\nTag already exists: '\"{tagName}\" etiketa badago jada'\nTrimmed input must be at least N characters long: Moztutako sarrerak karaktere bat izan behar du gutxienez | Moztutako sarrerak gutxienez {length} karaktere izan behar ditu\nChapters:\n  Chapters: Kapituluak\n  Key Moments: Une garrantzitsuenak\nHashtag:\n  Hashtag: Traola\n  This hashtag does not currently have any videos: Traola honek ez du bideorik une honetan\nOk: Ados\nChannel Hidden: '{channel} gehitu da kanalaren iragazkian'\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nSearch character limit: Bilaketa-kontsultak {searchCharacterLimit} karaktereen muga gainditzen du\nFeed:\n  Feed Last Updated: '{feedName} jarioaren azken eguneraketa: {date}'\n  Refresh Feed: Eguneratu {subscriptionName}\nMoments Ago: duela momentu batzuk\nYes, Delete: Bai, ezabatu\nCancel: Utzi\nYes, Open Link: Bai, ireki esteka\nYes, Restart: Bai, berrabiarazi\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Azpitituluak\n    Closed Captions: Azpititulu deskriptiboak\n    8K: 8K\n    VR180: VR180\n    360 Video: 360º\n    New: Berria\n    3D: 3D\nKeys:\n  arrowleft: Gezia ezkerrera\n  arrowright: Gezia eskuinera\n  arrowup: Gezia gora\n  arrowdown: Gezia behera\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Plus\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: Egin klik eskuineko botoiarekin edo mantendu sakatuta historia ikusteko\nAutoplay Interruption Timer: Erreprodukzio automatikoa bertan behera utzi da {autoplayInterruptionIntervalHours} orduz geldirik egon delako\nDescription:\n  Collapse Description: Erakutsi gutxiago\n  Expand Description: '...gehiago'\nKeyboardShortcutPrompt:\n  Skip by Tenths: Saltatu bideoa ehunekoaren arabera (3 jauzi iraupenaren %30era iristeko)\n  New Window: Sortu leiho berri bat\n  Navigate to Settings: Nabigatu ezarpenen orrira\n  Navigate to History: Nabigatu historiaren orrira\n  Refresh: Freskatu jarioa azken edukiarekin\n  Volume Down: Jaitsi bolumena\n  Small Rewind: Birbobinatu X segundo atzerako tartearen eta uneko bideo-erreprodukzioaren tasaren arabera\n  Small Fast Forward: Aurrera egin X segundo atzerako tartearen eta uneko bideo-erreprodukzioaren tasaren arabera\n  Last Chapter: Azken atala\n  Next Chapter: Hurrengo atala\n  Captions: Aktibatu/Desaktibatu epigrafeak\n  Stats: Erakutsi bideoaren estatistikak\n  Fullscreen: Aldatu pantaila osora\n  History Forward: Egin orrialde bat aurrera\n  Focus Secondary Search: Fokuratu bigarren mailako bilaketa-barran (bat badago)\n  Play: Txandakatu erreproduzitu/gelditu\n  Large Fast Forward: Egin aurrera 10 segundo / Egin aurrera bideoa egungo bideoaren erreprodukzio tasan oinarrituta\n  Large Rewind: Birbobinatu 10 segundo / Birbobinatu bideoa uneko bideo-erreprodukzio tasan oinarrituta\n  Full Window: Aldatu leiho osora\n  Theatre Mode: Aldatu antzerki modura\n  Decrease Video Speed: Murriztu bideoaren abiadura bideoaren erreprodukzio-tasaren tartearen arabera\n  Increase Video Speed: Handitu bideoaren abiadura bideoaren erreprodukzio-tasaren tartearen arabera\n  Search in New Window: Bilatu leiho berrian\n  Last Frame: Aurreko fotograma (geldituta dagoen bitartean)\n  Next Frame: Hurrengo fotograma (geldituta dagoen bitartean)\n  Volume Up: Igo bolumena\n  Toggle Developer Tools: Txandakatu garatzailearen tresnak\n  Reset Zoom: Berrezarri zoom maila / Erabiltzaile Interfazearen eskala\n  Zoom In: Handiagotu\n  Zoom Out: Txikiagotu\n  Focus Search: Fokuratu bilaketa-barran\n  Keyboard Shortcuts: Teklatuko laster-bideak\n  Sections:\n    Video:\n      Playback: 'Bideoa: Erreprodukzioa'\n      General: 'Bideoa: Orokorra'\n    App:\n      Situational: 'App: Egoera mailakoa'\n      General: 'App: Orokorra'\n  Picture in Picture: Aldatu irudiz irudiko modura\n  Mute: Aldatu mututasuna\n  Take Screenshot: Hartu pantaila-argazkia\n  Minimize Window: Minimizatu leihoa\n  Close Window: Itxi leihoa\n  Show Keyboard Shortcuts: Erakutsi teklatuko laster-bideak\n  History Backward: Egin orrialde bat atzera\n  Home: Joan bideoaren hasierara\n  End: Bilatu bideoaren amaierarantz\n  Skip to Next Video: Joan erreprodukzio-zerrendaren hurrengo bideora edo gomendatutako hurrengo bideora\n  Skip to Previous Video: Joan erreprodukzio-zerrendaren aurreko bideora\nshortcutLabelSeparator: ｜\nCompact side navigation: Trinkotu alboko nabigazioa\nExpand side navigation: Zabaldu alboko nabigazioa\n"
  },
  {
    "path": "static/locales/fa.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'فارسی'\n\n# Webkit Menu Bar\nFile: 'فایل'\nQuit: 'خروج'\nEdit: 'ویرایش'\nUndo: 'بازگردانی'\nRedo: 'انجام دوباره'\nCut: 'برش'\nCopy: 'کپی'\nPaste: 'جایگذاری'\nDelete: 'حذف'\nSelect all: 'انتخاب همه'\nToggle Developer Tools: 'فعال سازی حالت توسعه دهنده'\nActual size: 'اندازه واقعی'\nZoom in: 'بزرگنمایی'\nZoom out: 'کوچک نمایی'\nToggle fullscreen: 'فعال سازی حالت تمام صفحه'\nWindow: 'پنجره'\nMinimize: 'کوچک سازی'\nClose: 'بستن'\nBack: 'بازگشت'\nForward: 'پیشروی'\nOpen New Window: 'بازکردن پنجره جدید'\n\nDownload From Site: 'دانلود از سایت'\nSearch / Go to URL: 'جست و جو / برو به لینک'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'فیلترهای جست و جو'\n  Sort By:\n    Most Relevant: 'مرتبط ترین'\n    Rating: 'امتیاز'\n    Upload Date: 'زمان بارگذاری'\n    View Count: 'تعداد بازدید'\n  Time:\n    Time: 'زمان'\n    Any Time: 'هر زمانی'\n    Last Hour: 'یک ساعت قبل'\n    Today: 'امروز'\n    This Week: 'این هفته'\n    This Month: 'این ماه'\n    This Year: 'این سال'\n  Type:\n    Type: 'نوع'\n    All Types: 'همه ی انواع'\n    Videos: 'ویدیو ها'\n    Channels: 'کانال ها'\n    #& Playlists\n    Movies: فیلم ها\n  Duration:\n    Duration: 'طول مدت'\n    All Durations: 'طول مدت همه'\n    Short (< 4 minutes): 'کوتاه(>۴ دقیقه)'\n    Long (> 20 minutes): 'طولانی(<۲۰ دقیقه)'\n  # On Search Page\n    Medium (4 - 20 minutes): متوسط (۴ تا ۲۰ دقیقه)\n  Search Results: 'نتایج جست و جو'\n  Fetching results. Please wait: 'دریافت نتایج.لطفا صبر کنید'\n  Fetch more results: 'دریافت نتایج بیشتر'\n  There are no more results for this search: 'نتایج بیشتری برای این جست و جو نیست'\n# Sidebar\n  Features:\n    360 Video: ویدیو ۳۶۰\n    Location: موقعیت\n    Features: قابلیت ها\n    Subtitles: زیرنویس\n    3D: سه بعدی\n    HDR: اچ‌دی‌آر\n    Live: زنده\n    4K: ۴کی\n    HD: وضوح‌بالا\n    Creative Commons: کرییتیو کامنز\n    VR180: VR180\n  Clear Filters: پاک کردن فیلترها\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'دنبال کرده ها'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'این پروفایل تعداد زیادی اشتراک دارد. اجبار RSS برای جلوگیری از محدودیت نرخ'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'لیست اشتراک شما در حال حاضر خالی است. اضافه کردن اشتراک‌ها را برای مشاهده آنها در اینجا شروع کنید. اگر می‌خواهید اشتراک‌های خود را وارد کنید، می‌توانید به تنظیمات داده رفته و وارد کردن اشتراک‌ها را انتخاب کنید یا می‌توانید کانالی را جستجو کرده و در آن‌ها مشترک شوید.'\n  Load More Videos: 'بارگیری ویدیو های بیشتر'\n  Error Channels: کانال های خطادار\n  Subscriptions Tabs: برگه های اشتراک\n  Disabled Automatic Fetching: شما دریافت خودکار دنبال کرده ها را غیر فعال کرده اید. دنبال کرده ها را تازه سازی کنید تا آنها را اینجا ببینید.\n  Empty Channels: کانال های مشترک شما در حال حاضر هیچ ویدیویی ندارند.\n  All Subscription Tabs Hidden: همه تب های اشتراک پنهان هستند. برای مشاهده محتوا در اینجا، لطفاً برخی از برگه‌ها را در بخش '{subsection}' در '{settingsSection}' باز کنید.\n  Load More Posts: بارگذاری پیام های بیشتر\n  Empty Posts: کانال‌های مشترک شما در حال حاضر هیچ پستی برای نمایش ندارند.\nMore: 'بیشتر'\nTrending:\n  Trending: 'پربازدید ها'\n  Gaming: 'بازی'\n  Trending Tabs: 'سربرگ پربازدید ها'\n  Sports: ورزش\nMost Popular: 'پر طرفدارترین ها'\nPlaylists: 'لیست های پخش'\nUser Playlists:\n  Your Playlists: 'لیست های پخش شما'\n  Search bar placeholder: جستجو برای فهرست های پخش\n  Empty Search Message: هیچ ویدیویی در این لیست پخش وجود ندارد که با جستجوی شما مطابقت داشته باشد\n  Cancel: لغو\n  Remove from Playlist: پاک کردن از فهرست پخش\n  Playlist Name: نام فهرست پخش\n  Save Changes: ذخیره سازی تغییرات\n  Move Video Down: انتقال ویدیو به پایین\n  Add to Playlist: افزودن به فهرست پخش\n  Add to Favorites: افزودن به {playlistName}\n  Move Video Up: انتقال ویدیو به بالا\n  Playlist Description: توضیحات فهرست پخش\n  Remove Watched Videos: ویدیوهای تماشا شده را حذف کنید\n  Create New Playlist: ایجاد فهرست پخش جدید\n  Playlists with Matching Videos: فهرست‌های پخش با ویدیوهای منطبق\n  This playlist currently has no videos.: این فهرست پخش در حال حاضر ویدیویی ندارد.\n  Edit Playlist Info: ویرایش اطلاعات فهرست پخش\n  Remove from Favorites: حذف از {playlistName}\n  Remove Duplicate Videos: حذف ویدیوهای تکراری\n  AddVideoPrompt:\n    Save: ذخیره کنید\n    Search in Playlists: جستجو در لیست‌های پخش\n    Allow Adding Duplicate Video(s): اجازه افزودن ویدیو(های) تکراری\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: هنوز هیچ لیست پخشی را انتخاب نکرده‌اید.\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} ویدیو از قبل اضافه شده'\n    N playlists selected: '{playlistCount} انتخاب شد'\n    Added {count} Times: قبلا اضافه شده | {count} بار اضافه شد\n    Select a playlist to add your N videos to: یک لیست پخش برای افزودن ویدیوی خود به | انتخاب کنید یک لیست پخش برای افزودن ویدیوهای {videoCount} خود انتخاب کنید در\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} ویدیو اضافه خواهند شد'\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: ویدیو حذف شده است\n      There was a problem with removing this video: در حذف این ویدیو مشکلی وجود داشت\n      This playlist is now used for quick bookmark: این لیست پخش اکنون برای نشانک سریع استفاده می‌شود\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: برخی از ویدیوها در لیست پخش هنوز بارگیری نشده اند. به هر حال برای کپی اینجا کلیک کنید.\n      \"{videoCount} video(s) have been removed\": 1 ویدئو حذف شد | {videoCount} ویدیو حذف شد\n      Playlist {playlistName} has been deleted.: فهرست پخش {playlistName} حذف شد.\n      This video cannot be moved up.: این ویدئو را نمی‌توان به بالا منتقل کرد.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: این لیست پخش اکنون برای نشانک سریع به جای {oldPlaylistName} استفاده می شود. برای لغو اینجا را کلیک کنید\n      This playlist is already being used for quick bookmark.: این لیست پخش در حال حاضر برای نشانک سریع استفاده می شود.\n      Playlist name cannot be empty. Please input a name.: نام لیست پخش نمی تواند خالی باشد. لطفا یک نام وارد کنید.\n      There were no videos to remove.: هیچ ویدیویی برای حذف وجود نداشت.\n      This playlist is protected and cannot be removed.: این لیست پخش محافظت می‌شود و نمی‌توان آن را حذف کرد.\n      This video cannot be moved down.: این ویدئو را نمی‌توان به پایین منتقل کرد.\n      Playlist has been updated.: لیست پخش به روز شد.\n      There was an issue with updating this playlist.: مشکلی در به‌روزرسانی این لیست پخش وجود داشت.\n      This playlist does not exist: این لیست پخش وجود ندارد\n      Reverted to use {oldPlaylistName} for quick bookmark: به استفاده از {oldPlaylistName} برای نشانک‌گذاری سریع بازگردد\n      This playlist has a video with a duration error: این لیست پخش شامل حداقل یک ویدیو است که مدت زمان ندارد، به گونه‌ای مرتب می‌شود که گویی مدت زمان آنها صفر است.\n      Video has been removed. Click here to undo.: ویدیو حذف شد. برای لغو اینجا کلیک کنید.\n    Search for Videos: جستجوی ویدئوها\n  Sort By:\n    EarliestUpdatedFirst: تاریخ به‌روزرسانی (قدیمی‌ترین)\n    LatestUpdatedFirst: تاریخ به‌روزرسانی (جدیدترین)\n    NameAscending: آ-ی\n    NameDescending: ی-آ\n    LatestCreatedFirst: تاریخ ایجاد (جدیدترین)\n    LatestPlayedFirst: تاریخ پخش (جدیدترین)\n    EarliestPlayedFirst: تاریخ پخش (قدیمی‌ترین)\n    EarliestCreatedFirst: تاریخ ایجاد (قدیمی‌ترین)\n  CreatePlaylistPrompt:\n    Toast:\n      Playlist {playlistName} has been successfully created.: لیست پخش {playlistName} با موفقیت ایجاد شد.\n      There is already a playlist with this name. Please pick a different name.: از قبل یک فهرست پخش با این نام وجود دارد. لطفا نام دیگری انتخاب کنید.\n      There was an issue with creating the playlist.: مشکلی در ایجاد لیست پخش وجود داشت.\n    New Playlist Name: نام لیست پخش جدید\n    Create: ایجاد\n  You have no playlists. Click on the create new playlist button to create a new one.: شما هیچ لیست پخشی ندارید. بر روی دکمه ایجاد لیست پخش جدید کلیک کنید تا لیست پخش جدیدی ایجاد شود.\n  Export Playlist: صادر کردن این لیست پخش\n  The playlist has been successfully exported: لیست پخش با موفقیت صادر شد\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: آیا مطمئنید که می خواهید 1 ویدیوی تماشا شده را از این لیست پخش حذف کنید؟ این قابل واگرد نیست. | آیا مطمئن هستید که می خواهید {playlistItemCount} ویدیو تماشا شده را از این لیست پخش حذف کنید؟ این قابل واگرد نیست.\n  Cannot delete the quick bookmark target playlist.: نمی توان لیست پخش مورد نظر نشانک سریع را حذف کرد.\n  Are you sure you want to delete this playlist? This cannot be undone: آیا مطمئن هستید که می خواهید این لیست پخش را حذف کنید؟ این قابل واگرد نیست.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: آیا مطمئنید که می‌خواهید 1 ویدیوی تکراری را از این فهرست پخش حذف کنید؟ این قابل واگرد نیست. | آیا مطمئنید که می خواهید {playlistItemCount} ویدیو تکراری را از این لیست پخش حذف کنید؟ این قابل واگرد نیست.\n  Copy Playlist: رونوشت لیست‌پخش\n  Enable Quick Bookmark With This Playlist: فعال کردن نشانک سریع با این لیست پخش\n  Quick Bookmark Enabled: نشانک سریع فعال شد\n  Delete Playlist: حذف لیست پخش\n  TotalTimePlaylist: 'زمان کل: {duration}'\n  Export list of URLs: صادرات فهرست نشانی اینترنتی\nHistory:\n  # On History Page\n  History: 'تاریخچه'\n  Watch History: 'تاریخچه تماشا'\n  Your history list is currently empty.: 'تاریخچه شما در حال حاضر خالی است.'\n  Search bar placeholder: جستجو در تاریخچه\n  Empty Search Message: هیچ ویدیویی در سابقه شما وجود ندارد که با جستجوی شما مطابقت داشته باشد\n  Case Sensitive Search: جستجوی حساس به حروف کوچک و بزرگ\n  DateOldestHistory: اولین تماشا شده\n  DateNewestHistory: آخرین مشاهده اول\nSettings:\n  # On Settings Page\n  Settings: 'تنظیمات'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'این نرم افزار نیاز به راه اندازی دوباره دارد تا تغییرات لحاظ شوند. تغییرات ذخیره و راه اندازی شود؟'\n  General Settings:\n    General Settings: 'عمومی'\n    Check for Updates: 'بررسی برای به روزرسانی ها'\n    Check for Latest Blog Posts: 'بررسی آخرین مطالب وبلاگ'\n    Fallback to Non-Preferred Backend on Failure: 'بازگشت به Backend غیر ترجیحی در صورت شکست'\n    Enable Search Suggestions: 'فعال کردن پیشنهادات جستجو'\n    Default Landing Page: 'صفحه اول پیشفرض'\n    Locale Preference: 'تغیر زبان سیستم'\n    System Default: 'پیشفرض سیستم'\n    Preferred API Backend:\n      Preferred API Backend: 'API پشتیبان ترجیح داده شده'\n      Local API: 'ای پی ای داخلی'\n      Invidious API: 'ای پی ای Invidious'\n    Video View Type:\n      Video View Type: 'طرز نمایش ویدیو'\n      Grid: 'شبکه'\n      List: 'فهرست'\n    Thumbnail Preference:\n      Thumbnail Preference: 'اولویت کاور ویدیو'\n      Default: 'پیشفرض'\n      Beginning: 'ابتدا'\n      Middle: 'وسط'\n      End: 'انتها'\n      Hidden: مخفی\n      Blur: تاری\n    Current Invidious Instance: 'نمونه فعلی Invidious'\n    The currently set default instance is {instance}: 'در حال حاضر نمونه Invidious پیشفرض {instance} است'\n    No default instance has been set: 'هیچ نمونه پیشفرضی تنظیم نشده'\n    Current instance will be randomized on startup: 'نمونه فعلی هنگام شروع برنامه تصادفی خواهد بود'\n    Set Current Instance as Default: 'تنظیم نمونه فعلی به عنوان نمونه پیشفرض'\n    Clear Default Instance: 'پاک کردن نمونه پیشفرض'\n    View all Invidious instance information: 'دیدن تمام اطلاعات نمونه Invidious'\n    Region for Trending: 'منطقه برای پربازدید ها'\n        #! List countries\n    External Link Handling:\n      Open Link: باز کردن لینک\n      Ask Before Opening Link: پرسیدن قبل از باز کردن لینک\n      No Action: کاری نکردن\n      External Link Handling: اداره کردن لینک های خارجی\n    Auto Load Next Page:\n      Label: بارگذاری خودکار صفحه بعدی\n      Tooltip: صفحات و نظرات اضافی را به صورت خودکار بارگیری کنید.\n    Open Deep Links In New Window: نشانی های ارسال شده به FreeTube را در یک پنجره جدید باز کنید\n    Minimize to system tray: کوچک کردن در سینی سیستم\n  Theme Settings:\n    Theme Settings: 'طرح'\n    Match Top Bar with Main Color: 'یکسان سازی قطعه بالا با رنگ اصلی'\n    Expand Side Bar by Default: 'گسترش ستون فرعی به صورت پیشفرض'\n    Disable Smooth Scrolling: 'غیرفعال کردن حرکت ملایم'\n    UI Scale: 'نسبت رابط کاربری'\n    Base Theme:\n      Base Theme: 'تم اصلی'\n      Black: 'سیاه'\n      Dark: 'تاریک'\n      Light: 'روشن'\n      Dracula: دراکولا\n      System Default: پیش فرض سیستم\n      Catppuccin Mocha: مجموعه رنگ کتپوسین موکا\n      Hot Pink: صورتی داغ\n      Pastel Pink: صورتی پاستلی\n      Solarized Dark: درخشش تاریک\n      Solarized Light: درخشش روشن\n      Gruvbox Dark: جعبه تیره تاریک\n      Gruvbox Light: جعبه تیره روشن\n      Nordic: شمال اروپا\n      Catppuccin Frappe: تم رنگ کت پوچین فراپه\n      Everforest Light Medium: جنگل ابدی روشن متوسط\n      Everforest Light Hard: جنگل ابدی روشن سخت\n      Everforest Dark Hard: جنگل ابدی تاریک سخت\n      Everforest Dark Medium: جنگل ابدی تاریک متوسط\n      Everforest Dark Low: جنگل ابدی تاریک کم\n      Everforest Light Low: جنگل ابدی روشن کم\n    Main Color Theme:\n      Main Color Theme: 'رنگ تم اصلی'\n      Red: 'قرمز'\n      Pink: 'صورتی'\n      Purple: 'بنفش'\n      Deep Purple: 'بنفش پر رنگ'\n      Indigo: 'نیلی'\n      Blue: 'آبی'\n      Light Blue: 'آبی روشن'\n      Cyan: 'آبی یشمی'\n      Teal: 'سبز آبی'\n      Green: 'سبز'\n      Light Green: 'سبز روشن'\n      Lime: 'لیمویی'\n      Yellow: 'زرد'\n      Amber: 'کهربایی'\n      Orange: 'نارنجی'\n      Deep Orange: 'نارنجی پر رنگ'\n      Dracula Green: سبز دراکولا\n      Dracula Pink: صورتی دراکولا\n      Dracula Purple: بنفش دراکولا\n      Dracula Yellow: زرد دراکولا\n      Dracula Orange: نارنجی دراکولا\n      Dracula Red: قرمز دراکولا\n      Dracula Cyan: آبی یشمی دراکولا\n      Catppuccin Mocha Rosewater: گلاب\n      Catppuccin Mocha Sapphire: یاقونی\n      Catppuccin Mocha Blue: کتپوچین موکا آبی\n      Catppuccin Mocha Sky: آسمانی\n      Catppuccin Mocha Lavender: بنفش کمرنگ\n      Catppuccin Mocha Flamingo: فلامینگو\n      Catppuccin Mocha Teal: مرغابی\n      Catppuccin Mocha Pink: کتپوچین موکا صورتی\n      Catppuccin Mocha Mauve: ارغوانی سیر\n      Catppuccin Mocha Red: کتپوسین موکا قرمز\n      Catppuccin Mocha Maroon: خرمایی\n      Catppuccin Mocha Peach: هلویی\n      Catppuccin Mocha Yellow: کتپوسین موکا زرد\n      Catppuccin Mocha Green: کتپوچین موکا سبز\n      Gruvbox Light Orange: جعبه‌تیره نارنجی روشن\n      Solarized Cyan: فیروزه‌ای درخشان\n      Solarized Orange: نارنجی درخشان\n      Solarized Red: قرمز درخشان\n      Solarized Violet: بنفش درخشان\n      Solarized Blue: آبی درخشان\n      Solarized Magenta: سرخابی درخشان\n      Solarized Green: سبز درخشان\n      Gruvbox Dark Yellow: جعبه‌تیره زرد\n      Gruvbox Dark Blue: جعبه‌تیره آبی\n      Gruvbox Dark Aqua: جعبه‌تیره آسمانی\n      Gruvbox Dark Purple: جعبه‌تیره ارغوانی\n      Gruvbox Dark Orange: جعبه‌تیره نارنجی\n      Gruvbox Light Red: جعبه‌تیره قرمز\n      Solarized Yellow: زرد درخشان\n      Gruvbox Dark Green: جعبه‌تیره سبز\n      Gruvbox Light Blue: جعبه‌تیره آبی روشن\n      Gruvbox Light Purple: جعبه‌تیره ارغوانی روشن\n      Catppuccin Frappe Sky: کتپوچین فراپه آسمانی\n      Catppuccin Frappe Peach: کتپوچین فراپه هلویی\n      Catppuccin Frappe Lavender: کتپوچین فراپه اسطوخودوس\n      Catppuccin Frappe Flamingo: کتپوچین فراپه فلامینگو\n      Catppuccin Frappe Green: کتپوچین فراپه سبز\n      Catppuccin Frappe Teal: کتپوچین فراپه آبی رنگ\n      Catppuccin Frappe Rosewater: کتپوچین فراپه گلاب\n      Catppuccin Frappe Yellow: کتپوچین فراپه زرد\n      Catppuccin Frappe Pink: کتپوچین فراپه صورتی\n      Catppuccin Frappe Mauve: کتپوچین فراپه ارغوانی\n      Catppuccin Frappe Maroon: کتپوچین فراپه مارون\n      Catppuccin Frappe Sapphire: کتپوچین فراپه یاقوت کبود\n      Catppuccin Frappe Blue: کتپوچین فراپه آبی\n      Catppuccin Frappe Red: کتپوچین فراپه قرمز\n      Everforest Light Green: جنگل ابدی سبز روشن\n      Everforest Light Aqua: جنگل ابدی آسمانی روشن\n      Everforest Light Blue: جنگل ابدی آبی روشن\n      Everforest Light Purple: جنگل ابدی بنفش روشن\n      Everforest Dark Red: جنگل ابدی قرمز تیره\n      Everforest Dark Orange: جنگل ابدی نارنجی تیره\n      Everforest Dark Yellow: جنگل ابدی زرد تیره\n      Everforest Dark Green: جنگل ابدی سبز تیره\n      Everforest Dark Aqua: جنگل ابدی آسمانی تیره\n      Everforest Dark Blue: جنگل ابدی آبی تیره\n      Everforest Dark Purple: جنگل ابدی ینفش تیره\n      Everforest Light Red: جنگل ابدی قرمز روشن\n      Everforest Light Orange: جنگل ابدی نارنجی روشن\n      Everforest Light Yellow: جنگل ابدی زرد روشن\n    Secondary Color Theme: 'رنگ دوم تم'\n        #* Main Color Theme\n    Hide Side Bar Labels: مخفی کردن عنوان های ستون فرعی\n    Hide FreeTube Header Logo: لوگوی سربرگ FreeTube را مخفی کنید\n  Player Settings:\n    Player Settings: 'پخش کننده'\n    Play Next Video: 'پخش اتوماتیک ویدیو پیشنهادی'\n    Turn on Subtitles by Default: 'فعال کردن زیرنویس به عنوان پیشفرض'\n    Autoplay Videos: 'شروع خودکار ویدیوها'\n    Proxy Videos Through Invidious: 'پروکسی ویدیو ها از طریق Invidious'\n    Autoplay Playlists: 'پخش خودکار فهرست پخش'\n    Enable Theatre Mode by Default: 'فعال کردن حالت تئاتر به عنوان پیشفرض'\n    Scroll Volume Over Video Player: 'کنترل صدا با حرکت اسکرول موس روی پخش کننده ویدیو'\n    Display Play Button In Video Player: 'نمایش دکمه پخش داخل پخش کننده ویدیو'\n    Next Video Interval: 'تایمر شمارش معکوس پخش خودکار'\n    Fast-Forward / Rewind Interval: 'بازه زمانی جلو / عقب رفتن سریع'\n    Default Volume: 'میزان صدای پیشفرض'\n    Default Playback Rate: 'سرعت پخش پیشفرض'\n    Default Video Format:\n      Default Video Format: 'فرمت ویدیو پیشفرض'\n      Dash Formats: 'فرمت های DASH'\n      Legacy Formats: 'فرمت های قدیمی'\n      Audio Formats: 'فرمت های صدا'\n    Default Quality:\n      Default Quality: 'کیفیت پیشفرض'\n      Auto: 'خودکار'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Scroll Playback Rate Over Video Player: کنترل سرعت پخش با حرکت اسکرول موس روی پخش کننده ویدیو\n    Video Playback Rate Interval: فاصله سرعت پخش ویدیو\n    Max Video Playback Rate: حداکثر سرعت پخش ویدیو\n    Enter Fullscreen on Display Rotate: در چرخه نمایشگر وارد صفحه تمام صفحه شوید\n    Screenshot:\n      Format Label: فرمت اسکرین شات\n      Error:\n        Forbidden Characters: کاراکتر های ممنوعه\n        Empty File Name: نام فایل خالی\n      File Name Label: الگوی نام فایل\n      Quality Label: کیفیت اسکرین شات\n      File Name Tooltip: می توانید از متغیرهای زیر استفاده کنید. %Y سال 4 رقم. رقم %M ماه 2. %D رقم روز 2. %H ساعت 2 رقمی. %N دقیقه 2 رقم. %S 2 رقم دوم. %T میلی ثانیه 3 رقمی. %s ویدیو دوم. %t ویدیو میلی ثانیه 3 رقمی. %i شناسه ویدیو.\n      Enable: اسکرین شات فعال باشد\n      Ask Path: پرسش برای محل ذخیره\n      Folder Label: پوشه اسکرین شات\n      Folder Button: پوشه را انتخاب کنید\n    Skip by Scrolling Over Video Player: با پیمایش روی پخش‌کننده ویدیو از آن بگذرید\n    Autoplay Interruption Timer: تایمر وقفه پخش خودکار\n    Default Viewing Mode:\n      Theater: تئاتر\n      Default Viewing Mode: حالت تماشای پیش‌فرض\n      Full Screen: تمام صفحه\n      Picture in Picture: تصویر در تصویر\n      External Player: ‍پخش کننده خارجی ({externalPlayerName})\n  External Player Settings:\n    External Player Settings: 'پخش کننده خارجی'\n    External Player: 'پخش کننده خارجی'\n    Ignore Unsupported Action Warnings: 'به اخطارهای فعالیت پشتیبانی نشده اهمیت نده'\n    Custom External Player Executable: 'پخش کننده خارجی شخصی سازی شده قابل اجرا'\n    Custom External Player Arguments: 'ورودی های شخصی سازی شده پخش کننده خارجی'\n    Players:\n      None:\n        Name: هیچ کدام\n    Ignore Default Arguments: نادیده گرفتن برهان های پیش فرض\n  Privacy Settings:\n    Privacy Settings: 'امنیتی'\n    Remember History: 'حفظ تاریخچه تماشا'\n    Save Watched Progress: 'ذخیره ویدیو های دیده شده'\n    Clear Search Cache: 'پاک کردن کش جستجو'\n    Are you sure you want to clear out your search cache?: 'آیا مطمئن هستید که میخواهید کش جستجویتان را پاک کنید؟'\n    Search cache has been cleared: 'کش جستجو پاک شد'\n    Remove Watch History: 'حذف تاریخچه تماشا'\n    Are you sure you want to remove your entire watch history?: 'آیا مطمئن هستید که میخواهید تمام تاریخچه تماشایتان را حذف کنید؟'\n    Watch history has been cleared: 'تاریخچه تماشا پاک شد'\n    Remove All Subscriptions / Profiles: 'حذف تمام دنبال شوندگان / پروفایل ها'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'آیا مطمئن هستید که می خواهید همه اشتراک ها و نمایه ها را حذف کنید؟ این قابل بازگشت نیست.'\n    Save Watched Videos With Last Viewed Playlist: ویدئوهای تماشا شده را با لیست پخش آخرین مشاهده ذخیره کنید\n    All playlists have been removed: تمام لیست های پخش حذف شد\n    Remove All Playlists: حذف تمام لیست های پخش\n    Are you sure you want to remove all your playlists?: آیا مطمئنید که می‌خواهید همه فهرست‌های پخش خود را حذف کنید؟\n    Clear Search History and Cache: تاریخچه جستجو و حافظه پنهان را پاک کنید\n    Remember Search History: سابقه جستجو را به خاطر بسپارید\n    Are you sure you want to clear out your search history and cache?: آیا مطمئنید که می‌خواهید سابقه جستجو و حافظه پنهان خود را پاک کنید؟\n    Search history and cache have been cleared: سابقه جستجو و حافظه پنهان پاک شده است\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: خودکار\n        Never: هرگز\n        Semi-auto: نیمه خودکار\n      Tooltip: خودکار = ذخیره در هر خروجی از صفحه ویدئو، زمانی که ویدیو به پایان رسید و با خطا مواجه شد (به عنوان مثال، نرخ محدود و تماشای جلسه منقضی شده). نیمه خودکار = مانند خودکار به جز در خروج از صفحه نمایش ویدئو و می تواند پیشرفت دستی را از طریق یک دکمه به نام ذخیره پیشرفت تماشا شده، واقع در زیر پخش کننده ویدئو ذخیره کند.\n  Subscription Settings:\n    Subscription Settings: 'دنبال شوندگان'\n    Fetch Feeds from RSS: 'دریافت feed ها از RSS'\n    Fetch Automatically: آوردن خودکار فید\n    Confirm Before Unsubscribing: تایید لغو اشتراک\n    'Limit the number of videos displayed for each channel': تعداد ویدیوهای نمایش داده شده برای هر کانال را محدود کنید\n    To: به\n  Distraction Free Settings:\n    Distraction Free Settings: 'اضافات مفید'\n    Hide Video Views: 'مخفی کردن دیده های ویدیو'\n    Hide Video Likes And Dislikes: 'مخفی کردن لایک و دیسلایک های ویدیو'\n    Hide Channel Subscribers: 'مخفی کردن دنبال کنندگان کانال'\n    Hide Comment Likes: 'مخفی کردن لایک های نظرات'\n    Hide Recommended Videos: 'مخفی کردن ویدیو های پیشنهادی'\n    Hide Trending Videos: 'مخفی کردن ویدیو های پر بازدید'\n    Hide Popular Videos: 'مخفی کردن ویدیو های پر طرفدار'\n    Hide Playlists: 'مخفی کردن فهرست های پخش'\n    Hide Live Chat: 'مخفی کردن چت لایو'\n    Hide Active Subscriptions: 'مخفی کردن دنبال کنندگان فعال'\n    Hide Channel Playlists: '\"لیست های پخش\" کانال را مخفی کنید'\n    Sections:\n      Watch Page: صفحه تماشا\n      Subscriptions Page: صفحه اشتراک ها\n      Side Bar: نوار کناری\n      Channel Page: صفحه کانال\n      General: عمومی\n    Hide Live Streams: پنهان کردن پخشهای زنده\n    Hide Subscriptions Videos: پنهان کردن ویدیوهای اشتراک\n    Hide Video Description: مخفی کردن توضیحات ویدیو\n    Hide Featured Channels: پنهان کردن کانال های ویژه\n    Hide Comments: پنهان کردن نظرات\n    Hide Profile Pictures in Comments: مخفی کردن تصاویر پروفایل در نظرات\n    Display Titles Without Excessive Capitalisation: نمایش عناوین بدون حروف بزرگ و نقطه گذاری\n    Hide Channels: پنهان کردن ویدیوها از کانال ها\n    Hide Upcoming Premieres: مخفی کردن اولین نمایش های آینده\n    Hide Chapters: پنهان کردن فصل ها\n    Hide Channels Placeholder: شناسه کانال\n    Hide Subscriptions Live: مخفی کردن اشتراک های زنده\n    Hide Channel Shorts: مخفی کردن \"ویدئو های کوتاه\" کانال\n    Hide Subscriptions Shorts: مخفی کردن شورت اشتراک ها\n    Hide Channel Podcasts: پنهان کردن \"پادکست‌های\" کانال\n    Hide Channel Releases: مخفی کردن \"انتشارات\" کانال\n    Hide Sharing Actions: مخفی کردن فعالیت های مشترک\n    Hide Videos on Watch: 'مخفی کردن ویدیو ها هنگام تماشا'\n    Hide Videos, Playlists and Channels Containing Text Placeholder: کلمه، بخش کلمه یا عبارت\n    Hide Channels Invalid: شناسه کانال ارائه شده نامعتبر بود\n    Hide Channels Already Exists: شناسه کانال از قبل وجود دارد\n    Hide Videos, Playlists and Channels Containing Text: ویدیوها و لیست های پخش حاوی متن را مخفی کنید\n    Hide Channel Home: مخفی کردن \"صفحه اصلی\" کانال\n    Hide Channels API Error: خطای بازیابی کاربر با شناسه ارائه شده. لطفا دوباره بررسی کنید که شناسه درست باشد.\n    Hide Channels Disabled Message: برخی از کانال‌ها با استفاده از شناسه مسدود شدند و پردازش نشدند. در حالی که آن شناسه ها در حال به روز رسانی هستند، ویژگی مسدود می شود\n    Show Added Items: نمایش موارد اضافه شده\n    Hide Channel Courses: پنهان کردن زبانه \"دوره‌ها\" کانال\n    Hide Subscriptions Posts: مخفی کردن پست های اشتراک\n    Hide Channel Posts: مخفی کردن تب \"پست ها\" کانال\n  Data Settings:\n    Data Settings: 'داده ها'\n    Select Export Type: 'انتخاب روش پشتیبان گیری'\n    Import Subscriptions: 'وارد کردن بک آپ دنبال شوندگان'\n    Export Subscriptions: 'ذخیره (پشتیبان گیری)دنبال شوندگان'\n    Export FreeTube: 'استخراج FreeTube'\n    Export YouTube: 'استخراج YouTube'\n    Export NewPipe: 'استخراج NewPipe'\n    Import History: 'وارد کردن تاریخچه'\n    Export History: 'ذخیره (پشتیبان گیری)تاریخچه'\n    Profile object has insufficient data, skipping item: 'پروفایل داده کافی ندارد، در حال چشم پوشی'\n    All subscriptions and profiles have been successfully imported: 'همه دنبال شوندگان و پروفایل ها با موفقیت ثبت شد'\n    All subscriptions have been successfully imported: 'همه دنبال شوندگان با موفقیت ثبت شد'\n    Invalid subscriptions file: 'فایل دنبال شوندگان نامعتبر است'\n    Invalid history file: 'فایل تاریخچه نامعتبر است'\n    Subscriptions have been successfully exported: 'دنبال شوندگان با موفقیت استخراج شدند'\n    History object has insufficient data, skipping item: 'تاریخچه داده کافی ندارد، در حال چشم پوشی'\n    All watched history has been successfully imported: 'همه تاریخچه تماشا با موفقیت وارد شد'\n    All watched history has been successfully exported: 'همه تاریخچه تماشا با موفقیت صادر شد'\n    Unable to read file: 'قادر به خواندن فایل نیست'\n    Unable to write file: 'امکان نوشتن فایل وجود ندارد'\n    Unknown data key: 'کلید داده ناشناخته'\n    How do I import my subscriptions?: 'چگونه دنبال شوندگان را وارد کنم؟'\n    Import Playlists: وارد کردن فهرست های پخش\n    Export Playlists: استخراج فهرست های پخش\n    All playlists has been successfully imported: همه لیست های پخش با موفقیت وارد شدند\n    All playlists has been successfully exported: همه لیست های پخش با موفقیت صادر شد\n    Playlist File: فایل لیست پخش\n    Manage Subscriptions: مدیریت اشتراک ها\n    History File: فایل تاریخچه\n    Subscription File: فایل اشتراک\n    Playlist insufficient data: داده ناکافی برای لیست پخش «{playlist}»، در حال رد شدن از مورد\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"این گزینه ویدئوها را از همه لیست های پخش به یک لیست پخش به نام \\\" مورد علاقه\\\" صادر می کند.\\nنحوه صادر کردن و وارد کردن ویدیوها در لیست پخش برای نسخه قدیمی FreeTube:\\n1. لیست های پخش خود را با فعال بودن این گزینه صادر کنید.\\n2. با استفاده از گزینه حذف تمام لیست‌های پخش در قسمت تنظیمات حریم خصوصی، تمام لیست های پخش موجود خود را حذف کنید.\\n3. نسخه قدیمی FreeTube را راه اندازی کنید و لیست های پخش صادر شده را وارد کنید.\\\"\"\n      Label: صادر‌کردن لیست‌های پخش برای نسخه های قدیمی FreeTube\n  Proxy Settings:\n    Proxy Host: میزبان پروکسی\n    Region: منطقه\n    Error getting network information. Is your proxy configured properly?: خطا در دریافت اطلاعات شبکه. آیا پروکسی شما به درستی پیکربندی شده است؟\n    Ip: آی پی\n    Country: کشور\n    Proxy Settings: پروکسی\n    Proxy Port Number: شماره پورت پروکسی\n    Test Proxy: تست پروکسی\n    Enable Tor / Proxy: پروکسی / تور را فعال کنید\n    Proxy Protocol: پروتکل پروکسی\n    City: شهر\n    Clicking on Test Proxy will send a request to: با کلیک بر روی تست پروکسی یک درخواست ارسال می شود\n    Your Info: اطلاعات شما\n    Proxy Warning: FreeTube یک پروکسی داخلی ندارد اما می‌تواند به یک پروکسی خارجی مانند پروکسی که روی دستگاه شما اجرا می‌شود مانند تور یا یک پراکسی خارجی مثل یک پراکسی SOCKS5 که توسط برخی VPN‌ها ارائه می‌شود، متصل شود. در صورت فعال بودن، مطمئن شوید که پروکسی/تور شما به درستی پیکربندی شده است، در غیر این صورت FreeTube نمی تواند هیچ داده ای را واکشی کند.\n    Proxy Username: نام کاربری پروکسی\n    Proxy Password: رمز عبور پراکسی\n  SponsorBlock Settings:\n    Skip Options:\n      Skip Option: گزینه پرش\n      Do Nothing: هیچ کاری نکن\n      Show In Seek Bar: نمایش در نوار جستجو\n      Auto Skip: پرش خودکار\n      Prompt To Skip: اعلان برای پرش\n    Enable SponsorBlock: فعال کردن محدود کردن حامی\n    SponsorBlock Settings: محدود کردن حامی\n    Notify when sponsor segment is skipped: وقتی بخش حامی رد شد اطلاع دهید\n    UseDeArrowTitles: از عنوان های ویدیویی DeArrow استفاده کنید\n    Category Color: رنگ دسته\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API URL (پیش‌فرض https://sponsor.ajay.app است)\n    UseDeArrowThumbnails: استفاده از افزونه DeArrow برای ریز‌عکسها\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': رابط آدرس سازنده ریز‌عکس DeArrow (پیش‌فرض https://dearrow-thumb.ajay.app است)\n  Parental Control Settings:\n    Hide Unsubscribe Button: پنهان کردن دکمه لغو اشتراک\n    Show Family Friendly Only: نمایش فقط دوستانه برای خانواده\n    Hide Search Bar: پنهان کردن نوار جستجو\n    Parental Control Settings: کنترل والدین\n    Hide Uploader on Watch page: مخفی کردن آپلودکننده در صفحه تماشا\n  Experimental Settings:\n    Experimental Settings: آزمایشی\n    Replace HTTP Cache: ‍کش HTTP را جایگزین کنید\n    Warning: این تنظیمات آزمایشی هستند، ممکن است هنگام فعال بودن باعث خرابی شوند. تهیه نسخه پشتیبان به شدت توصیه می شود. با مسئولیت خود استفاده کنید!\n  Password Settings:\n    Remove Password: رمز عبور را حذف کنید\n    Password Settings: رمز عبور\n    Set Password To Prevent Access: برای جلوگیری از دسترسی به تنظیمات، رمز عبور تنظیم کنید\n    Set Password: قراردادن رمز عبور\n  Password Dialog:\n    Password: کلمه عبور\n    Enter Password To Unlock: برای باز کردن قفل تنظیمات رمز عبور را وارد کنید\n  Sort Settings Sections (A-Z): مرتب‌سازی بخش‌های تنظیمات (آ-ی)\n  Return to Settings Menu: بازگشت به منوی تنظیمات\nChannel:\n  Playlists:\n    Sort Types:\n      Last Video Added: آخرین ویدیو اضافه شده\n      Oldest: قدیمی ترین\n      Newest: جدیدترین\n    Playlists: فهرست های پخش\n    This channel does not currently have any playlists: این کانال در حال حاضر هیچ لیست پخشی ندارد\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: این کانال دارای محدودیت سنی است و در حال حاضر نمی توان آن را در FreeTube مشاهده کرد.\n  Live:\n    Live: زنده\n    This channel does not currently have any live streams: این کانال در حال حاضر هیچ پخش زنده ای ندارد\n  Podcasts:\n    This channel does not currently have any podcasts: این کانال در حال حاضر هیچ پادکست ندارد\n    Podcasts: پادکست ها\n  This channel does not exist: این کانال وجود ندارد\n  This channel does not allow searching: این کانال اجازه جستجو را نمی دهد\n  Shorts:\n    This channel does not currently have any shorts: این کانال در حال حاضر هیچ شورت ندارد\n  Releases:\n    Releases: منتشر شده\n    This channel does not currently have any releases: این کانال در حال حاضر هیچ نسخه ای ندارد\n  Posts:\n    Posts: پست‌ها\n    votes: '{votes} رأی'\n    Reveal Answers: پاسخ ها را فاش کن\n    This channel currently does not have any posts: این کانال در حال حاضر هیچ پستی ندارد\n    Hide Answers: پنهان کردن پاسخ ها\n    View Full Post: مشاهده کامل پست\n    Video hidden by FreeTube: ویدیو توسط FreeTube مخفی شده\n    Viewing Posts Only Supported By Invidious: مشاهده پست ها فقط توسط Invidious پشتیبانی می شود. برای مشاهده محتوا بدون Invidious، به برگه انجمن کانال بروید.\n  Removed subscription from {count} other channel(s): اشتراک از {count} کانال(های) دیگر حذف شد\n  About:\n    Tags:\n      Search for: جستجوی '{tag}'\n      Tags: برچسب ها\n    Joined: پیوسته\n    Location: مکان\n    Details: جزئیات\n    Channel Description: توضیحات کانال\n    About: درباه\n    Featured Channels: کانال های ویژه\n  Channel Tabs: زبانه های کانال\n  Videos:\n    This channel does not currently have any videos: این کانال در حال حاضر هیچ ویدیویی ندارد\n    Sort Types:\n      Newest: جدیدترین\n      Oldest: قدیمی ترین\n      Most Popular: محبوبترین\n    Videos: ویدیوها\n  Search Channel: جستجوی کانال\n  Subscribe: اشتراک\n  Unsubscribe: لغو اشتراک\n  Your search results have returned 0 results: نتایج جستجوی شما 0 نتیجه برگردانده است\n  Channel has been removed from your subscriptions: کانال از اشتراک های شما حذف شده است\n  Added channel to your subscriptions: کانال به اشتراک های شما اضافه شد\n  Home:\n    View Playlist: نمایش لیست‌پخش\n    Home: خانه\n  Courses:\n    Courses: دوره ها\n    This channel does not currently have any courses: این کانال در حال حاضر هیچ دوره‌ای ندارد\nVideo:\n  External Player:\n    video: ویدیو\n    Unsupported Actions:\n      opening specific video in a playlist (falling back to opening the video): باز کردن یک ویدیوی خاص در یک لیست پخش (بازگشت به باز کردن ویدیو)\n      setting a playback rate: تنظیم نرخ پخش\n      opening playlists: باز کردن لیست های پخش\n      shuffling playlists: درهم ریختن لیست های پخش\n      starting video at offset: شروع ویدیو در حالت افست\n      reversing playlists: معکوس کردن لیست های پخش\n      looping playlists: در حال چرخش لیست های پخش\n    OpenInTemplate: باز کردن در {externalPlayer}\n    UnsupportedActionTemplate: '{externalPlayer} پشتیبانی نمی‌کند: {action}'\n    playlist: فهرست پخش\n    OpeningTemplate: باز کردن {videoOrPlaylist} در {externalPlayer}...\n  Published:\n    In less than a minute: در کمتر از یک دقیقه\n  Copy Invidious Link: لینک Invidious را کپی کنید\n  Previous: قبلی\n  Autoplay: پخش خودکار\n  Started streaming on: پخش جریانی را شروع کرد\n  Copy YouTube Channel Link: لینک کانال یوتیوب را کپی کنید\n  Views: دیده شده ها\n  Live Chat is currently not supported in this build.: گفتگوی زنده در حال حاضر در این ساخت پشتیبانی نمی شود.\n  Sponsor Block category:\n    sponsor: حامی\n    intro: معرفی\n    self-promotion: خود تبلیغی\n    filler: پرکننده\n    recap: روکش\n    music offtopic: موسیقی آف تاپیک\n    interaction: تعامل\n    outro: دیگر\n  Loop Playlist: حلقه پخش لیست\n  Live Now: زنده هم اکنون\n  Save Video: ذخیره ویدیو\n  Open in Invidious: در Invidious باز کنید\n  Video has been removed from your saved list: ویدیو از لیست ذخیره شده شما حذف شده است\n  Open in YouTube: در یوتیوب باز کنید\n  Next: بعدی\n  Open Channel in Invidious: کانال را در Invidious باز کنید\n  Copy Invidious Channel Link: لینک کانال Invidious را کپی کنید\n  Watched: دیده شده\n  Open Channel in YouTube: کانال را در یوتیوب باز کنید\n  Copy YouTube Link: لینک یوتیوب را کپی کنید\n  Open YouTube Embedded Player: پخش کننده جاساز یوتیوب را بار کنید\n  Shuffle Playlist: مخلوط کردن لیست پخش\n  Reverse Playlist: لیست پخش معکوس\n  Starting soon, please refresh the page to check again: به زودی شروع می شود، لطفاً برای بررسی دوباره صفحه را بازخوانی کنید\n  Live: زنده\n  Live Chat: چت زنده\n  Enable Live Chat: فعال کردن چت زنده\n  Streamed on: پخش جریانی\n  Published on: منتشر شده در\n  Video has been saved: ویدیو ذخیره شده است\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': گفتگوی زنده در حال حاضر با Invidious API پشتیبانی نمی شود. اتصال مستقیم به YouTube مورد نیاز است.\n  Premieres: نخستین نمایش\n  Upcoming: نزدیک\n  Live chat is enabled. Chat messages will appear here once sent.: چت زنده فعال است. پیام‌های گپ پس از ارسال در اینجا ظاهر می‌شوند.\n  Scroll to Bottom: به پایین بروید\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': چت زنده برای این جریان در دسترس نیست. ممکن است توسط آپلود کننده غیرفعال شده باشد.\n  Show Super Chat Comment: نمایش نظر سوپر چت\n  Copy YouTube Embedded Player Link: پیوند YouTube Embedded Player را کپی کنید\n  Remove From History: حذف از دیده شده ها\n  Video has been marked as watched: ویدیو به عنوان تماشا شده علامت گذاری شده است\n  Mark As Watched: علامت گذاری به عنوان تماشا شده\n  Video has been removed from your history: ویدیو از سابقه شما حذف شده است\n  Player:\n    You appear to be offline: به نظر می رسد آفلاین هستید.\n    Exit Theatre Mode: خروج از حالت تئاتر\n    Stats:\n      Video ID: 'شناسه ویدئو: {videoId}'\n      Media Formats: 'فرمت ویدئو: {formats}'\n      Stats: اطلاعات\n      Resolution: 'وضوح: {width}x{height}{''@''}{frameRate}'\n      Bandwidth: 'پهنای باند: {bandwidth} کیلوبیت‌بر‌ثانیه'\n      Player Dimensions: 'ابعاد پخش کننده: {width}x{height}'\n      Bitrate: 'نرخ بیت: {bitrate} کیلوبیت‌بر‌ثانیه'\n      Buffered: 'بافر: {bufferedPercentage}%'\n      Volume: 'صدا: {volumePercentage}%'\n      CodecAudio: 'کدک: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'فریم‌های رد شده: {droppedFrames} / مجموع فریم‌ها: {totalFrames}'\n      CodecsVideoAudio: 'کدک‌ها: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'کدک‌ها: {videoCodec} / {audioCodec}'\n    Take Screenshot: گرفتن عکس صفحه\n    Show Stats: نمایش اطلاعات\n    Skipped segment: بخش {segmentCategory} رد شد\n    TranslatedCaptionTemplate: '{language} (ترجمه شده از \"{originalLanguage}\")'\n    Hide Stats: مخفی کردن اطلاعات\n    Full Window: تمام‌صفحه\n    Exit Full Window: خروج از تمام‌صفحه\n    Playback will resume automatically when your connection comes back: با بازگشت اتصال شما، پخش به طور خودکار از سر گرفته می شود.\n    Audio Tracks: تراک صوتی\n    Theatre Mode: حالت تئاتر\n    Autoplay is off: پخش خودکار خاموش است\n    Autoplay is on: پخش خودکار روشن است\n  Hide Channel: مخفی‌کردن کانال\n  IP block: YouTube آدرس نشانی شما را از تماشای ویدیو مسدود کرده است. لطفاً سعی کنید به فیلترشکن یا پروکسی دیگری بروید.\n  More Options: گزینه‌های بیشتر\n  Unhide Channel: نمایش کانال\n  Unlisted: بدون لیست\n  MembersOnly: ویدیوهای مختص اعضا را نمی‌توان با FreeTube تماشا کرد زیرا به ورود Google و عضویت پولی در کانال آپلودکننده نیاز دارند.\n  AgeRestricted: ویدیوهای دارای محدودیت سنی را نمی‌توان با FreeTube تماشا کرد، زیرا نیاز به ورود به سیستم Google و استفاده از یک حساب YouTube تأیید شده برای سن دارند.\n  DeArrow:\n    Show Original Details: نمایش جزئیات اصلی\n    Show Modified Details: نمایش جزئیات اصلاح شده\n  DRMProtected: ویدیوهای محافظت شده DRM را نمی توان در FreeTube پخش کرد، زیرا به اجزای اختصاصی و منبع بسته نیاز دارند. اگر می‌خواهید این ویدیو را تماشا کنید، لطفاً آن را در وب‌سایت رسمی YouTube در یک مرورگر وب با قابلیت DRM تماشا کنید.\n  Save Watched Progress: ذخیره پیشرفت تماشا شده\n  Watched Progress Saved: پیشرفت های تماشا شده نجات یافته\nTooltips:\n  General Settings:\n    External Link Handling: \"وقتی روی پیوندی که در FreeTube باز نمی شود، روی آن کلیک می شود، رفتار پیش فرض را انتخاب کنید.\\nبه طور پیش فرض FreeTube پیوند کلیک شده را در مرورگر پیش فرض شما باز می کند.\\n\"\n    Region for Trending: منطقه گرایش‌ها به شما امکان می‌دهد ویدیوهای پرطرفدار کشوری را که می‌خواهید نمایش دهید انتخاب کنید.\n    Thumbnail Preference: تمام تصاویر کوچک در سراسر FreeTube با یک قاب از ویدیو، به جای تصویر کوچک پیش‌فرض، محو یا پنهان می‌شوند.\n    Invidious Instance: نمونه Invidious که FreeTube برای تماس های API به آن متصل می شود.\n    Fallback to Non-Preferred Backend on Failure: هنگامی که API ترجیحی شما با مشکل مواجه شود، FreeTube به طور خودکار سعی می کند از API غیر ترجیحی شما به عنوان روش بازگشتی در صورت فعال شدن استفاده کند.\n    Preferred API Backend: پس زمینه ای را انتخاب کنید که FreeTube برای به دست آوردن داده ها استفاده می کند. API محلی یک استخراج کننده داخلی است. Invidious API برای اتصال به سرور Invidious نیاز دارد.\n    Open Deep Links In New Window: نشانی هایی که به FreeTube ارسال می شوند، مانند پسوندهای مرورگر تغییر مسیر یا برهان های خط فرمان، در یک پنجره جدید باز می شوند.\n  SponsorBlock Settings:\n    UseDeArrowTitles: عناوین ویدیویی را با عناوین ارسال شده توسط کاربر از DeArrow جایگزین کنید.\n    UseDeArrowThumbnails: ریز عکسها را با ریز عکسهای DeArrow جایگزین کنید.\n  Player Settings:\n    Skip by Scrolling Over Video Player: از چرخ اسکرول برای رد شدن از ویدیو، سبک MPV استفاده کنید.\n    Scroll Playback Rate Over Video Player: در حالی که مکان نما روی ویدیو است، کلید کنترل (کلید فرمان در مک) را فشار داده و نگه دارید و چرخ ماوس را به جلو یا عقب ببرید تا سرعت پخش را کنترل کنید. کلید کنترل (کلید فرمان در مک) را فشار داده و نگه دارید و روی ماوس کلیک چپ کنید تا به سرعت به سرعت پخش پیش فرض برگردید (مگر اینکه در تنظیمات تغییر نکرده باشد).\n    Proxy Videos Through Invidious: به جای اتصال مستقیم به YouTube، به Invidious متصل می شود تا ویدیوها را ارائه دهد.\n    Default Video Format: فرمت‌های مورد استفاده هنگام پخش ویدیو را تنظیم کنید. فرمت‌های DASH می‌توانند کیفیت‌های بالاتری را پخش کنند. فرمت‌های قدیمی حداکثر به 360p محدود می‌شوند اما از پهنای باند کمتری استفاده می‌کنند. فرمت‌های صوتی فقط جریان‌های صوتی هستند.\n  Subscription Settings:\n    Fetch Feeds from RSS: وقتی این گزینه فعال باشد، FreeTube به جای روش پیش‌فرض خود برای دریافت فید اشتراک شما از RSS استفاده می‌کند. RSS سریع‌تر است و از مسدود شدن IP جلوگیری می‌کند، اما اطلاعات خاصی مانند مدت زمان ویدیو، وضعیت پخش زنده یا پست‌ها را ارائه نمی‌دهد\n    Fetch Automatically: وقتی این گزینه فعال باشد، FreeTube به طور خودکار فید اشتراک شما را در هنگام راه‌اندازی و باز شدن یک پنجره جدید دریافت می‌کند.\n  External Player Settings:\n    Custom External Player Executable: به طور پیش فرض، FreeTube فرض می کند که پخش کننده خارجی انتخاب شده را می توان از طریق متغیر محیطی PATH پیدا کرد. در صورت نیاز، یک مسیر سفارشی را می توان در اینجا تنظیم کرد.\n    DefaultCustomArgumentsTemplate: \"(پیش‌فرض: '{defaultCustomArguments}')\"\n    Ignore Warnings: اخطارها را برای زمانی که پخش کننده خارجی فعلی از عملکرد فعلی پشتیبانی نمی کند (به عنوان مثال معکوس کردن لیست های پخش و غیره) حذف کنید.\n    Custom External Player Arguments: هر برهان خط فرمان سفارشی که می خواهید به پخش کننده خارجی منتقل شود.\n    External Player: با انتخاب یک پخش کننده خارجی، نمادی برای باز کردن ویدیو (در صورت پشتیبانی لیست پخش) در پخش کننده خارجی، روی تصویر کوچک نمایش داده می شود. هشدار، تنظیمات ناخوشایند بر پخش کننده های خارجی تأثیر نمی گذارد.\n    Ignore Default Arguments: هیچ برهان پیش فرضی را به غیر از آدرس ویدیو به پخش کننده خارجی ارسال نکنید (به عنوان مثال نرخ پخش، آدرس لیست پخش و غیره). برهان های سفارشی همچنان منتقل خواهند شد.\n  Distraction Free Settings:\n    Hide Subscriptions Live: این تنظیم توسط تنظیم \"{appWideSetting}\" در سطح برنامه، در بخش \"{subsection}\" از \"{settingsSection}\" لغو می‌شود\n    Hide Channels: یک شناسه کانال وارد کنید تا همه ویدیوها، لیست‌های پخش و خود کانال در جستجو، پرطرفدار، محبوب‌ترین و توصیه‌شده‌ها ظاهر نشود. شناسه کانال وارد شده باید کاملاً مطابقت داشته باشد و شامل حروف کوچک و بزرگ باشد.\n    Hide Videos, Playlists and Channels Containing Text: یک کلمه، قطعه کلمه یا عبارت (بدون حساسیت به حروف کوچک) وارد کنید تا همه ویدیوها و فهرست‌های پخشی که عنوان اصلی آنها حاوی آن در تمام FreeTube است، پنهان شود، به استثنای تاریخچه، فهرست‌های پخش شما، و ویدیوهای داخل فهرست‌های پخش.\n    Hide Videos on Watch: ویدیوهای تماشا شده را از تب‌های ویدیوها، ویدیوهای کوتاه و ویدیوهای زنده در صفحات اشتراک و کانال پنهان می‌کند. این کار روی تب خانه در صفحات کانال تأثیری ندارد\n  Experimental Settings:\n    Replace HTTP Cache: حافظه پنهان HTTP مبتنی بر دیسک Electron را غیرفعال می کند و یک کش تصویر سفارشی در حافظه را فعال می کند. منجر به افزایش مصرف رم خواهد شد.\nSearch Bar:\n  Clear Input: پاک کردن ورودی\n  Remove: حذف\nAre you sure you want to open this link?: آیا مطمئن هستید که میخواهید این لینک را باز کنید؟\nAbout:\n  Email: پست الکترونیکی\n  Discussions: گفتگو\n  Downloads / Changelog: دانلودها / تغییرات\n  Please check for duplicates before posting: لطفاً قبل از ارسال موارد تکراری را بررسی کنید\n  Help: راهنما\n  Website: سایت\n  Credits: اعتبارات\n  Beta: بتا\n  About: درباره\n  FreeTube Wiki: ویکی فریتیوب\n  GitHub releases: نسخه های گیت هاب\n  FAQ: پرسش و پاسخ\n  room rules: قوانین اتاق\n  Translate: ترجمه\n  Blog: وبلاگ\n  Chat on Matrix: چت در ماتریکس\n  these people and projects: این افراد و پروژه ها\n  Report a problem: گزارش یک مشکل\n  GitHub issues: مشکلات گیت هاب\n  Donate: اهدا\n  Source code: کد منبع\n  Mastodon: برنامه ماستودون\n  AGPLv3: پروانه‌عمومی‌جامع‌آفرو نسخه‌3\nNew Window: پنجره جدید\nPreferences: تنظیمات\nVersion {versionNumber} is now available!  Click for more details: نسخه {versionNumber} در دسترس است!  برای مشاهده جزئیات کلیک کنید\nA new blog is now available, {blogTitle}. Click to view more: یک مطلب جدید در دسترس است, {blogTitle}. برای مشاهده بیشتر کلیک کنید\nChannels:\n  Channels: کانال ها\n  Unsubscribe Prompt: آیا مطمئنید که می‌خواهید اشتراک «{channelName}» را لغو کنید؟\n  Title: لیست کانال\n  Search bar placeholder: جستجو در کانال ها\n  Count: '{number} تعداد کانال پیدا شد.'\n  Empty: لیست کانال شما در حال حاضر خالی است.\nGlobal:\n  Videos: ویدئوها\n  Shorts: کوتاه\n  Live: زنده\n  Sort By: مرتب‌کردن بر اساس\n  Counts:\n    Subscriber Count: ۱ دنبال کننده | {count} دنبال کننده\n    View Count: ۱ بازدید | {count} بازدید\n    Watching Count: ۱ در حال تماشا | {count} در حال تماشا\n    Channel Count: ۱ کانال | {count} کانال\n    Video Count: ۱ ویدیو | {count} ویدیو\n    Like Count: 1 پسند | {count} پسند\n    Comment Count: 1 نظر | {count} نظر\n  Posts: پست‌ها\nShare:\n  Share Playlist: لیست پخش را به اشتراک بگذارید\n  Share Channel: اشتراک گذاری کانال\n  Copy Embed: کپی کردن لینک کوتاه\n  Invidious Embed URL copied to clipboard: آدرس کوتاه Invidious در کلیپ بورد کپی شد\n  YouTube URL copied to clipboard: لینک یوتیوب در کلیپ بورد کپی شد\n  Copy Link: لینک را کپی کنید\n  Share Video: اشتراک گذاری ویدیو\n  Include Timestamp: شامل مهر زمانی\n  Invidious Channel URL copied to clipboard: آدرس کانال Invidious در کلیپ بورد کپی شد\n  YouTube Embed URL copied to clipboard: لینک کوتاه یوتیوب در کلیپ بورد کپی شد\n  YouTube Channel URL copied to clipboard: لینک کانال یوتیوب در کلیپ بورد کپی شد\n  Open Link: بازکردن لینک\n  Open Embed: بازکردن لینک کوتاه\n  Invidious URL copied to clipboard: آدرس Invidious در کلیپ بورد کپی شد\nChange Format:\n  Change Media Formats: تغییر فرمت های رسانه\n  Dash formats are not available for this video: فرما های دش برای این ویدیو در دسترس نیستند\n  Use Legacy Formats: از قالب‌های قدیمی استفاده کنید\n  Audio formats are not available for this video: فرمت های صوتی برای این ویدیو موجود نیست\n  Use Dash Formats: از فرمت های دش استفاده کنید\n  Use Audio Formats: از فرمت های صوتی استفاده کنید\n  Legacy formats are not available for this video: قالب‌های قدیمی برای این ویدیو موجود نیست\nChapters:\n  Chapters: فصل\n  Key Moments: لحظات کلیدی\nHashtag:\n  This hashtag does not currently have any videos: این هشتگ در حال حاضر هیچ ویدیویی ندارد\n  Hashtag: هشتگ\nExternal link opening has been disabled in the general settings: باز کردن پیوند خارجی در تنظیمات عمومی غیرفعال شده است\nScreenshot Error: اسکرین شات ناموفق بود. {error}\n'The playlist has ended. Enable loop to continue playing': لیست پخش به پایان رسیده است. حلقه را برای ادامه بازی فعال کنید\nPlaying Next Video: پخش ویدیوی بعدی\nLoop is now disabled: حلقه اکنون غیرفعال است\nPlaying Next Video Interval: پخش ویدیوی بعدی در کمترین زمان برای لغو کلیک کنید. | پخش ویدیوی بعدی در {nextVideoInterval} ثانیه دیگر. برای لغو کلیک کنید. | پخش ویدیوی بعدی در {nextVideoInterval} ثانیه. برای لغو کلیک کنید.\nClipboard:\n  Copy failed: کپی در کلیپ بورد ناموفق بود\n  Cannot access clipboard without a secure connection: بدون اتصال ایمن نمی توان به کلیپ بورد دسترسی پیدا کرد\nComments:\n  View {replyCount} replies: مشاهده {replyCount} پاسخ\n  Pinned by: پین شده توسط\n  Member: عضو\n  Load More Comments: بارگذاری نظرات بیشتر\n  There are no comments available for this video: هیچ نظری برای این ویدیو موجود نیست\n  Comments: نظرات\n  Getting comment replies, please wait: در حال دریافت پاسخ نظرات، لطفا صبر کنید\n  There are no more comments for this video: هیچ نظر دیگری برای این ویدیو وجود ندارد\n  Hide Comments: پنهان کردن نظرات\n  Top comments: نظرات برتر\n  Show More Replies: نمایش پاسخ های بیشتر\n  Click to View Comments: برای مشاهده نظرات کلیک کنید\n  Newest first: جدیدترین اول\n  Hearted: دلی\n  There are no comments available for this post: هیچ نظری برای این پست موجود نیست\n  Subscribed: دنبال شده\nThe playlist has been reversed: لیست پخش معکوس شده است\nDefault Invidious instance has been cleared: نمونه پیش فرض Invidious پاک شده است\nProfile:\n  Your default profile has been set to {profile}: نمایه پیش فرض شما روی {profile} تنظیم شده است\n  Removed {profile} from your profiles: '{profile} از نمایه‌های شما حذف شد'\n  '{profile} is now the active profile': '{profile} اکنون نمایه فعال است'\n  '{number} selected': '{number} انتخاب شد'\n  Toggle Profile List: فهرست نمایه را تغییر دهید\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : این نمایه اصلی شماست. آیا مطمئن هستید که می خواهید کانال های انتخاب شده را حذف کنید؟ همان کانال ها در هر نمایه ای که در آن یافت می شوند حذف می شوند.\n  Profile Settings: نمایه\n  Profile Filter: فیلتر پروفایل\n  Profile Manager: مدیر پروفایل\n  Custom Color: رنگ سفارشی\n  All Channels: همه کانال ها\n  Profile Preview: پیش نمایش پروفایل\n  Create Profile: ایجاد پروفایل\n  Profile has been created: پروفایل ایجاد شده است\n  Add Selected To Profile: انتخاب شده را به پروفایل اضافه کنید\n  Profile has been updated: پروفایل به روز شد\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: آیا مطمئن هستید که می خواهید کانال های انتخاب شده را حذف کنید؟ با این کار کانال از هیچ نمایه دیگری حذف نمی شود.\n  Are you sure you want to delete this profile?: آیا مطمئن هستید که می خواهید این پروفایل را حذف کنید؟\n  Select None: انتخاب هیچ کدام\n  Delete Selected: انتخاب شده را پاک کن\n  No channel(s) have been selected: هیچ کانالی انتخاب نشده است\n  Update Profile: بروزرسانی پروفایل\n  Make Default Profile: ایجاد پروفایل پیش فرض\n  Edit Profile: ویرایش پروفایل\n  Create New Profile: ایجاد پروفایل جدید\n  Color Picker: انتخاب کننده رنگ\n  Subscription List: نمایه پیش فرض شما به نمایه اصلی شما تغییر یافته است\n  Select All: انتخاب همه\n  Delete Profile: حذف پروفایل\n  All subscriptions will also be deleted.: تمامی اشتراک ها نیز حذف خواهند شد.\n  Your profile name cannot be empty: نام پروفایل شما نمی تواند خالی باشد\n  Other Channels: کانال های دیگر\n  Your default profile has been changed to your primary profile: پروفایل پیش فرض شما به پروفایل اصلی شما تغییر یافته است\n  Profile Select: پروفایل را انتخاب کنید\n  Edit Profile Name: ویرایش نام نمایه\n  Create Profile Name: ایجاد نام نمایه\n  Profile Name: نام نمایه\n  Open Profile Dropdown: بازکردن نمایه کشویی\n  Close Profile Dropdown: بستن نمایه کشویی\nScreenshot Success: عکس‌صفحه ذخیره شد\nOk: تایید\nLoop is now enabled: حلقه اکنون فعال است\nShuffle is now enabled: Shuffle اکنون فعال است\nFalling back to Invidious API: بازگشت به Invidious API\nLocal API Error (Click to copy): خطای Local API (برای کپی کلیک کنید)\nShuffle is now disabled: Shuffle اکنون غیرفعال است\nCanceled next video autoplay: پخش خودکار ویدیوی بعدی لغو شد\nUnknown YouTube url type, cannot be opened in app: نوع URL ناشناخته YouTube، در برنامه باز نمی شود\nFalling back to Local API: بازگشت به API محلی\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: این ویدیو به دلیل عدم وجود قالب در دسترس نیست. این ممکن است به دلیل در دسترس نبودن کشور اتفاق بیفتد.\nPlaying Previous Video: پخش ویدیوی قبلی\nDefault Invidious instance has been set to {instance}: نمونه پیش‌فرض Invidious روی {instance} تنظیم شده است\nYes: بلی\nInvidious API Error (Click to copy): خطای Invidious API (برای کپی کلیک کنید)\nNo: خیر\nPlaylist:\n  Last Updated On: آخرین بروز رسانی در تاریخ\n  View Full Playlist: مشاهده لیست پخش کامل\n  Playlist: فهرست پخش\n  Sort By:\n    VideoDurationDescending: مدت (اول طولانی‌ترین)\n    VideoDurationAscending: مدت (اول کوتاه ترین)\n    VideoTitleAscending: عنوان (آ-ی)\n    DateAddedNewest: آخرین اضافه شده در ابتدا\n    DateAddedOldest: اولین اضافه شده در ابتدا\n    AuthorDescending: نویسنده (ی-آ)\n    VideoTitleDescending: عنوان (ی-آ)\n    Custom: سفارشی\n    AuthorAscending: نویسنده (آ-ی)\n    PublishedNewest: جدیدترین منتشر شده اول\n    PublishedOldest: قدیمی‌ترین منتشر شده اول\nMini Player: مینی پلیر\nUp Next: تا بعدی\nFeed:\n  Refresh Feed: تازه‌سازی {subscriptionName}\n  Feed Last Updated: '{feedName} آخرین به روز رسانی فید: {date}'\nGo to page: برو به {page}\nSearch Listing:\n  Label:\n    Subtitles: زیرنویس\n    4K: 4K\n    Closed Captions: زیرنویس‌ها\n    3D: 3 بعدی\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: جدید\nClose Banner: بستن بنر\nAge Restricted:\n  This video is age restricted: این ویدیو دارای محدودیت سنی است\n  This channel is age restricted: این کانال دارای محدودیت سنی می باشد\nSearch character limit: عبارت جستجو از حد مجاز نویسه {searchCharacterLimit} فراتر است\nYes, Delete: بله حذف شود\nYes, Restart: بله شروع دوباره\nCancel: لغو\nTrimmed input must be at least N characters long: ورودی بریده شده باید حداقل 1 کاراکتر طول داشته باشد | ورودی بریده شده باید حداقل {length} کاراکتر باشد\nTag already exists: برچسب \"{tagName}\" از قبل وجود دارد\ncheckmark: ✓\nChannel Unhidden: '{channel} از فیلتر کانال حذف شد'\nChannel Hidden: '{channel} به فیلتر کانال اضافه شد'\nYes, Open Link: بله بازکردن پیوند\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: برای دیدن تاریخچه کلیک راست کرده یا نگه دارید\nMoments Ago: لحظاتی پیش\nDisplay Label: '{label}: {value}'\nAutoplay Interruption Timer: پخش خودکار به دلیل {autoplayInterruptionIntervalHours} ساعت عدم فعالیت لغو شد\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: فلش پایین\n  arrowleft: فلش چپ\n  arrowright: ‌فلش راست\n  arrowup: فلش بالا\n  shift: شیفت\n  enter: Enter\n  plus: بعلاوه\nDescription:\n  Expand Description: '...بیشتر'\n  Collapse Description: نمایش کمتر\nKeyboardShortcutPrompt:\n  Show Keyboard Shortcuts: نمایش کلیدهای میانبر\n  Fullscreen: تغییر تمام صفحه\n  Large Rewind: 10 ثانیه به عقب برگردانید / بر اساس نرخ پخش ویدیوی فعلی، آن را به عقب برگردانید\n  Large Fast Forward: 10 ثانیه به جلو / ویدیو به جلو بر اساس نرخ پخش فعلی ویدیو\n  Mute: تغییر به بی‌صدا\n  Decrease Video Speed: بر اساس فاصله زمانی سرعت پخش ویدیو، سرعت ویدیو را کاهش دهید\n  Increase Video Speed: بر اساس فاصله زمانی سرعت پخش ویدیو، سرعت ویدیو را افزایش دهید\n  Take Screenshot: گرفتن عکس صفحه\n  Minimize Window: کوچک‌کردن پنجره\n  Close Window: بستن پنجره\n  Toggle Developer Tools: حالت ابزارهای توسعه دهنده\n  Next Frame: فریم بعدی (حین مکث)\n  Volume Up: افزایش صدا\n  Volume Down: کاهش صدا\n  Theatre Mode: تغییر حالت تئاتر\n  Full Window: تغییر تمام پنجره\n  Keyboard Shortcuts: کلیدهای میانبر\n  Sections:\n    Video:\n      Playback: ویدئو: بازپخش\n      General: ویدئو: عمومی\n    App:\n      Situational: 'برنامه: وضعیتی'\n      General: برنامه: عمومی\n  New Window: ایجاد پنجره جدید\n  Navigate to Settings: به صفحه تنظیمات بروید\n  Navigate to History: به صفحه تاریخچه بروید\n  Refresh: فید را با جدیدترین محتوا به‌روز کنید\n  Reset Zoom: بازنشانی سطح بزرگنمایی / مقیاس رابط‌کاربری\n  Zoom In: بزرگنمایی\n  Zoom Out: کوچک‌نمایی\n  Focus Search: تمرکز روی نوار جستجو\n  Search in New Window: جستجو در پنجره جدید\n  Last Frame: فریم قبلی (حین مکث)\n  Small Rewind: بر اساس فاصله زمانی معکوس و سرعت پخش فعلی ویدیو، X ثانیه به عقب برگردانید\n  Small Fast Forward: بر اساس فاصله زمانی معکوس و سرعت پخش فعلی ویدیو، X ثانیه به جلو بروید\n  Last Chapter: آخرین بخش\n  Next Chapter: بخش بعدی\n  Focus Secondary Search: روی نوار جستجوی ثانویه تمرکز کنید (در صورت وجود)\n  Captions: زیرنویس‌ها را روشن/خاموش کنید\n  Stats: نمایش آمار ویدئویی\n  History Backward: یک صفحه به عقب برگرد\n  History Forward: یک صفحه جلو بروید\n  Picture in Picture: تغییر حالت تصویر در تصویر\n  Play: تغییر به پخش/مکث\n  Skip by Tenths: رد شدن از ویدیو بر اساس درصد (3 پرش به 30٪ از کل زمان)\n  Home: رفتن به ابتدای ویدیو\n  End: رفتن به انتهای ویدیو\n  Skip to Next Video: رفتن به ویدیوی بعدی در لیست پخش یا ویدیوی پیشنهادی بعدی\n  Skip to Previous Video: رفتن به ویدیوی قبلی در لیست پخش\nshortcutLabelSeparator: ｜\n"
  },
  {
    "path": "static/locales/fi.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Tiedosto'\nQuit: 'Lopeta'\nEdit: 'Muokkaa'\nUndo: 'Kumoa'\nRedo: 'Tee uudelleen'\nCut: 'Leikkaa'\nCopy: 'Kopioi'\nPaste: 'Liitä'\nDelete: 'Poista'\nSelect all: 'Valitse kaikki'\nToggle Developer Tools: 'Kehittäjän työkalut päällä/pois'\nActual size: 'Todellinen koko'\nZoom in: 'Lähennä'\nZoom out: 'Loitonna'\nToggle fullscreen: 'Vaihda koko näyttön tilaan'\nWindow: 'Ikkuna'\nMinimize: 'Pienennä'\nClose: 'Sulje'\nBack: 'Takaisin'\nForward: 'Eteenpäin'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videot'\n  Shorts: Shortit\n  Live: Livenä\n  Posts: Postaukset\n  Sort By: Järjestä\n  Counts:\n    Video Count: 1 video | {count} videota\n    Subscriber Count: 1 tilaaja | {count} tilaajaa\n    View Count: 1 katselukerta | {count} katselukertaa\n    Watching Count: 1 katsoja | {count} katsojaa\n    Channel Count: 1 kanava | {count} kanavaa\n# Search Bar\n    Like Count: 1 tykkäys | {count} tykkäystä\n    Comment Count: 1 kommentti | {count} kommenttia\nSearch / Go to URL: 'Etsi / Mene osoitteeseen'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Hakusuodattimet'\n  Sort By:\n    Most Relevant: 'Osuvin'\n    Rating: 'Arvio'\n    Upload Date: 'Latauspäivämäärä'\n    View Count: 'Näyttökerrat'\n  Time:\n    Time: 'Aika'\n    Any Time: 'Milloin tahansa'\n    Last Hour: 'Viime tunti'\n    Today: 'Tänään'\n    This Week: 'Tällä viikolla'\n    This Month: 'Tässä kuussa'\n    This Year: 'Tänä vuonna'\n  Type:\n    Type: 'Luokka'\n    All Types: 'Kaikki luokat'\n    Videos: 'Videot'\n    Channels: 'Kanavat'\n    #& Playlists\n    Movies: Elokuvat\n  Duration:\n    Duration: 'Kesto'\n    All Durations: 'Kaikki kestot'\n    Short (< 4 minutes): 'Lyhyt (alle 4 minuuttia)'\n    Long (> 20 minutes): 'Pitkä (yli 20 minuuttia)'\n  # On Search Page\n    Medium (4 - 20 minutes): Keskikokoinen (4 - 20 minuuttia)\n  Search Results: 'Hakutulokset'\n  Fetching results. Please wait: 'Haetaan tuloksia. Odota hetki'\n  Fetch more results: 'Hae lisää tuloksia'\n# Sidebar\n  There are no more results for this search: Ei lisää tuloksia tällä haulla\n  Features:\n    Subtitles: Teksitykset\n    Creative Commons: Creative Commons\n    3D: 3D\n    4K: 4K\n    HD: HD\n    Location: Sijainti\n    HDR: HDR\n    Live: Live\n    Features: Ominaisuudet\n    VR180: VR180\n    360 Video: 360 Video\n  Clear Filters: Tyhjennä suodattimet\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Tilaukset'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Sinulla ei juuri nyt ole tilauksia. Tilaa kanavia nähdäksesi ne täällä.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Tällä profiililla on paljon tilauksia.  Pakotetaan RSS nopeuden rajoittamisen välttämiseksi\n  Load More Videos: Lataa lisää videoita\n  Error Channels: Kanavat, joissa on virheitä\n  Empty Channels: Tilaamillasi kanavilla ei ole videoita tällä hetkellä.\n  Disabled Automatic Fetching: Olet poistanut käytöstä tilausten automaattisen noutamisen. Virkistä tilaukset nähdäksesi ne täällä.\n  Subscriptions Tabs: Tilaukset-välilehdet\n  All Subscription Tabs Hidden: Kaikki tilausvälilehdet on piilotettu. Jos haluat nähdä sisällön täällä, poista joitakin välilehtiä ”{settingsSection}”-osion ”{settingsSection}”-osion ”{subsection}”-välilehdistä.\n  Load More Posts: Lataa lisää julkaisuja\n  Empty Posts: Tilaamillasi kanavilla ei tällä hetkellä ole julkaisuja.\nTrending:\n  Trending: 'Nousussa'\n  Trending Tabs: Nousussa olevat välilehdet\n  Gaming: Pelaaminen\n  Sports: Urheilu\nMost Popular: 'Suosituimmat'\nPlaylists: 'Soittolistat'\nUser Playlists:\n  Your Playlists: 'Omat soittolistat'\n  Search bar placeholder: Etsi soittolistoja\n  Empty Search Message: Tällä soittolistalla ei ole hakuasi vastaavia videoita\n  Sort By:\n    NameAscending: A-Ö\n    NameDescending: Ö-A\n    LatestCreatedFirst: Viimeksi luotu\n    EarliestCreatedFirst: Ensin luotu\n    LatestUpdatedFirst: Viimeksi päivitetty\n    EarliestUpdatedFirst: Ensin päivitetty\n    LatestPlayedFirst: Viimeksi toistettu\n    EarliestPlayedFirst: Ensin toistettu\n  Move Video Up: Siirrä video ylös\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: Video on poistettu\n      Playlist name cannot be empty. Please input a name.: Soittolistan nimi ei voi olla tyhjä. Anna soittolistalle nimi.\n      Playlist has been updated.: Soittolista on päivitetty.\n      \"{videoCount} video(s) have been removed\": 1 video on poistettu | {videoCount} videota on poistettu\n      This video cannot be moved up.: Tätä videota ei voi siirtää ylös.\n      This video cannot be moved down.: Tätä videota ei voi siirtää alas.\n      This playlist is protected and cannot be removed.: Tämä soittolista on suojattu ja sitä ei voi poistaa.\n      Playlist {playlistName} has been deleted.: Soittolista {playlistName} on poistettu.\n      This playlist does not exist: Soittolistaa ei ole olemassa\n      There was an issue with updating this playlist.: Tätä soittolistaa päivittäessä ilmeni ongelma.\n      There was a problem with removing this video: Tämän videon poistamisessa oli ongelmia\n      This playlist is now used for quick bookmark: Tätä soittolistaa käytetään nyt nopeaa kirjanmerkkiä varten\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Tätä soittolistaa käytetään nyt pikakirjanmerkkinä {oldPlaylistName}:n sijaan. Klikkaa tästä peruuttaaksesi\n      There were no videos to remove.: Poistettavia videoita ei ollut.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Joitakin soittolistan videoita ei ole vielä ladattu. Klikkaa tästä kopioidaksesi joka tapauksessa.\n      This playlist has a video with a duration error: Tämä soittolista sisältää vähintään yhden videon, jolla ei ole kestoa, se lajitellaan ikään kuin sen kesto olisi nolla.\n      Video has been removed. Click here to undo.: Video on poistettu. Klikkaa tästä peruuttaaksesi.\n      This playlist is already being used for quick bookmark.: Tätä soittolistaa käytetään jo nopeaan kirjanmerkkiin.\n      Reverted to use {oldPlaylistName} for quick bookmark: Palautettu käyttämään {oldPlaylistName} nopeaa kirjanmerkkiä varten\n    Search for Videos: Etsi videot\n  Move Video Down: Siirrä video alas\n  Remove from Playlist: Poista soittolistalta\n  Playlist Name: Soittolistan nimi\n  Playlist Description: Soittolistan kuvaus\n  Edit Playlist Info: Muokkaa soittolistan tietoja\n  Copy Playlist: Kopioi soittolista\n  This playlist currently has no videos.: Tällä soittolistalla ei ole videoita.\n  Delete Playlist: Poista soittolista\n  Are you sure you want to delete this playlist? This cannot be undone: Haluatko varmasti poistaa tämän soittolistan? Toimintoa ei voi perua.\n  You have no playlists. Click on the create new playlist button to create a new one.: Sinulla ei ole soittolistoja. Luo uusi soittolista napsauttamalla \"Luo uusi soittolista\".\n  Create New Playlist: Luo uusi soittolista\n  Add to Playlist: Lisää soittolistalle\n  Save Changes: Tallenna muutokset\n  Cancel: Peruuta\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} valittu'\n    Save: Tallenna\n    Toast:\n      You haven't selected any playlist yet.: Et ole valinnut yhtäkään soittolistaa.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Added {count} Times: Jo lisätty | Lisätty {count} kertaa\n    Search in Playlists: Haku soittolistoista\n    Select a playlist to add your N videos to: Valitse soittoluettelo, johon haluat lisätä videosi | Valitse soittoluettelo, johon haluat lisätä {videoCount}-videot\n    Allow Adding Duplicate Video(s): Salli päällekkäisten videoid(en) lisääminen\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videoita lisätään'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Jo lisätyt videot'\n  CreatePlaylistPrompt:\n    New Playlist Name: Uuden soittolistan nimi\n    Create: Luo\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Samalla nimellä on jo olemassa soittolista. Valitse eri nimi.\n      Playlist {playlistName} has been successfully created.: Soittolista {playlistName} on luotu.\n      There was an issue with creating the playlist.: Soittolistaa luotaessa ilmeni ongelma.\n  Add to Favorites: Lisää soittolistaan {playlistName}\n  Remove from Favorites: Poista soittolistalta {playlistName}\n  Remove Watched Videos: Poista katsotut videot\n  Export Playlist: Vie tämä soittolista\n  The playlist has been successfully exported: Soittolista viety onnistuneesti\n  Quick Bookmark Enabled: Pikakirjanmerkki käytössä\n  Playlists with Matching Videos: Soittolistat, joissa on vastaavia videoita\n  Enable Quick Bookmark With This Playlist: Ota nopea kirjanmerkki käyttöön tällä soittolistalla\n  Remove Duplicate Videos: Poista päällekkäiset videot\n  TotalTimePlaylist: 'Kokonaisaika: {duration}'\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Haluatko varmasti poistaa 1 päällekkäisen videon tästä soittolistasta? Tätä ei voi peruuttaa. | Haluatko varmasti poistaa {playlistItemCount} päällekkäiset videot tästä soittolistasta? Tätä ei voi peruuttaa.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Haluatko varmasti poistaa 1 katsotun videon tästä soittolistasta? Tätä ei voi peruuttaa. | Haluatko varmasti poistaa {playlistItemCount} katsotut videot tästä soittolistasta? Tätä ei voi peruuttaa.\n  Cannot delete the quick bookmark target playlist.: Pikakirjanmerkin kohdesoittolistaa ei voi poistaa.\nHistory:\n  # On History Page\n  History: 'Historia'\n  Watch History: 'Katseluhistoria'\n  Your history list is currently empty.: Historiasi on tällä hetkellä tyhjä.\n  Search bar placeholder: Etsi historiasta\n  Empty Search Message: Historiassasi ei ole videoita, jotka vastaavat hakuasi\n  Case Sensitive Search: kirjainkoolla erotteleva haku\n  DateOldestHistory: Varhaisin katsottu ensin\n  DateNewestHistory: Viimeisimpänä katsottu ensin\nSettings:\n  # On Settings Page\n  Settings: 'Asetukset'\n  General Settings:\n    General Settings: 'Yleistä'\n    Fallback to Non-Preferred Backend on Failure: 'Vikatilanteessa palaa toissijaiseen taustaohjelmaan'\n    Enable Search Suggestions: 'Salli hakuehdotukset'\n    Default Landing Page: 'Oletusaloitussivu'\n    Locale Preference: 'Maa-asetus'\n    Preferred API Backend:\n      Preferred API Backend: 'Ensisijainen API-taustaohjelma'\n      Local API: 'Paikallinen API'\n      Invidious API: 'Invidious-käyttöliittymä'\n    Video View Type:\n      Video View Type: 'Videonäkymän asettelu'\n      Grid: 'Ruudukko'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Pikkukuvan valinta'\n      Default: 'Oletus'\n      Beginning: 'Alku'\n      Middle: 'Puoliväli'\n      End: 'Loppu'\n      Hidden: Piilotettu\n      Blur: Sumennettu\n    Region for Trending: 'Nousussa-sivun alue'\n        #! List countries\n    Check for Latest Blog Posts: Tarkista tuoreimmat blogimerkinnät\n    Check for Updates: Tarkista päivitykset\n    View all Invidious instance information: Invidious instancen tiedot\n    System Default: Järjestelmän oletus\n    Clear Default Instance: Tyhjennä oletuspalveluntarjoaja\n    Set Current Instance as Default: Aseta nykyinen palveluntarjoaja oletukseksi\n    Current instance will be randomized on startup: Nykyinen palveluntarjoaja valitaan satunnaisesti käynnistyksen yhteydessä\n    No default instance has been set: Oletuspalveluntarjoajaa ei ole määritelty\n    The currently set default instance is {instance}: Nykyinen oletuspalveluntarjoaja on {instance}\n    Current Invidious Instance: Nykyinen Invidious-palveluntarjoaja\n    External Link Handling:\n      No Action: Ei toimintoa\n      Ask Before Opening Link: Kysy ennen linkin avaamista\n      Open Link: Avaa linkki\n      External Link Handling: Ulkoisten linkkien käsittely\n    Auto Load Next Page:\n      Label: Lataa seuraava sivu automaattisesti\n      Tooltip: Lataa lisäsivut ja kommentit automaattisesti.\n    Open Deep Links In New Window: Avaa FreeTube uudelleenohjatut URL-osoitteet uudessa ikkunassa\n  Theme Settings:\n    Theme Settings: 'Teema'\n    Match Top Bar with Main Color: 'Käytä pääväriä yläpalkissa'\n    Base Theme:\n      Base Theme: 'Perusteema'\n      Black: 'Musta'\n      Dark: 'Tumma'\n      Light: 'Vaalea'\n      Dracula: 'Dracula-teema'\n      System Default: Järjestelmän oletusarvo\n      Catppuccin Mocha: Catppuccin Mocha -teema\n      Hot Pink: Pinkki\n      Pastel Pink: Pastellinpinkki\n      Solarized Light: Solarized Valo\n      Solarized Dark: Solarized tumma\n      Nordic: Pohjoismainen\n      Catppuccin Frappe: Catppuccino Frappe\n      Gruvbox Dark: Gruvbox Tumma\n      Gruvbox Light: Gruvbox Valo\n    Main Color Theme:\n      Main Color Theme: 'Pääväriteema'\n      Red: 'Punainen'\n      Pink: 'Vaaleanpunainen'\n      Purple: 'Purppura'\n      Deep Purple: 'Syvä purppura'\n      Indigo: 'Indigonsininen'\n      Blue: 'Sininen'\n      Light Blue: 'Vaaleansininen'\n      Cyan: 'Syaani'\n      Teal: 'Sinivihreä'\n      Green: 'Vihreä'\n      Light Green: 'Vaaleanvihreä'\n      Lime: 'Limenvihreä'\n      Yellow: 'Keltainen'\n      Amber: 'Meripihka'\n      Orange: 'Oranssi'\n      Deep Orange: 'Syvä oranssi'\n      Dracula Cyan: 'Dracula Syaani'\n      Dracula Green: 'Dracula Vihreä'\n      Dracula Orange: 'Dracula Oranssi'\n      Dracula Pink: 'Dracula Vaaleanpunainen'\n      Dracula Purple: 'Dracula Purppura'\n      Dracula Red: 'Dracula Punainen'\n      Dracula Yellow: 'Dracula Keltainen'\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky -teema\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal -teema\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink -teema\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve -teema\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire -teema\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater -teema\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo -teema\n      Catppuccin Mocha Red: Catppuccin Mocha Red -teema\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon -teema\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach -teema\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow -teema\n      Catppuccin Mocha Green: Catppuccin Mocha Green -teema\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue -teema\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender -teema\n    Secondary Color Theme: 'Toissijainen väriteema'\n        #* Main Color Theme\n    UI Scale: Käyttöliittymän koko\n    Disable Smooth Scrolling: Poista tasainen vieritys käytöstä\n    Expand Side Bar by Default: Laajenna sivupalkki oletusarvoisesti\n    Hide Side Bar Labels: Piilota sivupalkin nimikkeet\n    Hide FreeTube Header Logo: Piilota FreeTube-otsikkologo\n  Player Settings:\n    Player Settings: 'Soittimen asetukset'\n    Play Next Video: 'Toista seuraava video'\n    Turn on Subtitles by Default: 'Ota tekstitys käyttöön oletusarvoisesti'\n    Autoplay Videos: 'Toista videot automaattisesti'\n    Proxy Videos Through Invidious: 'Välitä videot Invidiousin kautta'\n    Autoplay Playlists: 'Toista soittolistat automaattisesti'\n    Enable Theatre Mode by Default: 'Ota teatteritila käyttöön oletusarvoisesti'\n    Default Volume: 'Äänenvoimakkuuden oletusarvo'\n    Default Playback Rate: 'Toiston oletusnopeus'\n    Default Video Format:\n      Default Video Format: 'Videon oletusmuoto'\n      Dash Formats: 'DASH-formaatit'\n      Legacy Formats: 'Vanhat formaatit'\n      Audio Formats: 'Ääniformaatit'\n    Default Quality:\n      Default Quality: 'Laadun oletusarvo'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4K'\n      8k: '8K'\n    Next Video Interval: Seuraavan videon väli\n    Display Play Button In Video Player: Näytä toista-nappula videotoistimessa\n    Scroll Volume Over Video Player: Säädä äänenvoimakkuutta vierittämällä videon päällä\n    Fast-Forward / Rewind Interval: Pikakelauksen intervalli\n    Scroll Playback Rate Over Video Player: Toistonopeuden selaaminen videosoittimessa\n    Max Video Playback Rate: Videon maksimitoistonopeus\n    Video Playback Rate Interval: Videon toistonopeuden aikaväli\n    Screenshot:\n      Error:\n        Forbidden Characters: Kielletyt merkit\n        Empty File Name: Tyhjä tiedostonimi\n      Enable: Ota kuvakaappaus käyttöön\n      Folder Label: Kuvakaappauskansio\n      Folder Button: Valitse kansio\n      Format Label: Kuvakaappauksen muoto\n      Quality Label: Kuvakaappauksen laatu\n      File Name Label: Tiedostonimimalli\n      Ask Path: Kysy tallennuskansiota\n      File Name Tooltip: Voit käyttää allanäkyviä muuttujia. %Y Vuosi 4 numeroa. %M Kuukausi 2 numeroa. %D Päivä 2 numeroa. %H Tunnit 2 numeroa. %N Minuutit 2 numeroa. %S Sekunnit 2 numeroa. %T Millisekunnit 3 numeroa. %s Videosekunnit. %t Videon Millisekunnit 3 numeroa. %i Videotunniste eli ID.\n    Enter Fullscreen on Display Rotate: Siirry koko näytön tilaan näyttöä kiertäessä\n    Skip by Scrolling Over Video Player: Ohita vierittämällä videosoittimen yli\n  Subscription Settings:\n    Subscription Settings: 'Tilausasetukset'\n    Fetch Feeds from RSS: Nouda RSS-syöte\n    Fetch Automatically: Nouda syöte automaattisesti\n    'Limit the number of videos displayed for each channel': Rajoita kanavilta näytettyjen videoiden määrää\n    Confirm Before Unsubscribing: Vahvista ennen tilauksen peruuttamista\n  Privacy Settings:\n    Watch history has been cleared: Katseluhistoria poistettiin\n    Are you sure you want to remove your entire watch history?: Haluatko varmasti poistaa katseluhistorian?\n    Remove Watch History: Poista katseluhistoria\n    Search cache has been cleared: Hakuvälimuisti tyhjennettiin\n    Are you sure you want to clear out your search cache?: Haluatko varmasti tyhjentää hakuvälimuistin?\n    Clear Search Cache: Tyhjennä hakuvälimuisti\n    Save Watched Progress: Tallenna tilanne katsotuissa\n    Remember History: Muista historia\n    Privacy Settings: Yksityisyysasetukset\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Haluatko varmasti poistaa kaikki tilaukset ja profiilit?  Tätä toimintoa ei voi perua.\n    Remove All Subscriptions / Profiles: Poista kaikki tilaukset / profiilit\n    Save Watched Videos With Last Viewed Playlist: Tallenna katsotut videot Viimeksi katsottujen soittolistalle\n    Remove All Playlists: Poista kaikki soittolistat\n    All playlists have been removed: Kaikki soittolistat on poistettu\n    Are you sure you want to remove all your playlists?: Haluatko varmasti poistaa kaikki soittolistat?\n    Search history and cache have been cleared: Hakuhistoria ja välimuisti on tyhjennetty\n    Are you sure you want to clear out your search history and cache?: Haluatko varmasti poistaa hakuhistoriasi ja välimuistin tiedot?\n    Clear Search History and Cache: Tyhjennä hakuhistoria ja välimuisti\n    Remember Search History: Muista hakuhistoria\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Älä koskaan\n        Auto: Automaattisesti\n        Semi-auto: Puoliautomaattisesti\n  Data Settings:\n    How do I import my subscriptions?: Kuinka voin tuoda tilaukseni?\n    Unknown data key: Tuntematon data-avain\n    Unable to write file: Tiedostoa ei voida kirjoittaa\n    Unable to read file: Tiedostoa ei voida lukea\n    All watched history has been successfully exported: Kaikki katsottujen historia on viety onnistuneesti\n    All watched history has been successfully imported: Kaikki katsottujen historia on tuotu onnistuneesti\n    History object has insufficient data, skipping item: Historiakohteen tiedot ovat puuttelliset, ohitetaan kohde\n    Subscriptions have been successfully exported: Tilaukset on viety onnistuneesti\n    Invalid history file: Puutteellinen historiatiedosto\n    Invalid subscriptions file: Puutteellinen tilaustiedosto\n    All subscriptions have been successfully imported: Kaikki tilaukset on tuotu onnistuneesti\n    All subscriptions and profiles have been successfully imported: Kaikki tilaukset ja profiilit on tuotu onnistuneesti\n    Profile object has insufficient data, skipping item: Profiilikohteen tiedot ovat puutteelliset, ohitetaan kohde\n    Export History: Vie historia\n    Import History: Tuo historia\n    Export NewPipe: Vie NewPipe-tilaukset\n    Export YouTube: Vie YouTube-tilaukset\n    Export FreeTube: Vie FreeTube-tilaukset\n    Export Subscriptions: Vie tilaukset\n    Import Subscriptions: Tuo tilaukset\n    Select Export Type: Valitse Viennin tyyppi\n    Data Settings: Data-asetukset\n    Manage Subscriptions: Hallitse tilauksia\n    All playlists has been successfully imported: Kaikki soittolistat on onnistuneesti tuotu\n    All playlists has been successfully exported: Kaikki soittolistat on viety onnistuneesti\n    Import Playlists: Tuo soittolistoja\n    Export Playlists: Vie soittolistoja\n    Playlist insufficient data: Riittämätön määrä tietoja ”{playlist}” -soittolistalle, ohitetaan kohde\n    Playlist File: Soittolistatiedosto\n    History File: Historia-tiedosto\n    Subscription File: Tilaustiedosto\n    Export Playlists For Older FreeTube Versions:\n      Label: Vie soittolistat FreeTuben vanhempiin versioihin\n  Distraction Free Settings:\n    Hide Live Chat: Piilota Live-keskustelu\n    Hide Popular Videos: Piilota suositut videot\n    Hide Trending Videos: Piilota nousevat videot\n    Hide Recommended Videos: Piilota suositellut videot\n    Hide Comment Likes: Piilota kommenttien tykkäykset\n    Hide Channel Subscribers: Piilota kanavan tilaajat\n    Hide Video Likes And Dislikes: Piilota videon tykkäykset\n    Distraction Free Settings: Häiriötön\n    Hide Video Views: Piilota videon katselukerrat\n    Hide Active Subscriptions: Piilota aktiiviset tilaukset\n    Hide Playlists: Piilota soittolistat\n    Hide Comments: Piilota kommentit\n    Hide Video Description: Piilota videon kuvaus\n    Hide Live Streams: Piilota suorat lähetykset\n    Hide Sharing Actions: Piilota jakamistoiminnot\n    Hide Videos on Watch: 'Piilota katsotut videot'\n    Hide Chapters: Piilota kappaleet\n    Hide Channels: Piilota videot kanavilta\n    Hide Upcoming Premieres: Piilota tulevat ensiesitykset\n    Hide Channels Placeholder: Kanavan tunnus\n    Display Titles Without Excessive Capitalisation: Näytä otsikot ilman liiallista isoja kirjaimia\n    Hide Featured Channels: Piilota esillä olevat kanavat\n    Hide Channel Playlists: Piilota kanavan soittolistat\n    Hide Channel Shorts: Piilota kanavan lyhytelokuvat\n    Sections:\n      Side Bar: Sivupalkki\n      Channel Page: Kanavan sivu\n      Watch Page: Katso -sivu\n      General: Yleiset\n      Subscriptions Page: Tilaukset-sivu\n    Hide Channel Releases: Piilota kanavajulkaisut\n    Hide Channel Podcasts: Piilota kanavan podcastit\n    Hide Subscriptions Videos: Piilota tilausvideot\n    Hide Subscriptions Live: Piilota tilausten livet\n    Hide Profile Pictures in Comments: Piilota profiilikuvat kommenteissa\n    Hide Channels Invalid: Annettu kanavatunnus oli virheellinen\n    Hide Subscriptions Shorts: Piilota tilattujen kanavien Shorts-videot\n  The app needs to restart for changes to take effect. Restart and apply change?: Sovellus on käynnistettävä uudelleen, jotta muutokset tulevat voimaan. Käynnistetäänkö uudelleen?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Virhe verkkoyhteyden tietojen saamisessa. Onko välityspalvelin määritetty oikein?\n    Ip: Ip-osoite\n    Your Info: Tietosi\n    Country: Valtio\n    Test Proxy: Testaa välityspalvelin\n    Region: Alue\n    City: Kaupunki\n    Proxy Port Number: Välityspalvelimen portin numero\n    Proxy Host: Välityspalvelin\n    Proxy Settings: Välityspalvelimen asetukset\n    Enable Tor / Proxy: Ota käyttöön Tor / välityspalvelin\n    Proxy Protocol: Välityspalvelimen protokolla\n    Clicking on Test Proxy will send a request to: Napsauttamalla testaa välityspalvelinta lähettää pyynnön kohteeseen\n    Proxy Warning: FreeTubella ei ole sisäänrakennettua välityspalvelinta, mutta voit yhdistää ulkoisella välityspalvelimella, kuten Tor:lla tai jonkin VPN-tarjoajan Socks5:llä.\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Ilmoita sponsoriosuuden yli hypättäessä\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock-sponsorieston API-ohjelmointirajapinnan Url-osoite (vakio-osoite on https://sponsor.ajay.app)\n    Enable SponsorBlock: Kytke SponsorBlock-sponsoriesto päälle\n    SponsorBlock Settings: SponsorBlock-sponsorieston asetukset\n    Skip Options:\n      Skip Option: Ohita vaihtoehto\n      Auto Skip: Automaattinen ohitus\n      Show In Seek Bar: Näytä hakupalkissa\n      Do Nothing: Älä tee mitään\n      Prompt To Skip: Ehdota ohittamista\n    Category Color: Luokan väri\n    UseDeArrowTitles: Käytä DeArrow video-otsikoita\n    UseDeArrowThumbnails: Käytä DeArrow pikkukuvia\n  External Player Settings:\n    Custom External Player Arguments: Omavalintaisen ulkoisen toisto-ohjelman määritykset\n    Custom External Player Executable: Omavalintaisen ulkoisen toisto-ohjelman ajettava tiedosto\n    Ignore Unsupported Action Warnings: Sivuuta ei-tuettujen toimintojen varoitukset\n    External Player: Ulkoinen toisto-ohjelma\n    External Player Settings: Ulkoisen videontoisto-ohjelman asetukset\n    Players:\n      None:\n        Name: Ei mitään\n  Parental Control Settings:\n    Parental Control Settings: Perheasetukset\n    Hide Unsubscribe Button: Piilota Peruuta tilaus -paninike\n    Show Family Friendly Only: Näytä vain koko perheelle sopiva sisältö\n    Hide Search Bar: Piilota hakupalkki\n  Experimental Settings:\n    Experimental Settings: Kokeelliset asetukset\n    Warning: Nämä asetukset ovat kokeellisia ja ne voivat aiheuttavat kaatumisia, kun ne ovat käytössä. Varmuuskopioiden tekeminen on erittäin suositeltavaa. Käytä omalla vastuullasi!\n    Replace HTTP Cache: Korvaa HTTP-välimuisti\n  Password Dialog:\n    Password: Salasana\n    Enter Password To Unlock: Syötä salasana avataksesi asetukset\n  Password Settings:\n    Set Password To Prevent Access: Aseta salasana estääksesi pääsyn asetuksiin\n    Password Settings: Salasana-asetukset\n    Set Password: Aseta salasana\n    Remove Password: Poista salasana\n  Sort Settings Sections (A-Z): Järjestä asetusosio (A-Ö)\n  Return to Settings Menu: Palaa asetusvalikkoon\nAbout:\n  #On About page\n  About: 'Tietoja'\n  #& About\n#On Channel Page\n  GitHub issues: GitHub-ongelmat\n  Report a problem: Ilmoita ongelmasta\n  FAQ: UKK\n  Blog: Blogi\n  Email: Sähköposti\n  Chat on Matrix: Matrix\n  these people and projects: nämä henkilöt ja projektit\n  room rules: huoneen säännöt\n  Please check for duplicates before posting: Tarkista kopioiden varalta ennen julkaisua\n  Website: Verkkosivusto\n  Mastodon: Mastodon\n  Translate: Käännös\n  Credits: Kiitettävää\n  Help: Apua\n  GitHub releases: GitHub-julkaisut\n  Downloads / Changelog: Lataukset/muutosloki\n  Beta: Beta\n  FreeTube Wiki: FreeTuben wiki\n  Donate: Lahjoita\n  Source code: Lähdekoodi\n  Discussions: Keskustelut\n  AGPLv3: AGPLv3\nChannel:\n  Subscribe: 'Tilaa'\n  Unsubscribe: 'Peruuta tilaus'\n  Search Channel: 'Etsi kanavalta'\n  Your search results have returned 0 results: 'Hakusi on tuottanut 0 tulosta'\n  Videos:\n    Videos: 'Videot'\n    This channel does not currently have any videos: 'Tällä kanavalla ei juuri nyt ole yhtään videota'\n    Sort Types:\n      Newest: 'Uusimmat'\n      Oldest: 'Vanhimmat'\n      Most Popular: 'Suosituimmat'\n  Playlists:\n    Playlists: 'Soittolistat'\n    This channel does not currently have any playlists: 'Tällä kanavalla ei juuri nyt ole yhtään soittolistaa'\n    Sort Types:\n      Last Video Added: 'Viimeksi lisätty video'\n      Newest: 'Uusin'\n      Oldest: 'Vanhin'\n  About:\n    About: 'Tietoja'\n    Channel Description: 'Kanavan kuvaus'\n    Featured Channels: 'Suositellut kanavat'\n    Tags:\n      Tags: Tunnisteet\n      Search for: Etsi ”{tag}”\n    Location: Sijainti\n    Joined: Liittynyt\n    Details: Yksityiskohdat\n  Added channel to your subscriptions: Kanava on lisätty tilauksiisi\n  Removed subscription from {count} other channel(s): Poistettu tilaus {count} muulta kanavalta\n  Channel has been removed from your subscriptions: Kanava on poistettu tilauksistasi\n  Channel Tabs: Kanavavälilehdet\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Tämä kanava on ikärajoitettu, eikä sitä voi tällä hetkellä katsoa FreeTubessa.\n  This channel does not exist: Tätä kanavaa ei ole olemassa\n  This channel does not allow searching: Tämä kanava ei salli etsintää\n  Posts:\n    This channel currently does not have any posts: Tällä kanavalla ei ole tällä hetkellä mitään\n    Reveal Answers: Näytä vastaukset\n    Hide Answers: Piilota vastaukset\n    votes: '{votes} ääntä'\n    Video hidden by FreeTube: Video on piilotettu FreeTuben toimesta\n  Live:\n    Live: Livenä\n    This channel does not currently have any live streams: Tällä kanavalla ei ole tällä hetkellä yhtään suoraa lähetystä\n  Shorts:\n    This channel does not currently have any shorts: Tällä kanavalla ei juuri nyt ole lyhyitä\n  Podcasts:\n    Podcasts: Podcastit\n    This channel does not currently have any podcasts: Tällä kanavalla ei ole yhtäkään podcastia\n  Releases:\n    Releases: Julkaisut\n    This channel does not currently have any releases: Tällä kanavalla ei ole yhtäkään julkaisua\nVideo:\n  Open in YouTube: 'Avaa YouTubessa'\n  Copy YouTube Link: 'Kopioi YouTube-linkki'\n  Open YouTube Embedded Player: 'Avaa upotettu YouTube-soitin'\n  Copy YouTube Embedded Player Link: 'Kopioi upotetun YouTube-soittimen linkki'\n  Open in Invidious: 'Avaa Invidious'\n  Copy Invidious Link: 'Kopioi Invidious-linkki'\n  Views: 'Katsomiskertaa'\n  Watched: 'Katsotut'\n  # As in a Live Video\n  Live: 'Suora'\n  Live Now: 'Suorana nyt'\n  Live Chat: 'Live-keskustelu'\n  Enable Live Chat: 'Ota live-keskustelu käyttöön'\n  Live Chat is currently not supported in this build.: 'Live-keskustelua ei tueta tässä versiossa.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Live-keskustelu on käytössä. Lähetetyt viestit näkyvät tässä.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Live-keskustelua ei tueta nykyisessä Invidious API:ssa. Suora yhteys Youtubeen vaaditaan.'\n  Published:\n    In less than a minute: Alle minuutin kuluessa\n  Published on: 'Julkaistu'\n#& Videos\n  Video has been removed from your history: Video on poistettu historiastasi\n  Video has been marked as watched: Video on merkitty katsotuksi\n  Remove From History: Poista historiasta\n  Mark As Watched: Merkitse katsotuksi\n  Autoplay: Automaattinen toisto\n  Previous: Edellinen\n  Next: Seuraava\n  Reverse Playlist: Käänteinen soittolista\n  Shuffle Playlist: Sekoita soittolistaa\n  Loop Playlist: Kierrätä soittolistaa\n  Starting soon, please refresh the page to check again: Hetki pieni, päivitä sivu uudelleen\n  Copy Invidious Channel Link: Kopio kanavan Invidious-linkki\n  Open Channel in Invidious: Avaa kanava Invidiousissa\n  Copy YouTube Channel Link: Kopioi YouTube-kanavan linkki\n  Open Channel in YouTube: Avaa kanava YouTubessa\n  Started streaming on: Lähetys alkanut\n  Streamed on: Lähetetty\n  External Player:\n    Unsupported Actions:\n      looping playlists: toistetaan soittoluettelot uudelleen jatkuvasti\n      shuffling playlists: sekoitetaan soittoluettelot\n      reversing playlists: käänteistetään soittoluettelot\n      opening specific video in a playlist (falling back to opening the video): avataan tietty video soittoluettelossa (avataan video taaksepäin mallintaen)\n      opening playlists: avataan soittoluettelot\n      setting a playback rate: asetetaan toiston suhde\n      starting video at offset: aloitetaan video poikkeamassa\n    UnsupportedActionTemplate: '{externalPlayer} ei tue: {action}'\n    OpeningTemplate: Avataan {videoOrPlaylist} täten {externalPlayer}...\n    playlist: soittoluettelo\n    video: video\n    OpenInTemplate: Avaa käyttäen {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Musiikki aihepiirin ulkopuolelta\n    interaction: Kanssakäyminen\n    self-promotion: Itsepromootio\n    outro: Loppu\n    intro: Alku\n    sponsor: Sponsori\n    recap: Kertaus\n    filler: Täyte\n  Video has been removed from your saved list: Video poistettiin tallennettujen videoiden luettelostasi\n  Video has been saved: Video on tallennettu\n  Save Video: Tallenna video\n  Premieres: Ensilähetykset\n  Show Super Chat Comment: Näytä Super Chat -kommentti\n  Scroll to Bottom: Vieritä Alaspäin\n  Upcoming: Tuleva\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Live-chat ei ole käytettävissä tässä suoratoistossa. Lataaja on saattanut poistaa sen käytöstä.\n  Unhide Channel: Näytä kanava\n  Hide Channel: Piilota kanava\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Näytä koko soittolista'\n  Last Updated On: 'Viimeksi päivitetty'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Soittolista\n  Sort By:\n    DateAddedOldest: Ensin lisätty ensin\n    DateAddedNewest: Viimeksi lisätty ensin\n    AuthorAscending: Tekijä (A-Ö)\n    AuthorDescending: Tekijä (Ö-A)\nChange Format:\n  Change Media Formats: 'Vaihda videoformaattia'\n  Use Dash Formats: 'Käytä DASH-formaatteja'\n  Use Legacy Formats: 'Käytä Legacy-formaatteja'\n  Use Audio Formats: 'Käytä ääniformaatteja'\n  Audio formats are not available for this video: Audioformaatit eivät ole saatavilla tähän videoon\n  Dash formats are not available for this video: DASH-formaatit eivät ole saatavilla tähän videoon\nShare:\n  Share Video: 'Jaa video'\n  Share Playlist: 'Jaa soittolista'\n  Copy Link: 'Kopioi linkki'\n  Open Link: 'Avaa linkki'\n  Copy Embed: 'Kopioi upotus'\n  Open Embed: 'Avaa upotus'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-osoite leikepöydälle'\n  Invidious Embed URL copied to clipboard: 'Invidious-upotus kopioitu leikepöydälle'\n  YouTube URL copied to clipboard: 'YouTube-osoite kopioitu leikepöydälle'\n  YouTube Embed URL copied to clipboard: 'YouTube-upotteen osoite kopioitu leikepöydälle'\n  Include Timestamp: Sisällytä aikaleima\n  YouTube Channel URL copied to clipboard: Kanavan Youtube URL kopioitu leikepöydälle\n  Invidious Channel URL copied to clipboard: Kanavan Invidious URL kopioutu leikepöydälle\n  Share Channel: Jaa kanava\nMini Player: 'Pieni soitin'\nComments:\n  Comments: 'Kommentit'\n  Click to View Comments: 'Napsauta avataksesi kommentit'\n  Getting comment replies, please wait: 'Haetaan vastauksia, odota hetki'\n  Hide Comments: 'Piilota kommentit'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Tähän videoon ei ole yhtään kommenttia'\n  Load More Comments: 'Lataa lisää kommentteja'\n  There are no more comments for this video: Ei ole enempää kommentteja tälle videolle\n  Newest first: Uusimmat ensin\n  Top comments: Suosituimmat kommentit\n  Show More Replies: Näytä enemmän vastauksia\n  Pinned by: Kiinnittänyt\n  Member: Jäsen\n  View {replyCount} replies: Näytä {replyCount} vastausta\n  Hearted: Tykätty\n  Subscribed: Tilattu\nUp Next: 'Seuraavaksi'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Paikallinen API-virhe (Kopioi napsauttamalla)'\nInvidious API Error (Click to copy): 'Invidious API-virhe (Kopioi napsauttamalla)'\nFalling back to Invidious API: 'Palaa takaisin Invidious-sovellusliittymään'\nFalling back to Local API: 'Palaa takaisin paikalliseen sovellusliittymään'\nLoop is now disabled: 'Silmukka on poistettu käytöstä'\nLoop is now enabled: 'Silmukka on nyt käytössä'\nShuffle is now disabled: 'Satunnaistoisto on poistettu käytöstä'\nShuffle is now enabled: 'Satunnaistoisto on nyt käytössä'\nPlaying Next Video: 'Seuraavan videon toistaminen'\nPlaying Previous Video: 'Edellisen videon toistaminen'\nCanceled next video autoplay: 'Peruttiin seuraavan videon toistaminen'\n'The playlist has ended. Enable loop to continue playing': 'Soittolista on pääättynyt. Ota silmukka käyttöön jatkaaksesi toistoa'\n\nYes: 'Kyllä'\nNo: 'Ei'\nLocale Name: suomi\nThe playlist has been reversed: Soittolista on muutettu käänteiseksi\nProfile:\n  '{profile} is now the active profile': '{profile} on nyt aktiivinen profiili'\n  Your default profile has been changed to your primary profile: Oletusprofiilisi on vaihdettu ensisijaiseksi profiiliksesi\n  Removed {profile} from your profiles: '{profile} on poistettu profiileistasi'\n  Your default profile has been set to {profile}: Oletusprofiiliksesi on määritetty {profile}\n  Profile has been updated: Profiili on päivitetty\n  Profile has been created: Profiili on luotu\n  Your profile name cannot be empty: Profiililla täytyy olla nimi\n  All subscriptions will also be deleted.: Kaikki tilaukset tullaan myös poistamaan.\n  Are you sure you want to delete this profile?: Haluatko varmasti poistaa tämän profiilin?\n  Delete Profile: Poista profiili\n  Make Default Profile: Määritä oletusprofiiliksi\n  Update Profile: Päivitä profiili\n  Create Profile: Luo profiili\n  Profile Preview: Profiilin esikatselu\n  Custom Color: Mukautettu väri\n  Color Picker: Värin valinta\n  Edit Profile: Muokkaa profiilia\n  Create New Profile: Luo uusi profiili\n  Profile Manager: Profiilin hallinta\n  All Channels: Kaikki kanavat\n  Profile Select: Profiilin valinta\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Haluatko varmasti poistaa valitut kanavat? Kanavia ei poisteta muista profiileista.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Tämä on ensisijainen profiilisi. Haluatko poistaa valitut kanavat? Kanavat poistetaan myös muista profiileista.\n  No channel(s) have been selected: Kanavia ei ole valittu\n  Add Selected To Profile: Lisää valitut profiiliin\n  Delete Selected: Poista valitut\n  Select None: Älä valitse mitään\n  Select All: Valitse Kaikki\n  '{number} selected': '{number} valittu'\n  Other Channels: Muut kanavat\n  Subscription List: Tilauslista\n  Profile Filter: Profiilisuodatin\n  Profile Settings: Profiiliasetukset\n  Profile Name: Profiilin nimi\n  Edit Profile Name: Muokkaa profiilin nimeä\n  Create Profile Name: Luo profiilin nimi\n  Toggle Profile List: Profiililista päällä/pois\nVersion {versionNumber} is now available!  Click for more details: Versio {versionNumber} on nyt saatavilla! Napsauta saadaksesi lisätietoja\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Tämä video ei ole saatavilla puuttuvien formaattien takia. Tämä voi tapahtua koska video ei ole saatavilla maassasi.\nA new blog is now available, {blogTitle}. Click to view more: Uusi blogi on saatavilla, {blogTitle}. Klikkaa nähdäksesi lisää\nDownload From Site: Lataa sivustolta\nTooltips:\n  General Settings:\n    Preferred API Backend: Valitse taustaohjelma, jota Freetube käyttää datan noutamiseen. Paikallinen API on ohjelmiston sisäinen. Invidious API vaatii yhteyden Invidious-palvelimeen.\n    Region for Trending: Valitsee minkä maan Nousevat videot sinulle näytetään.\n    Invidious Instance: Invidious instanssi, jota Freetube käyttää.\n    Thumbnail Preference: Kaikki pikkukuvat Freetubessa korvataan ruudulla videosta alkuperäisen pikkukuvan sijaan.\n    Fallback to Non-Preferred Backend on Failure: Kun valitsemasi API kohtaa ongelman, Freetube yrittää automaattisestia käyttää toissijaista vaihtoehtoa.\n    External Link Handling: \"Valitse oletuskäyttäytyminen, kun linkkiä, jota ei voi avata FreeTubessa, napsautetaan.\\nOletusarvoisesti FreeTube avaa napsautetun linkin oletusselaimessasi.\\n\"\n  Subscription Settings:\n    Fetch Feeds from RSS: Kun valittuna, FreeTube käyttää RSS-syötettä oletusmetodin sijaan tilauslistasi hakemisessa. RSS on nopeampi ja ehkäisee IP-estoa, mutta ei anna tietoja, kuten videon kesto tai livetila\n    Fetch Automatically: Kun tämä on käytössä, FreeTube hakee automaattisesti tilauksesi syötteen, kun uusi ikkuna avataan ja kun vaihdat profiilia.\n  Player Settings:\n    Default Video Format: Aseta videon toistamisessa käytätettävä formaatti. DASH-formaatit toistavat korkealaatuisempia videoita. Legacy-formaatit ovat rajoitettu 720p-resoluutioon, mutta käyttävät vähemmän dataa. Audioformaatit ovat vain äänistriimeihin.\n    Proxy Videos Through Invidious: Yhdistää Invidious-palvelimeen suoran YouTuben-yhteyden sijaan.\n    Scroll Playback Rate Over Video Player: Kursorin ollessa videon päällä, paina CTRL (Komentopainike MAC-tietokoneessa) pohjaan ja käytä hiiren rullaa muuttaaksesi toiston nopeutta. Palataksesi alkuperäiseen toistonopeuteen (1x ellei toisin määritelty asetuksissa), pidä CTRL-painike (Komentopainike MAC-tietokoneessa) painettuna ja paina hiiren vasenta näppäintä.\n    Skip by Scrolling Over Video Player: Käytä vieritysrullaa videon selaamiseen, MPV-tyyliin.\n  External Player Settings:\n    Custom External Player Arguments: Kaikki ne omavalintaiset komentorivin määreet, jotka haluat siirtää eteenpäin ulkoiselle toisto-ohjelmalle.\n    Ignore Warnings: Estä varoitukset, kun käytetty ulkoinen toisto-ohjelma ei tue määrättyä toimintamallia (kuten käänteiset soittoluettelot, jne.).\n    Custom External Player Executable: Vakiollisesti FreeTube olettaa, että valittu ulkoinen toisto-ohjelma voidaan löytää PATH-polkuympäristömuuttujan kautta. Mikäli tarvetta ilmenee, voidaan asettaa omavalintainen polku tähän.\n    External Player: Ulkoisen soittimen valitsemisen johdosta näkyy kuvake videon avaamiseen (soittoluettelonkin avaamiseen jos tuettu) ulkoisessa toistimessa. Varoitus, Invidious-asetukset eivät vaikuta ulkoisiin toistimiin.\n    DefaultCustomArgumentsTemplate: \"(Oletus: '{defaultCustomArguments}')\"\n  Experimental Settings:\n    Replace HTTP Cache: Poistaa Electronin levypohjaisen HTTP-välimuistin käytöstä ja ottaa käyttöön mukautetun muistissa olevan kuvavälimuistin. Lisää välimuistin käyttöä.\n  Distraction Free Settings:\n    Hide Channels: Anna kanavan nimi tai kanavatunnus piilottaaksesi kaikki videot, soittolistat ja itse kanavan näkymästä haussa, trendaamisessa, suosituimmissa ja suositelluissa. Annetun kanavan nimen on oltava täysin oikein ja kirjainkoolla on merkitystä.\n    Hide Subscriptions Live: Tämä asetus ohitetaan koko sovelluksen laajuisella ”{appWideSetting}” asetuksella, joka on ”{subsection}” osion ”{settingsSection}” osiossa\n  SponsorBlock Settings:\n    UseDeArrowTitles: Korvaa videon otsikot käyttäjien lähettämillä DeArrow’n otsikoilla.\nMore: Lisää\nPlaying Next Video Interval: Seuraava video alkaa. Klikkaa peruuttaaksesi. |Seuraava video alkaa {nextVideoInterval} sekunnin kuluttua. Klikkaa peruuttaaksesi. | Seuraava video alkaa {nextVideoInterval} sekunnin kuluttua. Klikkaa peruuttaaksesi.\nOpen New Window: Avaa uusi ikkuna\nUnknown YouTube url type, cannot be opened in app: Tuntematon YouTube-videon osoitemuoto, ei voida avata sovelluksessa\nDefault Invidious instance has been cleared: Oletusarvoinen Invidious-palveluntarjoaja on tyhjennetty\nDefault Invidious instance has been set to {instance}: Oletusarvoinen Invidious-palveluntarjoaja on jatkossa {instance}\nSearch Bar:\n  Clear Input: Tyhjennä syöte\n  Remove: Poista\nExternal link opening has been disabled in the general settings: Ulkoisen linkin avaaminen on poistettu käytöstä yleisissä asetuksissa\nAre you sure you want to open this link?: Haluatko varmasti avata tämän linkin?\nScreenshot Success: Kuvakaappaus tallennettu nimellä ”{filePath}”\nNew Window: Uusi Ikkuna\nScreenshot Error: Ruutukaappaus epäonnistui. {error}\nChannels:\n  Channels: Kanavat\n  Title: Kanavaluettelo\n  Search bar placeholder: Etsi kanavia\n  Count: '{number} kanava(a) löydetty.'\n  Empty: Kanavaluettelosi on tällä hetkellä tyhjä.\n  Unsubscribe Prompt: Haluatko varmasti perua kanavan ”{channelName}” tilauksen?\nClipboard:\n  Copy failed: Kopiointi leikepöydälle epäonnistui\n  Cannot access clipboard without a secure connection: Leikepöytää ei voi käyttää ilman suojattua yhteyttä\nChapters:\n  Chapters: Luvut\nPreferences: Asetukset\nOk: OK\nHashtag:\n  Hashtag: Avainsana\n  This hashtag does not currently have any videos: Tällä avainsanalla ei ole tällä hetkellä yhtään videota\nChannel Hidden: '{channel} lisätty kanavasuodattimeen'\nGo to page: Siirry sivulle {page}\nChannel Unhidden: '{channel} poistettu kanavasuodattimesta'\nAge Restricted:\n  This video is age restricted: Tämä video on ikärajoitettu\n  This channel is age restricted: Tämä kanava on ikärajoitettu\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Teksitykset\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Uusi\n    3D: 3D\n    Closed Captions: Suljetut kuvatekstit\nFeed:\n  Refresh Feed: Päivitä {subscriptionName}\n  Feed Last Updated: 'Syöte {feedName} päivitetty viimeksi: {date}'\nYes, Delete: Kyllä, poista\ncheckmark: ✓\nCancel: Peruuta\nYes, Restart: Kyllä, käynnistä uudelleen\nYes, Open Link: Kyllä, avaa linkki\nRight-click or hold to see history: Näytä historia napsauttamalla hiiren kakkospainiketta tai pitämällä painettuna\nClose Banner: Sulje Banneri\nSearch character limit: Hakukysely ylittää {searchCharacterLimit}-merkkirajan.\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Kehittäjän työkalut päällä/pois\n  Zoom In: Lähennä\n  Zoom Out: Loitonna\n  Fullscreen: Vaihda koko näyttöön\n  Reset Zoom: Palauta skaalaus\n  Take Screenshot: Ota kuvakaappaus\n  Show Keyboard Shortcuts: Näytä pikanäppäimet\n  Keyboard Shortcuts: Pikanäppäimet\n  History Backward: Siirry taaksepäin\n  History Forward: Siirry eteenpäin\n  New Window: Luo uusi ikkuna\n  Navigate to Settings: Siirry Asetukset-sivulle\n  Navigate to History: Siirry Historia-sivulle\n  Refresh: Virkistä syöte viimeisimmällä sisällöllä\n  Captions: Tekstitykset päälle/pois\n  Stats: Näytä videon tilastot\n  Picture in Picture: Vaihda Kuva kuvassa -tilaan\n  Play: Toista/pysäytä\n  Large Fast Forward: Siirry 10 sekuntia eteenpäin / Kelaa videota eteenpäin\n  Large Rewind: Siirry 10 sekuntia taaksepäin / Kelaa videota taaksepäin\n  Mute: Vaimenna\n  Increase Video Speed: Lisää videon toistonopeutta\n  Decrease Video Speed: Vähennä videon toistonopeutta\n  Full Window: Koko näytön tila päälle/pois\n  Theatre Mode: Teatteritila päälle/pois\n  Minimize Window: Pienennä ikkuna\n  Close Window: Sulje ikkuna\n  Search in New Window: Hae uudessa ikkunassa\n  Last Frame: Aiempi kuvaruutu (kun pysäytetty)\n  Next Frame: Seuraava kuvaruutu (kun pysäytetty)\n  Volume Up: Lisää äänenvoimakkuutta\n  Volume Down: Pienennä äänenvoimakkuutta\n  Last Chapter: Edellinen osio\n  Next Chapter: Seuraava osio\n  Skip by Tenths: Siirry videon läpi prosentteina\n"
  },
  {
    "path": "static/locales/fil.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Filipino'\n\n# Webkit Menu Bar\nFile: 'File'\nQuit: 'Umalis'\nEdit: 'I-edit'\nUndo: 'Pawalang-bisa'\nRedo: 'Gawing Muli'\nCut: 'Putolin'\nCopy: 'Kopya'\nPaste: 'I-paste'\nDelete: 'Alisin'\nSelect all: 'Piliin lahat'\nToggle Developer Tools: 'I-toggle ang mga Developer Tools'\nActual size: 'Totoong sukat'\nZoom in: 'Palakihin'\nZoom out: 'Paliitin'\nToggle fullscreen: 'I-fullscreen'\nWindow: 'Ang window'\nMinimize: 'I-minimize'\nClose: 'Isara'\nBack: 'Bumalik'\nForward: 'Pagsulong'\n\n# Search Bar\nSearch / Go to URL: 'Maghanap / Pumunta sa URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Mga filter ng paghahanap'\n  Sort By:\n    Most Relevant: 'Pinakanakakaugnay'\n    Rating: 'Mga Marka'\n    Upload Date: 'Petsa ng pag-upload'\n    View Count: 'Bilang ng pagtingin'\n  Time:\n    Time: 'Oras'\n    Any Time: 'Kahit anuman oras'\n    Last Hour: 'Nakaraang Oras'\n    Today: 'Ngayon'\n    This Week: 'Ngayong linggo'\n    This Month: 'Ngayong buwan'\n    This Year: 'Ngayong taon'\n  Type:\n    Type: 'Uri'\n    All Types: 'Lahat ng mga uri'\n    Videos: 'Mga video'\n    Channels: 'Mga channel'\n    #& Playlists\n  Duration:\n    Duration: 'Tagal'\n    All Durations: 'Lahat ng mga durasyon'\n    Short (< 4 minutes): 'Maikli (< 4 minuto)'\n    Long (> 20 minutes): 'Mahaba (> 20 minuto)'\n  # On Search Page\n    Medium (4 - 20 minutes): Kalagitnaan (4 - 20 na minuto)\n  Search Results: 'Mga Resulta'\n  Fetching results. Please wait: 'Sinusundo ang mga resulta. Maghintay lang po'\n  Fetch more results: 'Magsundo ng marami pang resulta'\n# Sidebar\n  Features:\n    Features: Mga Feature\n    Location: Lokasyon\n  There are no more results for this search: Wala nang resulta sa search na ito\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Mga Suskripsyon'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Ang\n    iyong listahan ng Suskripsyon ay kasalukuyang walang laman. Simulang magdagdag\n    ng mga suskripsyon upang makita ang mga ito dito.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Maraming\n    subscriptions itong profile.   Pilitin na iwasan ang rate limiting\nTrending:\n  Trending: 'Nagte-trend'\nMost Popular: 'Pinakasikat'\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\n  Player Settings: {}\nChannel:\n  Videos:\n    Videos: Mga video\n  Playlists: {}\nDownload From Site: I-download mula sa website\nOpen New Window: buksan ang bagong window\nNew Window: Bagong window\nGlobal:\n  Counts:\n    View Count: 1 na panonood | {count} na mga panonood\n  Live: Mga Live\n  Videos: Mga Video\n  Shorts: Mga Shorts\n  Sort By: 'Pag-uri-uriin ayon'\n  Posts: Mga Post\nSearch Bar:\n  Clear Input: Alisin ang Input\nExternal link opening has been disabled in the general settings: Ang pag bukas ng\n  link sa panlabas ay pinasara sa general settings\nAge Restricted:\n  This channel is age restricted: Itong channel ay pinaghihigpitan sa edad\n  This video is age restricted: Ang video na ito ay pinaghihigpitan sa edad\nClose Banner: I-Sara ang banner\nAre you sure you want to open this link?: Sigurado mo na buksan itong link?\nSearch character limit: Na sobrahan ng {searchCharacterLimit} na tilik ang Search\n  query\nGo to page: Pumunta sa {page}\nPreferences: Preferences\nVersion {versionNumber} is now available!  Click for more details: Version {versionNumber}\n  ay magamit na! . . Pindutin para sa detalye\nA new blog is now available, {blogTitle}. Click to view more: May bagong blog, {blogTitle},\n  Pindutin para makita\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: I-toggle ang mga Developer Tools\n  Zoom In: Palakihin\n  Zoom Out: Paliitin\n  Fullscreen: I-fullscreen\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\nProfile:\n  Select All: Piliin lahat\n"
  },
  {
    "path": "static/locales/fr-FR.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Fichier'\nQuit: 'Quitter'\nEdit: 'Modifier'\nUndo: 'Annuler'\nRedo: 'Rétablir'\nCut: 'Couper'\nCopy: 'Copier'\nPaste: 'Coller'\nDelete: 'Supprimer'\nSelect all: 'Tout sélectionner'\nToggle Developer Tools: 'Activer les outils de développement'\nActual size: 'Taille réelle'\nZoom in: 'Zoom avant'\nZoom out: 'Zoom arrière'\nToggle fullscreen: 'Plein écran'\nWindow: 'Fenêtre'\nMinimize: 'Réduire'\nClose: 'Fermer'\nBack: 'Retour'\nForward: 'Avancer'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vidéos'\n  Shorts: Shorts\n  Live: En direct\n  Posts: Posts\n  Sort By: Trier par\n\n# Search Bar\n  Counts:\n    Video Count: 1 vidéo | {count} vidéos\n    Channel Count: 1 chaîne | {count} chaînes\n    View Count: 1 vue | {count} vues\n    Subscriber Count: 1 abonné | {count} abonnés\n    Watching Count: 1 spectateur | {count} spectateurs\n    Comment Count: 1 commentaire | {count} commentaires\n    Like Count: 1 j’aime | {count} j’aime\nSearch / Go to URL: 'Rechercher / ouvrir l''URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtres de recherche'\n  Sort By:\n    Most Relevant: 'Plus pertinent'\n    Rating: 'Avis'\n    Upload Date: 'Date de mise en ligne'\n    View Count: 'Nombre de vues'\n  Time:\n    Time: 'Date'\n    Any Time: 'Toutes les dates'\n    Last Hour: 'Dernière heure'\n    Today: 'Aujourd’hui'\n    This Week: 'Cette semaine'\n    This Month: 'Ce mois-ci'\n    This Year: 'Cette année'\n  Type:\n    Type: 'Type'\n    All Types: 'Tous les types'\n    Videos: 'Vidéos'\n    Channels: 'Chaînes'\n    #& Playlists\n    Movies: Films\n  Duration:\n    Duration: 'Durée'\n    All Durations: 'Toutes les durées'\n    Short (< 4 minutes): 'Court (moins de 4 min)'\n    Long (> 20 minutes): 'Longue (plus de 20 min)'\n  # On Search Page\n    Medium (4 - 20 minutes): Moyenne (de 4 à 20 min)\n  Search Results: 'Résultats de la recherche'\n  Fetching results. Please wait: 'Récupération des résultats. Veuillez patienter'\n  Fetch more results: 'Afficher plus de résultats'\n# Sidebar\n  There are no more results for this search: Il n’y a pas plus de résultats pour cette recherche\n  Features:\n    Creative Commons: Creative Commons\n    Features: Fonctionnalités\n    HD: HD\n    Subtitles: Sous-titres\n    3D: 3D\n    Live: En direct\n    4K: 4K\n    360 Video: Vidéo 360\n    Location: Emplacement\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Effacer les filtres\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnements'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Votre liste d’abonnements est actuellement vide. Si vous souhaitez importer vos abonnements, vous pouvez aller dans Paramètres des données et sélectionner Importer des abonnements ou vous pouvez rechercher une chaîne et vous y abonner.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Ce profil comporte un grand nombre d'abonnements.  Le flux RSS dépassera la limite fixée\n  Load More Videos: Charger plus de vidéos\n  Error Channels: Chaînes avec des erreurs\n  Disabled Automatic Fetching: Vous avez désactivé la récupération automatique des abonnements. Actualisez les abonnements pour les voir ici.\n  Empty Channels: Les chaînes auxquelles vous êtes abonné(e) ne contiennent actuellement aucune vidéo.\n  Subscriptions Tabs: Onglets Abonnements\n  All Subscription Tabs Hidden: Tous les onglets d’abonnement sont cachés. Pour voir le contenu ici, veuillez désactiver certains onglets dans la section « {subsection} » dans « {settingsSection} ».\n  Load More Posts: Charger plus de billets\n  Empty Posts: Les chaînes auxquelles vous êtes abonné(e) ne contiennent actuellement aucun billet.\nTrending:\n  Trending: 'Tendance'\n  Trending Tabs: Onglets des Tendances\n  Gaming: Jeux vidéo\n  Sports: Sport\nMost Popular: 'Les plus populaires'\nPlaylists: 'Playlists'\nUser Playlists:\n  Your Playlists: 'Vos playlists'\n  Search bar placeholder: Recherche de playlists\n  Empty Search Message: Il n'y a pas de vidéos dans cette playlist qui correspondent à votre recherche\n  AddVideoPrompt:\n    Search in Playlists: Recherche dans les playlists\n    Save: Sauvegarder\n    Select a playlist to add your N videos to: Sélectionnez une playlist à laquelle ajouter votre vidéo | Sélectionnez une playlist à laquelle ajouter vos {videoCount} vidéos\n    Toast:\n      You haven't selected any playlist yet.: Vous n'avez pas encore sélectionné de playlist.\n      \"Video(s) added to {playlistCount} playlists\": \"Vidéo(s) ajoutée(s) à une playlist | Vidéo(s) ajoutée(s) à {playlistCount} playlists\"\n    N playlists selected: '{playlistCount} Sélectionnée(s)'\n    Added {count} Times: Déjà ajouté | Ajouté {count} fois\n    Allow Adding Duplicate Video(s): Autoriser l'ajout de vidéos en double\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} vidéos seront ajoutées'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} vidéos déjà ajoutées'\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Il n'y avait aucune vidéo à supprimer.\n      Video has been removed: La vidéo a été supprimée\n      Playlist has been updated.: La playlist a été mise à jour.\n      There was an issue with updating this playlist.: Un problème est survenu lors de la mise à jour de cette playlist.\n      This video cannot be moved up.: Cette vidéo ne peut pas être déplacée vers le haut.\n      This playlist is protected and cannot be removed.: Cette playlist est protégée et ne peut pas être supprimée.\n      Playlist {playlistName} has been deleted.: La playlist {playlistName} a été supprimée.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Certaines vidéos de la playlist ne sont pas encore chargées. Cliquez ici pour les copier quand même.\n      This playlist does not exist: Cette playlist n'existe pas\n      Playlist name cannot be empty. Please input a name.: Le nom de la playlist ne peut pas être vide. Veuillez saisir un nom.\n      There was a problem with removing this video: Il y a eu un problème lors de la suppression de cette vidéo\n      \"{videoCount} video(s) have been removed\": 1 vidéo a été supprimée | {videoCount} vidéos ont été supprimées\n      This video cannot be moved down.: Cette vidéo ne peut pas être déplacée vers le bas.\n      This playlist is now used for quick bookmark: Cette playlist est maintenant utilisée comme marque-page rapide\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Cette playlist est désormais utilisée comme marque-page rapide à la place de {oldPlaylistName}. Cliquez ici pour annuler\n      Reverted to use {oldPlaylistName} for quick bookmark: Reprise de {oldPlaylistName} pour un marque-page rapide\n      This playlist is already being used for quick bookmark.: Cette playlist est déjà utilisée comme signet rapide.\n      This playlist has a video with a duration error: Cette playlist contient au moins une vidéo qui n'a pas de durée, elle sera triée comme si la durée était nulle.\n      Video has been removed. Click here to undo.: La vidéo a été supprimée. Cliquez ici pour annuler.\n    Search for Videos: Rechercher des vidéos\n  Are you sure you want to delete this playlist? This cannot be undone: Êtes-vous sûr(e) de vouloir supprimer cette playlist ? Cette opération ne peut pas être annulée.\n  Sort By:\n    LatestPlayedFirst: Date de lecture (la plus récente)\n    EarliestCreatedFirst: Date de création (la plus ancienne)\n    LatestCreatedFirst: Date de création (la plus récente)\n    EarliestUpdatedFirst: Date de mise à jour (la plus ancienne)\n    NameDescending: Z→A\n    EarliestPlayedFirst: Date de lecture (la plus ancienne)\n    LatestUpdatedFirst: Date de mise à jour (la plus récente)\n    NameAscending: A→Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Vous n'avez pas de playlist. Cliquez sur le bouton créer une nouvelle playlist pour en créer une nouvelle.\n  Remove from Playlist: Retirer de la playlist\n  Save Changes: Enregistrer les modifications\n  CreatePlaylistPrompt:\n    Create: Créer\n    Toast:\n      There was an issue with creating the playlist.: Il y a eu un problème lors de la création de la playlist.\n      Playlist {playlistName} has been successfully created.: La playlist {playlistName} a été créée avec succès.\n      There is already a playlist with this name. Please pick a different name.: Il existe déjà une playlist portant ce nom. Veuillez choisir un autre nom.\n    New Playlist Name: Nouveau nom de la playlist\n  This playlist currently has no videos.: Cette playlist ne contient actuellement aucune vidéo.\n  Add to Playlist: Ajouter à la playlist\n  Move Video Down: Déplacer la vidéo vers le bas\n  Playlist Name: Nom de la playlist\n  Remove Watched Videos: Retirer les vidéos visionnées\n  Move Video Up: Déplacer la vidéo vers le haut\n  Cancel: Annuler\n  Delete Playlist: Supprimer la playlist\n  Create New Playlist: Créer une nouvelle playlist\n  Edit Playlist Info: Modifier les informations de la playlist\n  Copy Playlist: Copier la playlist\n  Playlist Description: Description de la playlist\n  Add to Favorites: Ajouter à {playlistName}\n  Remove from Favorites: Retirer de {playlistName}\n  Enable Quick Bookmark With This Playlist: Activer le marque-page rapide avec cette playlist\n  Playlists with Matching Videos: Playlists avec des vidéos correspondantes\n  Quick Bookmark Enabled: Signet rapide activé\n  Cannot delete the quick bookmark target playlist.: Impossible de supprimer la playlist cible des signets rapides.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Êtes-vous sûr(e) de vouloir retirer 1 vidéo en double de cette playlist ? Cette opération est irréversible. | Êtes-vous sûr(e) de vouloir retirer {playlistItemCount} vidéos en double de cette playlist ? Cette opération est irréversible.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Êtes-vous sûr(e) de vouloir retirer 1 vidéo regardée de cette playlist ? Cette opération est irréversible. | Êtes-vous sûr(e) de vouloir retirer {playlistItemCount} vidéos regardées de cette playlist ? Cette opération est irréversible.\n  Remove Duplicate Videos: Retirer les vidéos en double\n  The playlist has been successfully exported: La playlist a été exportée avec succès\n  Export Playlist: Exporter cette playlist\n  TotalTimePlaylist: 'Durée totale : {duration}'\n  Export list of URLs: Exporter la liste des URL\nHistory:\n  # On History Page\n  History: 'Historique'\n  Watch History: 'Historique de visionnage'\n  Your history list is currently empty.: 'Votre historique est vide.'\n  Search bar placeholder: \"Recherche dans l'historique\"\n  Empty Search Message: Il n'y a pas de vidéos dans votre historique qui correspondent à votre recherche\n  Case Sensitive Search: Recherche sensible à la casse\n  DateOldestHistory: Date de visionnage (la plus ancienne)\n  DateNewestHistory: Date de visionnage (la plus récente)\nSettings:\n  # On Settings Page\n  Settings: 'Paramètres'\n  General Settings:\n    General Settings: 'Général'\n    Fallback to Non-Preferred Backend on Failure: 'Revenir à l’API interne non préférentielle en cas d’échec'\n    Enable Search Suggestions: 'Activer les suggestions de recherche'\n    Default Landing Page: 'Page de lancement par défaut'\n    Locale Preference: 'Paramètres régionaux'\n    Preferred API Backend:\n      Preferred API Backend: 'API interne préférée'\n      Local API: 'API locale'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Type d’affichage des vidéos'\n      Grid: 'Grille'\n      List: 'Liste'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Préférences des miniatures'\n      Default: 'Par défaut'\n      Beginning: 'Début'\n      Middle: 'Milieu'\n      End: 'Fin'\n      Hidden: Masqué\n      Blur: Flou\n    Region for Trending: 'Pays pour les tendances'\n        #! List countries\n    Check for Latest Blog Posts: Consulter les derniers billets du blog\n    Check for Updates: Vérifier les mises à jour\n    View all Invidious instance information: Voir les informations de toutes les instances Invidious\n    System Default: Système par défaut\n    Clear Default Instance: Effacer l’instance par défaut\n    Set Current Instance as Default: Définir l’instance actuelle par défaut\n    Current instance will be randomized on startup: L’instance actuelle sera choisie au hasard au démarrage\n    No default instance has been set: Aucune instance n’a été définie par défaut\n    The currently set default instance is {instance}: L'instance par défaut actuellement définie est {instance}\n    Current Invidious Instance: Instance Invidious actuelle\n    External Link Handling:\n      No Action: Aucune action\n      Ask Before Opening Link: Demander avant d'ouvrir le lien\n      Open Link: Ouvrir le lien\n      External Link Handling: Gestion des liens externes\n    Auto Load Next Page:\n      Label: Chargement automatique de la page suivante\n      Tooltip: Chargement automatique des pages supplémentaires et des commentaires.\n    Open Deep Links In New Window: Ouvrir les URL transmises à FreeTube dans une nouvelle fenêtre\n    Minimize to system tray: Réduire dans la barre d'état système\n  Theme Settings:\n    Theme Settings: 'Thème'\n    Match Top Bar with Main Color: 'Faire correspondre la barre supérieure à la couleur principale'\n    Base Theme:\n      Base Theme: 'Thème de base'\n      Black: 'Noir'\n      Dark: 'Sombre'\n      Light: 'Clair'\n      Dracula: 'Dracula'\n      System Default: Paramètres système\n      Catppuccin Mocha: Catppuccin Moka\n      Pastel Pink: Rose pastel\n      Hot Pink: Rose vif\n      Nordic: Nordique\n      Solarized Light: Clair polarisé\n      Solarized Dark: Noir polarisé\n      Gruvbox Light: Gruvbox Clair\n      Gruvbox Dark: Gruvbox Sombre\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Light Hard: Jungle Dur Clair\n      Everforest Light Low: Jungle Faible Clair\n      Everforest Dark Low: Jungle Bas Sombre\n      Everforest Light Medium: Jungle Médian Clair\n      Everforest Dark Hard: Jungle Dur Sombre\n      Everforest Dark Medium: Jungle Médian Sombre\n      Catppuccin Latte: Latté Catppuccin\n    Main Color Theme:\n      Main Color Theme: 'Couleur principale'\n      Red: 'Rouge'\n      Pink: 'Rose'\n      Purple: 'Violet'\n      Deep Purple: 'Violet foncé'\n      Indigo: 'Indigo'\n      Blue: 'Bleu'\n      Light Blue: 'Bleu clair'\n      Cyan: 'bleu-vert'\n      Teal: 'Bleu sarcelle'\n      Green: 'Vert'\n      Light Green: 'Vert clair'\n      Lime: 'Citron vert'\n      Yellow: 'Jaune'\n      Amber: 'Ambre'\n      Orange: 'Orange'\n      Deep Orange: 'Orange foncé'\n      Dracula Cyan: 'bleu-vert Dracula'\n      Dracula Green: 'Dracula Vert'\n      Dracula Orange: 'Dracula Orange'\n      Dracula Pink: 'Dracula Rose'\n      Dracula Purple: 'Dracula Violet'\n      Dracula Red: 'Dracula Rouge'\n      Dracula Yellow: 'Dracula Jaune'\n      Catppuccin Mocha Flamingo: Catppuccin Moka Flamant Rose\n      Catppuccin Mocha Pink: Catppuccin Moka Rose\n      Catppuccin Mocha Rosewater: Catppuccin Moka Eau de Rose\n      Catppuccin Mocha Mauve: Catppuccin Moka Mauve\n      Catppuccin Mocha Red: Catppuccin Moka Rouge\n      Catppuccin Mocha Green: Catppuccin moka vert\n      Catppuccin Mocha Blue: Catppuccin moka bleu\n      Catppuccin Mocha Maroon: Catpuccin moka marron\n      Catppuccin Mocha Peach: Catpuccin moka pêche\n      Catppuccin Mocha Yellow: Catppuccin moka jaune\n      Catppuccin Mocha Sky: Catppuccin moka ciel\n      Catppuccin Mocha Sapphire: Catppuccin moka saphir\n      Catppuccin Mocha Lavender: Catppuccin moka lavande\n      Catppuccin Mocha Teal: Catppuccin moka bleu sarcelle\n      Solarized Magenta: Magenta polarisé\n      Solarized Violet: Violet polarisé\n      Solarized Blue: Bleu polarisé\n      Solarized Cyan: Cyan polarisé\n      Solarized Green: Vert polarisé\n      Solarized Yellow: Jaune polarisé\n      Solarized Orange: Orange polarisé\n      Solarized Red: Rouge polarisé\n      Gruvbox Dark Yellow: Gruvbox Jaune Sombre\n      Gruvbox Dark Purple: Gruvbox Violet Sombre\n      Gruvbox Dark Aqua: Gruvbox Eau Sombre\n      Gruvbox Dark Orange: Gruvbox Orange Sombre\n      Gruvbox Light Red: Gruvbox Rouge Clair\n      Gruvbox Light Blue: Gruvbox Bleu Clair\n      Gruvbox Light Purple: Gruvbox Violet Clair\n      Gruvbox Light Orange: Gruvbox Orange Clair\n      Gruvbox Dark Green: Gruvbox Vert Sombre\n      Gruvbox Dark Blue: Gruvbox Bleu Sombre\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamant Rose\n      Catppuccin Frappe Pink: Catppuccin Frappe Rose\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Eau de rose\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Rouge\n      Catppuccin Frappe Maroon: Catppuccin Frappe Marron\n      Catppuccin Frappe Peach: Catppuccin Frappe Pêche\n      Catppuccin Frappe Yellow: Catppuccin Frappe Jaune\n      Catppuccin Frappe Green: Catppuccin Frappe Vert\n      Catppuccin Frappe Teal: Catppuccin Frappe Sarcelle\n      Catppuccin Frappe Sky: Catppuccin Frappe Ciel\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Saphir\n      Catppuccin Frappe Blue: Catppuccin Frappe Bleu\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavande\n      Everforest Dark Yellow: Jungle Jaune Sombre\n      Everforest Dark Aqua: Jungle Cyan Sombre\n      Everforest Light Red: Jungle Rouge Clair\n      Everforest Light Orange: Jungle Orange Clair\n      Everforest Light Green: Jungle Vert Clair\n      Everforest Light Aqua: Jungle Cyan Clair\n      Everforest Light Blue: Jungle Bleu Clair\n      Everforest Dark Purple: Jungle Violet Sombre\n      Everforest Dark Green: Jungle Vert Sombre\n      Everforest Dark Orange: Jungle Orange Sombre\n      Everforest Dark Blue: Jungle Bleu Sombre\n      Everforest Light Purple: Jungle Violet Clair\n      Everforest Dark Red: Jungle Rouge Sombre\n      Everforest Light Yellow: Jungle Jaune Clair\n      Catppuccin Latte Mauve: Latté Catppuccin Mauve\n      Catppuccin Latte Red: Latté Catppuccin Rouge\n    Secondary Color Theme: 'Couleur secondaire'\n        #* Main Color Theme\n    UI Scale: Échelle de l'interface utilisateur\n    Expand Side Bar by Default: Étendre la barre latérale par défaut\n    Disable Smooth Scrolling: Désactiver le défilement fluide\n    Hide Side Bar Labels: Masquer les étiquettes dans la barre latérale\n    Hide FreeTube Header Logo: Masquer le logo FreeTube dans l’en-tête\n  Player Settings:\n    Player Settings: 'Lecteur'\n    Play Next Video: 'Lecture automatique des vidéos recommandées'\n    Turn on Subtitles by Default: 'Activer les sous-titres par défaut'\n    Autoplay Videos: 'Démarrer les vidéos automatiquement'\n    Proxy Videos Through Invidious: 'Proxy vidéo via Invidious'\n    Autoplay Playlists: 'Lire automatiquement les vidéos des playlists'\n    Enable Theatre Mode by Default: 'Activer le mode cinéma par défaut'\n    Default Volume: 'Volume par défaut'\n    Default Playback Rate: 'Vitesse de lecture par défaut'\n    Default Video Format:\n      Default Video Format: 'Format de vidéo par défaut'\n      Dash Formats: 'Formats DASH'\n      Legacy Formats: 'Format Legacy'\n      Audio Formats: 'Formats audio'\n    Default Quality:\n      Default Quality: 'Qualité par défaut'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4K'\n      8k: '8K'\n    Next Video Interval: Décompte de la lecture automatique\n    Scroll Volume Over Video Player: Contrôler le volume par la molette sur la vidéo\n    Display Play Button In Video Player: Afficher le bouton de lecture dans le lecteur vidéo\n    Fast-Forward / Rewind Interval: Pas de l’avance/retour rapide\n    Scroll Playback Rate Over Video Player: Contrôler la vitesse de lecture par la molette sur la vidéo\n    Video Playback Rate Interval: Pas de la vitesse de lecture\n    Max Video Playback Rate: Vitesse maximale de lecture vidéo\n    Screenshot:\n      Enable: Activer les captures d’écran\n      Ask Path: Demander le dossier de sauvegarde\n      Folder Button: Sélectionner un dossier\n      Error:\n        Forbidden Characters: Caractères interdits\n        Empty File Name: Nom de fichier vide\n      File Name Tooltip: Vous pouvez utiliser les variables suivantes. %Y Année 4 chiffres. %M Mois 2 chiffres. %D Jour 2 chiffres. %H Heure 2 chiffres. %N Minute 2 chiffres. %S Second 2 chiffres. %T Milliseconde 3 chiffres. %s Video Second. %t Milliseconde vidéo 3 chiffres. %i Video ID.\n      Quality Label: Qualité des captures d’écran\n      Format Label: Format des captures d’écran\n      File Name Label: Modèle de nom de fichier\n      Folder Label: Dossier des captures d’écran\n    Enter Fullscreen on Display Rotate: Entrer en plein écran sur l'affichage Rotation\n    Skip by Scrolling Over Video Player: Passer au suivant par la molette sur la vidéo\n    Autoplay Interruption Timer: Minuteur d'arrêt de la lecture automatique\n    Default Viewing Mode:\n      Default Viewing Mode: Mode d'affichage par défaut\n      Picture in Picture: Mode image dans l’image\n      External Player: Lecteur externe ({externalPlayerName})\n      Full Screen: Plein écran\n      Theater: Mode cinéma\n  Subscription Settings:\n    Subscription Settings: 'Abonnements'\n    Fetch Feeds from RSS: Récupération de flux RSS\n    Fetch Automatically: Récupération automatique des flux\n    Confirm Before Unsubscribing: Confirmer avant de se désabonner\n\n    'Limit the number of videos displayed for each channel': Limiter le nombre de vidéos affichées pour chaque chaîne\n    To: Pour\n  Privacy Settings:\n    Privacy Settings: Confidentialité\n    Remember History: Enregistrer l’historique de lecture\n    Watch history has been cleared: L’historique de lecture a été effacé\n    Are you sure you want to remove your entire watch history?: Êtes-vous sûr(e) de vouloir supprimer tout votre historique ?\n    Search cache has been cleared: L'historique de recherche a été effacé\n    Are you sure you want to clear out your search cache?: Êtes-vous sûr(e) de vouloir effacer votre historique de recherche ?\n    Clear Search Cache: Effacer l'historique de recherche\n    Save Watched Progress: Garder la progression de la vidéo\n    Remove Watch History: Effacer l’historique de lecture\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Êtes-vous sûr(e) de vouloir supprimer tous les abonnements et profils ? Cette action est irréversible.\n    Remove All Subscriptions / Profiles: Supprimer tous les abonnements et profils\n    Save Watched Videos With Last Viewed Playlist: Sauvegarder les vidéos regardées avec la dernière playlist vue\n    All playlists have been removed: Toutes les playlists ont été supprimées\n    Remove All Playlists: Supprimer toutes les playlists\n    Are you sure you want to remove all your playlists?: Êtes-vous sûr de vouloir supprimer toutes vos playlists ?\n    Remember Search History: Conserver l'historique de recherche\n    Are you sure you want to clear out your search history and cache?: Êtes-vous sûr(e) de vouloir effacer votre historique de recherche et votre cache ?\n    Clear Search History and Cache: Effacer l’historique de recherche et le cache\n    Search history and cache have been cleared: L’historique de recherche et le cache ont été effacés\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Jamais\n        Auto: Automatique\n        Semi-auto: Semi-automatique\n      Tooltip: Automatique = Enregistre en quittant le page de chaque vidéo, quand la vidéo s'est terminée ou en cas d'erreur (par ex. taux limité ou session de visionnage expirée. Semi-automatique = Comme automatique sauf en quittant la page d'une vidéo et vous pouvez enregistrer manuellement avec le bouton « Enregistrer l'état de visionnage » situé en-dessous du lecteur vidéo.\n  Data Settings:\n    How do I import my subscriptions?: Comment importer mes abonnements ?\n    Subscriptions have been successfully exported: Les abonnements ont été exportés avec succès\n    All subscriptions have been successfully imported: Tous les abonnements ont été importés avec succès\n    All subscriptions and profiles have been successfully imported: Tous les abonnements et profils ont été importés avec succès\n    Export History: Exporter l’historique\n    Import History: Importer l’historique\n    Export NewPipe: Export NewPipe\n    Export YouTube: Export YouTube\n    Export FreeTube: Export FreeTube\n    Export Subscriptions: Exporter vos abonnements\n    Import Subscriptions: Importer vos abonnements\n    Select Export Type: Sélectionner le type d'exportation\n    Unknown data key: Clé de données inconnue\n    Unable to write file: Impossible d'écrire le fichier\n    Unable to read file: Impossible de lire le fichier\n    Invalid history file: Fichier d'historique non valide\n    Invalid subscriptions file: Fichier d'abonnements invalide\n    Data Settings: Données\n    All watched history has been successfully exported: Tout votre historique de visionnage a été exporté avec succès\n    All watched history has been successfully imported: Tout votre historique de visionnage a été importé avec succès\n    History object has insufficient data, skipping item: Ignorer cet élément car les données d'historique sont insuffisantes\n    Profile object has insufficient data, skipping item: Ignorer cet élément car les données de profil sont insuffisantes\n    Manage Subscriptions: Gérer les abonnements\n    Import Playlists: Importer des playlists\n    Export Playlists: Exporter des playlists\n    Playlist insufficient data: Données insuffisantes pour la playlist « {playlist} », saut de l'élément\n    All playlists has been successfully imported: Toutes les playlists ont été importées avec succès\n    All playlists has been successfully exported: Toutes les playlists ont été exportées avec succès\n    History File: Fichier de l'historique\n    Subscription File: Fichier des abonnements\n    Playlist File: Fichier des playlists\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Cette option permet d'exporter les vidéos de toutes les listes de lecture vers une seule liste de lecture nommée « Favorites ».\\nComment exporter et importer des vidéos dans des sélections pour une ancienne version de FreeTube :\\n 1. Exportez vos sélections avec cette option activée.\\n2. Supprimez toutes vos sélections existantes à l'aide de l'option Supprimer toutes les sélections sous Paramètres de confidentialité.\\n3. Lancez l'ancienne version de FreeTube et importez les listes de lecture exportées. »\"\n      Label: Exportation des listes de lecture pour les anciennes versions de FreeTube\n    Search history file: Fichier d'historique de recherche\n    Search history: Historique des recherches\n    Import search history: Importer l'historique de recherche\n    Export search history: Exporter l'historique des recherches\n    All search history has been successfully imported: Tous les historiques de recherche ont été importées avec succès\n    All search history has been successfully exported: Tous les historiques de recherche ont été exportées avec succès\n  Distraction Free Settings:\n    Hide Video Likes And Dislikes: Masquer les J’aime et Je n’aime pas des vidéos\n    Hide Comment Likes: Masquer les J’aime dans les commentaires\n    Hide Channel Subscribers: Masquer le nombre d’abonnés des chaînes\n    Hide Video Views: Masquer les vues des vidéos\n    Hide Live Chat: Masquer le chat en direct\n    Hide Popular Videos: Masquer les vidéos populaires\n    Hide Trending Videos: Masquer les tendances\n    Hide Recommended Videos: Masquer les vidéos recommandées\n    Distraction Free Settings: Sans distraction\n    Hide Active Subscriptions: Masquer les abonnements actifs\n    Hide Playlists: Masquer les playlists\n    Hide Video Description: Masquer la description de la vidéo\n    Hide Comments: Masquer les commentaires\n    Hide Live Streams: Masquer les flux en direct\n    Hide Sharing Actions: Masquer les actions de partage\n    Hide Videos on Watch: 'Masquer les vidéos visionnées'\n    Hide Chapters: Masquer les chapitres\n    Hide Upcoming Premieres: Masquer les avant-premières à venir\n    Hide Channels: Masquer les vidéos des chaînes\n    Hide Channels Placeholder: Identifiant de la chaîne\n    Display Titles Without Excessive Capitalisation: Afficher les titres sans majuscules ni ponctuation excessives\n    Hide Channel Playlists: Masquer l’onglet « Playlists » de la chaîne\n    Hide Featured Channels: Masquer les chaînes en vedette\n    Hide Channel Shorts: Masquer l’onglet « Shorts » de la chaîne\n    Sections:\n      Channel Page: Page de la chaîne\n      Side Bar: Barre latérale\n      Watch Page: Page de lecture\n      General: Général\n      Subscriptions Page: Page Abonnements\n    Hide Channel Podcasts: Masquer l’onglet « Podcasts » de la chaîne\n    Hide Channel Releases: Masquer l’onglet « Publications » de la chaîne\n    Hide Subscriptions Videos: Masquer les vidéos des abonnements\n    Hide Subscriptions Shorts: Masquer les shorts des abonnements\n    Hide Subscriptions Live: Masquer les diffusions en direct des abonnements\n    Hide Profile Pictures in Comments: Masquer les photos de profil dans les commentaires\n    Hide Channels Invalid: L’identifiant de chaîne fourni n’est pas valide\n    Hide Channels Disabled Message: Certaines chaînes ont été bloquées à l’aide d’un identifiant et n’ont pas été traitées. La fonctionnalité est bloquée le temps que ces identifiants se mettent à jour\n    Hide Channels Already Exists: L’identifiant de chaîne existe déjà\n    Hide Channels API Error: Erreur de récupération de l'utilisateur portant l'identifiant fourni. Veuillez vérifier à nouveau si l'ID est correct.\n    Hide Videos, Playlists and Channels Containing Text: Masquer les vidéos et les playlists contenant du texte\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Mot, fragment de mot ou phrase\n    Hide Channel Home: Masquer l’onglet « Accueil » de la chaîne\n    Show Added Items: Afficher les éléments ajoutés\n    Hide Channel Courses: Masquer l’onglet « Cours » de la chaîne\n    Hide Channel Posts: Masquer l’onglet « Posts » de la chaîne\n    Hide Subscriptions Posts: Masquer les posts des abonnements\n  The app needs to restart for changes to take effect. Restart and apply change?: L'application doit être redémarrée pour que les changements prennent effet. Redémarrer et appliquer les changements ?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Erreur lors de l'obtention des informations sur le réseau. Votre proxy est-il correctement configuré ?\n    City: Ville\n    Region: Région\n    Country: Pays\n    Ip: Ip\n    Your Info: Vos informations\n    Test Proxy: Test du Proxy\n    Clicking on Test Proxy will send a request to: En cliquant sur Test du Proxy, une demande sera envoyée à\n    Proxy Port Number: Numéro de port du proxy\n    Proxy Host: Hôte du proxy\n    Proxy Protocol: Protocole du proxy\n    Enable Tor / Proxy: Activer Tor / Proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube n'a pas de proxy intégré mais peut se connecter à un proxy externe, tel qu'un proxy fonctionnant sur votre machine comme Tor ou un proxy externe tel qu'un proxy SOCKS5 fourni par certains VPN. Si cette option est activée, assurez-vous que votre proxy/Tor est configuré correctement, sinon FreeTube ne pourra pas récupérer de données.\n    Proxy Password: Mot de passe du proxy\n    Proxy Username: Nom d'utilisateur du proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notification lorsqu’un segment sponsorisé est ignoré\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'URL de l’API SponsorBlock (par défaut : https://sponsor.ajay.app)'\n    Enable SponsorBlock: Activer SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Ignorer l'option\n      Auto Skip: Ignorer automatiquement\n      Show In Seek Bar: Afficher dans la barre de recherche\n      Prompt To Skip: Inviter à ignorer\n      Do Nothing: Ne rien faire\n    Category Color: Couleur de la catégorie\n    UseDeArrowTitles: Utiliser DeArrow pour les titres des vidéos\n    UseDeArrowThumbnails: Utiliser DeArrow pour les miniatures\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': \"URL de l'API du générateur de miniatures DeArrow (par défaut : https://dearrow-thumb.ajay.app)\"\n  External Player Settings:\n    Ignore Unsupported Action Warnings: Ignorer les avertissements concernant les actions non prises en charge\n    External Player: Lecteur externe\n    External Player Settings: Lecteur externe\n    Custom External Player Arguments: Arguments personnalisés du lecteur externe\n    Custom External Player Executable: Exécutable de lecteur externe personnalisé\n    Players:\n      None:\n        Name: Aucun\n    Ignore Default Arguments: Ignorer les arguments par défaut\n  Parental Control Settings:\n    Hide Unsubscribe Button: Masquer le bouton de désabonnement\n    Hide Search Bar: Masquer la barre de recherche\n    Parental Control Settings: Contrôle parental\n    Show Family Friendly Only: Afficher uniquement le contenu familial\n    Hide Uploader on Watch page: Masquer la chaîne sur la page de lecture\n  Experimental Settings:\n    Replace HTTP Cache: Remplacer le cache HTTP\n    Experimental Settings: Expérimental\n    Warning: Ces paramètres sont expérimentaux ; ils peuvent provoquer des plantages lorsqu'ils sont activés. Il est fortement recommandé de faire des sauvegardes. Utilisez-les à vos risques et périls !\n  Password Dialog:\n    Password: Mot de passe\n    Enter Password To Unlock: Entrez le mot de passe pour déverrouiller les paramètres\n  Password Settings:\n    Remove Password: Supprimer le mot de passe\n    Set Password To Prevent Access: Définir un mot de passe pour empêcher l'accès aux paramètres\n    Set Password: Définir un mot de passe\n    Password Settings: Mot de passe\n  Sort Settings Sections (A-Z): Trier de À à Z les rubriques des paramètres\n  Return to Settings Menu: Revenir au Menu paramètres\n  SABR:\n    Label: Activer SABR comme backend DASH\n    Tooltip: SABR deviendra le seul moteur DASH dans les prochaines versions et ne pourra pas être désactivé. Cette option est disponible au cas où une implémentation préliminaire présenterait des problèmes irrémédiables.\nAbout:\n  #On About page\n  About: 'À propos'\n  #& About\n#On Channel Page\n  Website: Site web\n  Email: Courriel\n  Help: Aide\n  Blog: Blog\n  Credits: Crédits\n  FAQ: FAQ\n  Beta: Bêta\n  Donate: Faire un don\n  Translate: Aidez-nous à traduire FreeTube\n  Chat on Matrix: Discuter sur Matrix\n  Mastodon: Mastodon\n  Report a problem: Signaler un problème\n  Source code: Code source\n  these people and projects: ces personnes et ces projets\n  room rules: règles du salon\n  Please check for duplicates before posting: Veuillez vérifier s'il y a des doublons avant de publier\n  GitHub issues: Les problèmes identifiés par la communauté sur GitHub\n  FreeTube Wiki: Wiki de FreeTube\n  GitHub releases: Versions GitHub\n  Downloads / Changelog: Téléchargements / Journal des modifications\n  Discussions: Discussions\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Sous licence {licenseLink}\n  Please read the {roomRulesLink}: Veuillez lire les {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube est rendu possible grâce à {creditsPageLink}\nChannel:\n  Subscribe: 'S’abonner'\n  Unsubscribe: 'Se désabonner'\n  Search Channel: 'Chercher dans la chaîne'\n  Your search results have returned 0 results: 'Les résultats de votre recherche ont donné 0 résultat'\n  Videos:\n    Videos: 'Vidéos'\n    This channel does not currently have any videos: 'Cette chaîne n''a pas de vidéos actuellement'\n    Sort Types:\n      Newest: 'Plus récent'\n      Oldest: 'Plus ancien'\n      Most Popular: 'Les plus populaires'\n  Playlists:\n    Playlists: 'Playlists'\n    This channel does not currently have any playlists: 'Cette chaîne n’a pas encore de playlist'\n    Sort Types:\n      Last Video Added: 'Dernière vidéo ajoutée'\n      Newest: 'Les plus récentes'\n      Oldest: 'Les plus anciennes'\n  About:\n    About: 'À propos'\n    Channel Description: 'Description de la chaîne'\n    Featured Channels: 'Chaînes en vedette'\n    Tags:\n      Tags: Étiquettes\n      Search for: Rechercher « {tag} »\n    Details: Détails\n    Joined: Inscrit(e)\n    Location: Emplacement\n  Added channel to your subscriptions: Chaîne ajoutée à vos abonnements\n  Removed subscription from {count} other channel(s): Abonnement supprimé de {count} autre(s) chaîne(s)\n  Channel has been removed from your subscriptions: La chaîne a été retirée de vos abonnements\n  This channel does not exist: Cette chaîne n'existe pas\n  This channel does not allow searching: Cette chaîne ne permet pas la recherche\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Cette chaîne est limitée par l'âge et ne peut actuellement pas être visionnée dans FreeTube.\n  Channel Tabs: Onglets des chaînes\n  Posts:\n    This channel currently does not have any posts: Cette chaîne n'a actuellement aucune publication\n    votes: '{votes} votes'\n    Reveal Answers: Afficher les réponses\n    Hide Answers: Masquer les réponses\n    Video hidden by FreeTube: Vidéo cachée par FreeTube\n    View Full Post: Voir le message complet\n    Viewing Posts Only Supported By Invidious: L'affichage des messages n'est possible qu'avec Indivious. Allez dans l'onglet communauté de la chaîne pour visualiser le contenu sans Indivious.\n  Live:\n    Live: En direct\n    This channel does not currently have any live streams: Cette chaîne n’a pas encore de flux en direct\n  Shorts:\n    This channel does not currently have any shorts: Cette chaîne n’a pas encore de shorts\n  Releases:\n    Releases: Publications\n    This channel does not currently have any releases: Cette chaîne n’a actuellement aucune publication\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Cette chaîne n’a pas encore de podcast\n  Home:\n    Home: Accueil\n    View Playlist: Afficher la playlist\n  Courses:\n    Courses: Cours\n    This channel does not currently have any courses: Cette chaîne n'a actuellement pas de cours\nVideo:\n  Mark As Watched: 'Marquer comme vu'\n  Remove From History: 'Supprimer de l''historique'\n  Video has been marked as watched: 'La vidéo a été marqué comme Vu'\n  Video has been removed from your history: 'La vidéo a été retiré de votre historique'\n  Open in YouTube: 'Ouvrir sur YouTube'\n  Copy YouTube Link: 'Copier le lien YouTube'\n  Open YouTube Embedded Player: 'Ouvrir sur Youtube-NoCookie'\n  Copy YouTube Embedded Player Link: 'Copier le lien YouTube-NoCookie'\n  Open in Invidious: 'Ouvrir sur Individious'\n  Copy Invidious Link: 'Copier le lien Individious'\n  Views: 'Vues'\n  Watched: 'Vu'\n  # As in a Live Video\n  Live: 'En direct'\n  Live Now: 'En direct maintenant'\n  Live Chat: 'Chat en direct'\n  Enable Live Chat: 'Activer le chat en direct'\n  Live Chat is currently not supported in this build.: 'Le chat en direct n''est actuellement pas pris en charge dans cette version.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Le chat en direct est activé. Les messages apparaîtront ici une fois envoyés.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Le chat en direct n''est actuellement pas pris en charge avec l''API Invidious. Une connexion directe à YouTube est requise.'\n  Published:\n    In less than a minute: En moins d'une minute\n  Published on: 'Mise en ligne le'\n#& Videos\n  Previous: Précédente\n  Next: Suivante\n  Autoplay: Lecture auto\n  Reverse Playlist: Inverser la playlist\n  Shuffle Playlist: Mélanger la playlist\n  Loop Playlist: Playlist en boucle\n  Starting soon, please refresh the page to check again: Débute prochainement, veuillez actualiser la page pour vérifier à nouveau\n  Copy Invidious Channel Link: Copier le lien Invidious de la chaîne\n  Open Channel in Invidious: Ouvrir la chaîne sur Invidious\n  Copy YouTube Channel Link: Copier le lien de la chaîne YouTube\n  Open Channel in YouTube: Ouvrir la chaîne sur YouTube\n  Started streaming on: Diffusion lancée le\n  Streamed on: Diffusé le\n  Video has been removed from your saved list: La vidéo a été supprimée de votre liste enregistrée\n  Video has been saved: La vidéo a été enregistrée\n  Save Video: Enregistrer la vidéo\n  Sponsor Block category:\n    music offtopic: Musique hors sujet\n    interaction: Interaction\n    sponsor: Sponsor\n    self-promotion: Autopromotion\n    outro: Conclusion\n    intro: Intro\n    filler: Bouche-trou\n    recap: Récap\n  External Player:\n    playlist: playlist\n    video: vidéo\n    Unsupported Actions:\n      looping playlists: playlists en boucle\n      shuffling playlists: lecture aléatoire des playlists\n      reversing playlists: inverser l'ordre des playlists\n      opening specific video in a playlist (falling back to opening the video): ouvrir la vidéo sélectionnée dans la playlist (retour à l'ouverture de la vidéo)\n      opening playlists: ouvrir des playlists\n      setting a playback rate: régler la vitesse de lecture\n      starting video at offset: démarrer la vidéo avec un décalage\n    UnsupportedActionTemplate: '{externalPlayer} non pris en charge : {action}'\n    OpeningTemplate: Ouverture de {videoOrPlaylist} avec {externalPlayer}…\n    OpenInTemplate: Ouvrir avec {externalPlayer}\n  Premieres: Avant-première\n  Show Super Chat Comment: Afficher le commentaire Super Chat\n  Scroll to Bottom: Faire défiler jusqu'en bas\n  Upcoming: À venir\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Le chat en direct n'est pas disponible pour ce flux. Il a peut-être été désactivé par l'auteur de la diffusion.\n  Hide Channel: Cacher la chaîne\n  Unhide Channel: Rétablir la chaîne\n  More Options: Plus d'options\n  Player:\n    Audio Tracks: Pistes audio\n    Theatre Mode: Mode théâtre\n    Exit Theatre Mode: Quitter le mode théâtre\n    Full Window: Fenêtre pleine\n    Show Stats: Afficher les stats\n    Hide Stats: Masquer les stats\n    Stats:\n      Stats: Stats\n      Video ID: 'Identifiant de la vidéo : {videoId}'\n      Media Formats: 'Formats du média : {formats}'\n      Resolution: 'Résolution : {width}×{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensions du lecteur : {width}×{height}'\n      Volume: 'Volume : {volumePercentage} %'\n      Bandwidth: 'Bande passante : {bandwidth} kb/s'\n      Bitrate: 'Débit binaire : {bitrate} kb/s'\n      Buffered: 'Mise en mémoire tampon : {bufferedPercentage} %'\n      CodecAudio: 'Codec : {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codecs : {videoCodec} / {audioCodec}'\n      CodecsVideoAudio: 'Codecs : {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Images perdues : {droppedFrames} / Images totales : {totalFrames}'\n    Skipped segment: Segment {segmentCategory} ignoré\n    TranslatedCaptionTemplate: '{language} (traduit depuis : {originalLanguage})'\n    Exit Full Window: Quitter la fenêtre pleine\n    Take Screenshot: Prendre une capture d'écran\n    You appear to be offline: Vous semblez être hors ligne.\n    Playback will resume automatically when your connection comes back: La lecture reprendra automatiquement quand votre connexion reviendra.\n    Autoplay is on: La lecture automatique est activée\n    Autoplay is off: La lecture automatique est désactivée\n  IP block: YouTube a bloqué votre adresse IP pour le visionnage de vidéos. Veuillez essayer de changer de VPN ou de proxy.\n  Unlisted: Non répertorié\n  AgeRestricted: Les vidéos soumises à des restrictions d'âge ne peuvent pas être regardées avec FreeTube car elles nécessitent une connexion Google et l'utilisation d'un compte YouTube dont l'âge a été vérifié.\n  MembersOnly: Les vidéos réservées aux membres ne peuvent pas être visionnées avec FreeTube, car elles nécessitent une connexion Google et une adhésion payante à la chaîne du vidéaste.\n  DeArrow:\n    Show Original Details: Afficher les détails originaux\n    Show Modified Details: Afficher les détails modifiés\n  DRMProtected: Les vidéos protégées par DRM ne peuvent pas être lues dans FreeTube, car elles nécessitent des composants propriétaires et à source fermée. Si vous souhaitez regarder cette vidéo, veuillez la visionner sur le site officiel de YouTube dans un navigateur Web prenant en charge le DRM.\n#& Playlists\n  Save Watched Progress: Enregistrer l'état de visionnage\n  Watched Progress Saved: État de visionnage enregistré\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Temps de publicité pré-roll restant : {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Temps d’attente SABR restant : {remindingTimeSeconds}s'\n  Popout Live Chat: Ouvrir le chat dans une nouvelle fenêtre\nPlaylist:\n  #& About\n  View Full Playlist: 'Afficher la playlist complète'\n  Last Updated On: 'Dernière mise à jour le'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlist\n  Sort By:\n    DateAddedNewest: Date d'ajout (la plus récente)\n    AuthorDescending: Auteur (Z-A)\n    DateAddedOldest: Date d'ajout (la plus ancienne)\n    AuthorAscending: Auteur (A-Z)\n    VideoTitleAscending: Titre (A→Z)\n    VideoTitleDescending: Titre (Z→A)\n    Custom: Personnalisé\n    VideoDurationDescending: Durée (la plus longue)\n    VideoDurationAscending: Durée (la plus courte)\n    PublishedNewest: Date de publication (la plus récente)\n    PublishedOldest: Date de publication (la plus ancienne)\nChange Format:\n  Change Media Formats: 'Changer le format de la vidéo'\n  Use Dash Formats: 'Utiliser le format DASH'\n  Use Legacy Formats: 'Utiliser le format Legacy'\n  Use Audio Formats: 'Utiliser le format Audio'\n  Audio formats are not available for this video: Le format Audio n'est pas disponible pour cette vidéo\n  Dash formats are not available for this video: Le format DASH n'est pas disponible pour cette vidéo\n  Legacy formats are not available for this video: Les formats héritage ne sont pas disponibles pour cette vidéo\nShare:\n  Share Video: 'Partager la vidéo'\n  Share Playlist: 'Partager la playlist'\n  Copy Link: 'Copier le lien'\n  Open Link: 'Ouvrir le lien'\n  Copy Embed: 'Copier le code d''intégration'\n  Open Embed: 'Ouvrir le code d''intégration'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Individious copié dans le presse-papier'\n  Invidious Embed URL copied to clipboard: 'URL d''intégration Individious copié dans le presse-papier'\n  YouTube URL copied to clipboard: 'URL YouTube copié dans le presse-papiers'\n  YouTube Embed URL copied to clipboard: 'URL d''intégration YouTube copié dans le presse-papiers'\n  Include Timestamp: Inclure l'horodatage\n  YouTube Channel URL copied to clipboard: L'URL YouTube de la chaîne est copiée dans le presse-papiers\n  Invidious Channel URL copied to clipboard: L'URL Invidious de la chaîne est copiée dans le presse-papiers\n  Share Channel: Partager la chaîne\n  Share Post: Partager la publication\nMini Player: 'Mini-lecteur'\nComments:\n  Comments: 'Commentaires'\n  Click to View Comments: 'Afficher les commentaires'\n  Getting comment replies, please wait: 'Récupération des commentaires, veuillez patienter'\n  Hide Comments: 'Masquer les commentaires'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Il n''y a aucun commentaire pour cette vidéo'\n  Load More Comments: 'Charger plus de commentaires'\n  There are no more comments for this video: Il n'y a plus de commentaires pour cette vidéo\n  Newest first: Les plus récents d'abord\n  Top comments: Top des commentaires\n  Show More Replies: Afficher plus de réponses\n  Pinned by: Épinglé par\n  Member: Membre\n  Hearted: Aimé\n  View {replyCount} replies: Voir 1 réponse | Voir {replyCount} réponses\n  Subscribed: Abonné(e)\n  There are no comments available for this post: Il n'y a pas de commentaire associé à ce message\n  Hide {replyCount} replies: Masquer 1 réponse | Masquer {replyCount} réponses\n  View 1 reply from {channelName}: Voir 1 réponse de {channelName}\n  View {replyCount} replies from {channelName} and others: Afficher {replyCount} réponses de {channelName} et autres\nUp Next: 'À suivre'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Erreur d’API locale (cliquez pour copier)'\nInvidious API Error (Click to copy): 'Erreur d''API Invidious (Cliquez pour copier)'\nFalling back to Invidious API: 'Revenir à l''API Invidious'\nFalling back to Local API: 'Revenir à l''API locale'\nLoop is now disabled: 'La boucle est maintenant désactivée'\nLoop is now enabled: 'La boucle est maintenant activée'\nShuffle is now disabled: 'Mode aléatoire désactivé'\nShuffle is now enabled: 'Mode aléatoire activé'\nPlaying Next Video: 'Lecture de la vidéo suivante'\nPlaying Previous Video: 'Lecture de la vidéo précédente'\nCanceled next video autoplay: 'Annuler la lecture automatique'\n'The playlist has ended. Enable loop to continue playing': 'La playlist est terminée. Activez la lecture en boucle pour continuer'\n\nYes: 'Oui'\nNo: 'Non'\nLocale Name: Français\nProfile:\n  '{profile} is now the active profile': '{profile} est maintenant le profil actif'\n  Your default profile has been changed to your primary profile: Votre profil par défaut a été modifié en votre profil principal\n  Removed {profile} from your profiles: Supprimer {profile} de vos profils\n  Your default profile has been set to {profile}: Votre profil par défaut a été fixé à {profile}\n  Profile has been updated: Le profil a été mis à jour\n  Profile has been created: Le profil a été créé\n  Your profile name cannot be empty: Le nom de votre profil ne peut pas être vide\n  All subscriptions will also be deleted.: Tous les abonnements seront également supprimés.\n  Are you sure you want to delete this profile?: Êtes-vous sûr(e) de vouloir supprimer ce profil ?\n  Delete Profile: Supprimer le profil\n  Make Default Profile: Établir un profil par défaut\n  Update Profile: Mettre à jour le profil\n  Create Profile: Créer un profil\n  Profile Preview: Aperçu du profil\n  Custom Color: Couleur personnalisée\n  Color Picker: Sélecteur de couleurs\n  Edit Profile: Modifier le profil\n  Create New Profile: Créer un nouveau profil\n  Profile Manager: Gestionnaire de profil\n  All Channels: Toutes les chaînes\n  Profile Select: Sélection du profil\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Êtes-vous sûr(e) de vouloir supprimer les chaînes sélectionnées ?  Ceci ne supprimera pas la chaîne de tout autre profil.\n  Subscription List: Liste des abonnements\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Ceci est votre profil principal.  Êtes-vous sûr(e) de vouloir supprimer les chaînes sélectionnées ?  Les mêmes chaînes seront supprimées dans tous les profils où elles se trouvent.\n  No channel(s) have been selected: Aucune chaîne(s) n'a été sélectionnée\n  Add Selected To Profile: Ajouter la sélection au profil\n  Delete Selected: Supprimer la sélection\n  Select None: Ne rien sélectionner\n  Select All: Tout sélectionner\n  '{number} selected': '{number} sélectionné(s)'\n  Other Channels: Autres chaînes\n  Profile Filter: Filtre de profil\n  Profile Settings: Profil\n  Toggle Profile List: Afficher la liste des profils\n  Open Profile Dropdown: Ouvrir la liste déroulante du profil\n  Close Profile Dropdown: Fermer la liste déroulante du profil\n  Profile Name: Nom du profil\n  Edit Profile Name: Modifier le nom du profil\n  Create Profile Name: Créer un nom de profil\nThe playlist has been reversed: La playlist a été inversée\nA new blog is now available, {blogTitle}. Click to view more: Un nouveau billet de blog est maintenant disponible, {blogTitle}. Cliquez pour en savoir plus\nDownload From Site: Télécharger depuis le site\nVersion {versionNumber} is now available!  Click for more details: La version {versionNumber} est maintenant disponible !  Cliquez pour plus de détails\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Cette vidéo est indisponible car elle n'est pas dans un format valide. Cela peut arriver en raison de restrictions d'accès dans certains pays.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Lorsqu'il est activé, FreeTube utilisera RSS au lieu de sa méthode par défaut pour récupérer votre flux d'abonnement. RSS est plus rapide et empêche le blocage d'IP, mais ne fournit pas certaines informations comme la durée de la vidéo, le statut en direct ou les commentaires\n    Fetch Automatically: Lorsque cette option est activée, FreeTube récupère automatiquement le flux de votre abonnement au démarrage et à l'ouverture d'une nouvelle fenêtre.\n  Player Settings:\n    Default Video Format: Définir les formats utilisés lors de la lecture d'une vidéo. Les formats DASH peuvent être lus en qualité supérieure. Les formats Legacy sont limités à un maximum de 360p mais utilisent moins de bande passante. Les formats audio sont des flux audio uniquement.\n    Proxy Videos Through Invidious: Se connectera à Invidious pour lire des vidéos au lieu d'établir une connexion directe avec YouTube.\n    Scroll Playback Rate Over Video Player: Lorsque le curseur se trouve sur la vidéo, maintenez la touche Contrôle (touche Commande sur Mac) enfoncée et faites défiler la molette de la souris vers l'avant ou l'arrière pour contrôler la vitesse de lecture. Maintenez la touche Contrôle (touche Commande sur Mac) enfoncée et cliquez sur le bouton gauche de la souris pour revenir rapidement à la vitesse de lecture par défaut (1x, sauf si elle a été modifiée dans les paramètres).\n    Skip by Scrolling Over Video Player: Utilisez la molette de défilement pour passer d'une vidéo à l'autre, en style MPV.\n  General Settings:\n    Invidious Instance: L'instance Invidious à laquelle FreeTube se connectera pour les appels API.\n    Thumbnail Preference: Toutes les miniatures dans FreeTube seront remplacées par une image extraite de la vidéo, floutée ou masquée, au lieu de la miniature par défaut.\n    Fallback to Non-Preferred Backend on Failure: Lorsque votre API préférée a un problème, FreeTube tentera automatiquement d'utiliser votre API non préférée comme méthode de secours lorsqu'elle est activée.\n    Preferred API Backend: 'Choisissez l’API interne que FreeTube utilise pour obtenir les données : l’API locale est un extracteur intégré, l’API Invidious nécessite un serveur Invidious pour se connecter.'\n    Region for Trending: Ceci vous permet de choisir les vidéos tendance du pays que vous souhaitez afficher.\n    External Link Handling: \"Choisissez le comportement par défaut quand on clique sur un lien qui ne peut être ouvert dans FreeTube.\\nPar défaut, FreeTube ouvrira le lien dans votre navigateur par défaut.\\n\"\n    Open Deep Links In New Window: Les URL transmises à FreeTube, par exemple via des extensions de redirection d'un navigateur web ou via des arguments en ligne de commande, seront ouvertes dans une nouvelle fenêtre.\n  External Player Settings:\n    Custom External Player Arguments: Tous les arguments de ligne de commande personnalisés, que vous souhaitez transmettre au lecteur externe.\n    Ignore Warnings: Suppression des avertissements lorsque le lecteur externe actuel ne prend pas en charge l'action en cours (par exemple, inversion des playlists, etc.).\n    Custom External Player Executable: Par défaut, FreeTube suppose que le lecteur externe choisi peut être trouvé via la variable d'environnement PATH. Si nécessaire, un chemin personnalisé peut être défini ici.\n    External Player: La sélection du lecteur externe affichera une icône sur la miniature qui ouvrira la vidéo (playlist, si prise en charge) dans le lecteur externe. Attention, les paramètres Invidious n'affectent pas les lecteurs externes.\n    DefaultCustomArgumentsTemplate: '(Par défaut : « {defaultCustomArguments} »)'\n    Ignore Default Arguments: Ne pas envoyer d'arguments par défaut au lecteur externe en dehors de l'URL de la vidéo (par exemple, la vitesse de lecture, l'URL de la playlist, etc...). Les arguments personnalisés seront toujours transmis.\n  Experimental Settings:\n    Replace HTTP Cache: Désactive le cache HTTP d'Electron basé sur le disque et active un cache d'image personnalisé en mémoire. Ceci entraînera une augmentation de l'utilisation de la mémoire vive.\n  Distraction Free Settings:\n    Hide Channels: Entrez un identifiant de chaîne pour empêcher toutes les vidéos, les playlists et la chaîne elle-même d'apparaître dans les recherches, dans les catégories Tendances, Plus populaires et Recommandés. L'identifiant de la chaîne entré doit correspondre exactement et est sensible aux majuscules.\n    Hide Subscriptions Live: Ce paramètre est remplacé par le paramètre « {appWideSetting} » applicable à l'ensemble de l'application, dans la section « {subsection} » de la section « {settingsSection} »\n    Hide Videos, Playlists and Channels Containing Text: Saisissez un mot, un fragment de mot ou une phrase (insensible à la casse) pour masquer toutes les vidéos, playlists et chaînes dont le titre original contient ce mot ou cette phrase dans l'ensemble de FreeTube, à l'exception de l'historique, de vos playlists et des vidéos contenues dans les playlists.\n    Hide Videos on Watch: Masque les vidéos visionnées des onglets Vidéos, Shorts, En direct des pages Abonnements et Chaînes. Ceci n'a pas d'effet sur l'onglet Accueil des pages Chaînes\n  SponsorBlock Settings:\n    UseDeArrowTitles: Remplacer les titres des vidéos par des titres proposés par les utilisateurs de DeArrow.\n    UseDeArrowThumbnails: Remplacer les miniatures des vidéos par les miniatures de DeArrow.\nMore: Plus\nPlaying Next Video Interval: Lecture de la prochaine vidéo en un rien de temps. Cliquez pour annuler. | Lecture de la prochaine vidéo dans {nextVideoInterval} seconde. Cliquer pour annuler. | Lecture de la vidéo suivante dans {nextVideoInterval} secondes. Cliquer pour annuler.\nUnknown YouTube url type, cannot be opened in app: Type d'URL YouTube inconnu, ne peut pas être ouvert dans l'application\nOpen New Window: Ouvrir une nouvelle fenêtre\nDefault Invidious instance has been cleared: L'instance Invidious par défaut a été effacée\nDefault Invidious instance has been set to {instance}: L'instance Invidious par défaut a été définie sur {instance}\nSearch Bar:\n  Clear Input: Effacer l'entrée\n  Remove: Retirer\nAre you sure you want to open this link?: Êtes-vous sûr(e) de vouloir ouvrir ce lien ?\nExternal link opening has been disabled in the general settings: L'ouverture des liens externes a été désactivée dans les paramètres généraux\nScreenshot Success: Capture d'écran enregistrée\nScreenshot Error: La capture d’écran a échoué. {error}\nNew Window: Nouvelle fenêtre\nChannels:\n  Channels: Chaînes\n  Title: Liste des chaînes\n  Empty: Votre liste de chaînes est actuellement vide.\n  Search bar placeholder: Rechercher des chaînes\n  Count: '{number} chaîne(s) trouvée(s).'\n  Unsubscribe Prompt: Êtes-vous sûr(e) de vouloir vous désabonner de « {channelName} » ?\nClipboard:\n  Copy failed: La copie dans le presse-papiers a échoué\n  Cannot access clipboard without a secure connection: Impossible d'accéder au presse-papiers sans une connexion sécurisée\nChapters:\n  Chapters: Chapitres\n  Key Moments: Moments clés\nPreferences: Préférences\nOk: OK\nHashtag:\n  Hashtag: Mot-clé\n  This hashtag does not currently have any videos: Ce mot-clé n'a actuellement aucune vidéo\nGo to page: Aller à {page}\nChannel Hidden: '{channel} ajouté au filtre de chaîne'\nChannel Unhidden: '{channel} retiré du filtre de chaîne'\nTrimmed input must be at least N characters long: L'entrée tronquée doit comporter au moins 1 caractère | L'entrée tronquée doit comporter au moins {length} caractères\nTag already exists: L'étiquette « {tagName} » existe déjà\nAge Restricted:\n  This channel is age restricted: Cette chaîne est soumise à des restrictions d'âge\n  This video is age restricted: Cette vidéo est soumise à des restrictions d'âge\nClose Banner: Fermer la bannière\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: '{label} : {value}'\ncheckmark: ✓\nFeed:\n  Feed Last Updated: 'Dernière mise à jour du flux {feedName} : {date}'\n  Refresh Feed: Rafraîchir {subscriptionName}\nMoments Ago: il y a quelques instants\nYes, Delete: Oui, effacer\nYes, Restart: Oui, redémarrer\nYes, Open Link: Oui, ouvrir le lien\nCancel: Annuler\nSearch character limit: La recherche dépasse le nombre maximale de caractères {searchCharacterLimit}\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Sous-titres\n    Closed Captions: ST sourds et malentendants\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nouveau\n    3D: 3D\nshortcutJoinOperator: +\nKeys:\n  ctrl: Ctrl\n  arrowdown: Flèche bas\n  arrowleft: Flèche gauche\n  arrowright: Flèche droite\n  arrowup: Flèche haut\n  alt: Alt\n  enter: Entrée\n  plus: Plus\n  shift: Maj\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: Clic droit ou maintenez pour voir l’historique\nAutoplay Interruption Timer: Lecture automatique annulée après {autoplayInterruptionIntervalHours} heures d'inactivité\nDescription:\n  Expand Description: '...plus'\n  Collapse Description: Montrer moins\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Raccourcis clavier\n  Sections:\n    Video:\n      Playback: 'Vidéo : Lecture'\n      General: 'Vidéo : Général'\n    App:\n      General: 'Application : Générale'\n      Situational: 'Application : Situationnelle'\n  Show Keyboard Shortcuts: Afficher les raccourcis clavier\n  History Forward: Aller à la page suivante\n  Navigate to Settings: Naviguer vers la page des paramètres\n  Navigate to History: Naviguer vers la page de l'historique\n  Refresh: Actualiser le flux avec le contenu le plus récent\n  Captions: Activer/Désactiver les sous-titres\n  Stats: Afficher les statistiques de la vidéo\n  Picture in Picture: Activer/Désactiver le mode Image dans l'image\n  Play: Activer/Désactiver la lecture/pause\n  Large Fast Forward: Avancer de 10 secondes / Avancer rapidement la vidéo en fonction de la vitesse de lecture actuelle\n  Mute: Activer/Désactiver le son\n  Decrease Video Speed: Diminuer la vitesse de la vidéo en fonction de l'intervalle de la vitesse de lecture vidéo\n  Fullscreen: 'Activer/désactiver le plein écran'\n  Increase Video Speed: Augmenter la vitesse de la vidéo en fonction de l'intervalle de la vitesse de lecture vidéo\n  New Window: Créer une nouvelle fenêtre\n  Large Rewind: Rembobiner de 10 secondes / Rembobiner la vidéo en fonction de la vitesse de lecture actuelle\n  History Backward: Revenir à la page précédente\n  Focus Secondary Search: Mettre l'accent sur la barre de recherche secondaire (si elle est présente)\n  Theatre Mode: Activer/désactiver le mode cinéma\n  Take Screenshot: Faire une capture d'écran\n  Minimize Window: Minimiser la fenêtre\n  Close Window: Fermer la fenêtre\n  Toggle Developer Tools: Activer/désactiver les outils de développement\n  Reset Zoom: Réinitialiser le niveau de zoom / l'échelle de l'interface utilisateur\n  Zoom In: Zoom avant\n  Zoom Out: Zoom arrière\n  Focus Search: Mettre le focus sur la barre de recherche\n  Search in New Window: Rechercher dans une nouvelle fenêtre\n  Last Frame: Image précédente (lorsque la lecture est en pause)\n  Next Frame: Image suivante (lorsque la lecture est en pause)\n  Volume Up: Augmenter le volume\n  Volume Down: Réduire le volume\n  Small Rewind: Rembobiner X secondes en fonction de l'intervalle de rembobinage et de la vitesse de lecture vidéo actuelle\n  Small Fast Forward: Avancer de X secondes en fonction de l'intervalle d'avance rapide et de la vitesse de lecture vidéo actuelle\n  Last Chapter: Dernier chapitre\n  Next Chapter: Chapitre suivant\n  Full Window: Activer/désactiver la fenêtre maximisée\n  Skip by Tenths: Sauter dans la vidéo par pourcentage (3 sauts pour atteindre 30 % de la durée)\n  Home: Aller au début de la vidéo\n  End: Aller à la fin de la vidéo\n  Skip to Next Video: Passer à la vidéo suivante dans la playlist ou à la vidéo recommandée suivante\n  Skip to Previous Video: Revenir à la vidéo précédente dans la playlist\nshortcutLabelSeparator: ｜\nCompact side navigation: Navigation latérale compacte\nExpand side navigation: Développer la navigation latérale\n"
  },
  {
    "path": "static/locales/gl.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'galego'\n\n# Webkit Menu Bar\nFile: 'Arquivo'\nQuit: 'Saír'\nEdit: 'Editar'\nUndo: 'Desfacer'\nRedo: 'Refacer'\nCut: 'Cortar'\nCopy: 'Copiar'\nPaste: 'Pegar'\nDelete: 'Eliminar'\nSelect all: 'Seleccionar todo'\nToggle Developer Tools: 'Activar Ferramentas de Desenvolvedor'\nActual size: 'Tamaño actual'\nZoom in: 'Agrandar'\nZoom out: 'Reducir'\nToggle fullscreen: 'Activar pantalla completa'\nWindow: 'Ventá'\nMinimize: 'Minimizar'\nClose: 'Pechar'\nBack: 'Atrás'\nForward: 'Adiante'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vídeos'\n  Posts: Publicacións\n\n  Shorts: Cortos\n  Live: En vivo\n  Sort By: 'Ordenar por'\nVersion {versionNumber} is now available!  Click for more details: 'A versión {versionNumber} está dispoñible!  Fai clic para veres máis detalles'\nDownload From Site: 'Descargar do sitio'\nA new blog is now available, {blogTitle}. Click to view more: 'Hai unha nova entrada no blog dispoñible, {blogTitle}. Fai clic para veres máis'\n\n# Search Bar\nSearch / Go to URL: 'Buscar / Ir a URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Buscar filtros'\n  Sort By:\n    Most Relevant: 'Máis relevante'\n    Rating: 'Valoración'\n    Upload Date: 'Data de subida'\n    View Count: 'Visualizacións'\n  Time:\n    Time: 'Tempo'\n    Any Time: 'Cando queiras'\n    Last Hour: 'Última hora'\n    Today: 'Hoxe'\n    This Week: 'Esta semana'\n    This Month: 'Este mes'\n    This Year: 'Este ano'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Tódolos tipos'\n    Videos: 'Vídeos'\n    Channels: 'Canles'\n    #& Playlists\n    Movies: Películas\n  Duration:\n    Duration: 'Duración'\n    All Durations: 'Tódalas duracións'\n    Short (< 4 minutes): 'Curta (< 4 minutos)'\n    Long (> 20 minutes): 'Longa (> 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Medio (4-20 minutos)\n  Search Results: 'Resultados da busca'\n  Fetching results. Please wait: 'Buscando resultados. Por favor, agarda'\n  Fetch more results: 'Buscar máis resultados'\n# Sidebar\n  There are no more results for this search: Non hai máis resultados nesta busca\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subscricións'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Este perfil ten un gran número de subscricións.  Forzar ás RSS para evitar a limitación da taxa'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'A túa listaxe de subscricións está baleira. Engade algunhas para as ver aquí.'\n  Load More Videos: 'Cargar máis vídeos'\n  Error Channels: Canles con erros\n  Disabled Automatic Fetching: Desactivaches a obtención automática de subscricións. Actualiza as subscricións para velos aquí.\n  Empty Channels: As túas canles subscritas actualmente non teñen ningún vídeo.\nTrending:\n  Trending: 'Tendencias'\n  Gaming: Xogos\n  Trending Tabs: Pestanas das tendencias\nMost Popular: 'Máis populares'\nPlaylists: 'Listaxes de reprodución'\nUser Playlists:\n  Your Playlists: 'As túas listaxes de reprodución'\n  Empty Search Message: Non hai vídeos nesta lista de reprodución que coincidan coa túa busca\n  Search bar placeholder: Atopar na lista de reprodución\nHistory:\n  # On History Page\n  History: 'Histórico'\n  Watch History: 'Histórico de visualizacións'\n  Your history list is currently empty.: 'A túa listaxe histórica está baleira.'\n  Empty Search Message: Non hai vídeos no teu historial que coincidan coa túa busca\n  Search bar placeholder: Atopar na historia\nSettings:\n  # On Settings Page\n  Settings: 'Axustes'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Queres reiniciar a aplicación para aplicar os cambios?'\n  General Settings:\n    General Settings: 'Axustes xerais'\n    Check for Updates: 'Comprobar actualizacións'\n    Check for Latest Blog Posts: 'Comprobar se hai novas entradas no blog'\n    Fallback to Non-Preferred Backend on Failure: 'Usar motor API non preferido en caso de falla'\n    Enable Search Suggestions: 'Activar suxestións de busca'\n    Default Landing Page: 'Páxina inicial'\n    Locale Preference: 'Preferencia de localización'\n    Preferred API Backend:\n      Preferred API Backend: 'Motor API principal'\n      Local API: 'API local'\n      Invidious API: 'API de Invidious'\n    Video View Type:\n      Video View Type: 'Disposición dos vídeos'\n      Grid: 'Grella'\n      List: 'Listaxe'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencia de miniaturas'\n      Default: 'Por defecto'\n      Beginning: 'Principio'\n      Middle: 'Metade'\n      End: 'Final'\n    Region for Trending: 'Rexión para as tendencias'\n        #! List countries\n    View all Invidious instance information: Ver todala información da instancia de Invidious\n    System Default: Sistema predeterminado\n    Clear Default Instance: Borrar a instancia por defecto\n    Set Current Instance as Default: Definir a instancia actual como predeterminada\n    Current instance will be randomized on startup: A instancia actual será aleatoria no arranque\n    No default instance has been set: Ningunha instancia foi habilitada por defecto\n    The currently set default instance is {instance}: A Instancia Actualmente Habilitada Por Defecto é {instance}\n    Current Invidious Instance: Instancia Actual de Invidious\n    External Link Handling:\n      No Action: Ningunha acción\n      Ask Before Opening Link: Pregunta antes de abrila ligazón\n      External Link Handling: Manexo das ligazóns externas\n      Open Link: Abrir ligazón\n  Theme Settings:\n    Theme Settings: 'Axustes de tema'\n    Match Top Bar with Main Color: 'Combinar cor principal coa barra superior'\n    Expand Side Bar by Default: 'Expandir barra lateral por defecto'\n    Disable Smooth Scrolling: 'Desactivar desprazamento suavizado'\n    UI Scale: 'Escala da interface'\n    Base Theme:\n      Base Theme: 'Tema base'\n      Black: 'Negro'\n      Dark: 'Escuro'\n      Light: 'Claro'\n      Dracula: 'Drácula'\n      System Default: Predeterminado polo sistema\n      Catppuccin Mocha: Moca Catppuccin\n    Main Color Theme:\n      Main Color Theme: 'Cor principal'\n      Red: 'Vermello'\n      Pink: 'Rosa'\n      Purple: 'Morado'\n      Deep Purple: 'Morado escuro'\n      Indigo: 'Índigo'\n      Blue: 'Azul'\n      Light Blue: 'Azul claro'\n      Cyan: 'Ciano'\n      Teal: 'Azul petróleo'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Verde lima'\n      Yellow: 'Amarelo'\n      Amber: 'Ámbar'\n      Orange: 'Laranxa'\n      Deep Orange: 'Laranxa escuro'\n      Dracula Cyan: 'Drácula Ciano'\n      Dracula Green: 'Drácula Verde'\n      Dracula Orange: 'Drácula Laranxa'\n      Dracula Pink: 'Drácula Rosa'\n      Dracula Purple: 'Drácula Morado'\n      Dracula Red: 'Drácula Vermello'\n      Dracula Yellow: 'Drácula Amarelo'\n      Catppuccin Mocha Green: Catppuccin Mocha Verde\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Auga de Rosas\n      Catppuccin Mocha Pink: Catppuccin Mocha Rosa\n      Catppuccin Mocha Red: Catppuccin Mocha Vermello\n      Catppuccin Mocha Peach: Catppuccin Mocha Pexego\n      Catppuccin Mocha Yellow: Catppuccin Mocha Amarelo\n      Catppuccin Mocha Teal: Catppuccin Mocha verde azulado\n      Catppuccin Mocha Sky: Catppuccin Mocha Ceo\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Zafiro\n      Catppuccin Mocha Blue: Catppuccin Mocha Azul\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavanda\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamenco\n      Catppuccin Mocha Mauve: Catppuccin Mocha Malva\n      Catppuccin Mocha Maroon: Catppuccin Mocha Granate\n    Secondary Color Theme: 'Cor secundaria'\n        #* Main Color Theme\n    Hide Side Bar Labels: Ocultalas etiquetas da barra lateral\n    Hide FreeTube Header Logo: Ocultalo logotipo de Freetube na cabeceira\n  Player Settings:\n    Player Settings: 'Axustes do reprodutor'\n    Play Next Video: 'Reproducir próximo vídeo'\n    Turn on Subtitles by Default: 'Activar subtítulos por defecto'\n    Autoplay Videos: 'Reproducir vídeos automaticamente'\n    Proxy Videos Through Invidious: 'Utilizar Invidious como intermediario'\n    Autoplay Playlists: 'Reproducir listaxes de reprodución automaticamente'\n    Enable Theatre Mode by Default: 'Activar modo cinema por defecto'\n    Default Volume: 'Volume predeterminado'\n    Default Playback Rate: 'Velocidade de reprodución predeterminada'\n    Default Video Format:\n      Default Video Format: 'Formato de vídeo predeterminado'\n      Dash Formats: 'Formato dash'\n      Legacy Formats: 'Formato antigo (Legacy)'\n      Audio Formats: 'Formato de audio'\n    Default Quality:\n      Default Quality: 'Calidade predeterminada'\n      Auto: 'Automática'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Seguinte intervalo do vídeo\n    Display Play Button In Video Player: Amosar o botón de Reprodución no reprodutor de vídeo\n    Scroll Volume Over Video Player: Desprazar o volume do reprodutor de vídeo\n    Screenshot:\n      Folder Label: Cartafol das capturas da pantalla\n      Error:\n        Forbidden Characters: Personaxes prohibidos\n        Empty File Name: Nome do ficheiro baleiro\n      Quality Label: Calidade da captura da pantalla\n      Format Label: Formato da captura da pantalla\n      Ask Path: Pregunta onde se garda o cartafol\n      File Name Tooltip: Podes usalas variables a continuación. %Y 4 díxitos do ano. %M Mes 2 díxitos. %D Día 2 díxitos. %H Hora 2 díxitos. %N minutos 2 díxitos. %S Segundo 2 díxitos. %T Milisegundos 3 díxitos. %s segundo de vídeo. %t Video Milisegundos 3 díxitos. ID de vídeo %i.\n      Folder Button: Seleccione un cartafol\n      File Name Label: Patrón do nome do fixeiro\n      Enable: Activalas capturas da pantalla\n    Video Playback Rate Interval: Intervalo da taxa da reprodución do vídeo\n    Fast-Forward / Rewind Interval: Intervalo do avance/retroceso rápido\n    Scroll Playback Rate Over Video Player: Desprácese a taxa da reprodución sobre a reproducción do vídeo\n    Max Video Playback Rate: Velocidade máxima da reprodución do vídeo\n    Enter Fullscreen on Display Rotate: Poñase a pantalla enteira o xirala pantalla\n    Skip by Scrolling Over Video Player: Saltar desprazándose polo reprodutor de vídeo\n  Privacy Settings:\n    Privacy Settings: 'Axustes de privacidade'\n    Remember History: 'Lembrar histórico'\n    Save Watched Progress: 'Gardar progreso da reprodución'\n    Clear Search Cache: 'Limpar caché de busca'\n    Are you sure you want to clear out your search cache?: 'Estás seguro de querer limpar o caché de busca?'\n    Search cache has been cleared: 'Caché de busca limpado'\n    Remove Watch History: 'Limpar histórico de reprodución'\n    Are you sure you want to remove your entire watch history?: 'Estás seguro de querer limpar por completo o histórico de busca?'\n    Watch history has been cleared: 'Histórico de busca limpado'\n    Remove All Subscriptions / Profiles: 'Limpar tódalas subscricións / perfís'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Estás seguro de querer limpar tódalas subscricións e perfís? Esta acción é irreversible.'\n    Save Watched Videos With Last Viewed Playlist: Gardalos vídeos vistos coa última lista de reprodución vista\n  Subscription Settings:\n    Subscription Settings: 'Axustes de subscricións'\n    Fetch Feeds from RSS: 'Obter subscricións a través de RSS'\n    Fetch Automatically: Obter feed automaticamente\n  Distraction Free Settings:\n    Distraction Free Settings: 'Sen distraccións'\n    Hide Video Views: 'Agochar as visualizacións nos vídeos'\n    Hide Video Likes And Dislikes: 'Agochar likes/dislikes nos vídeos'\n    Hide Channel Subscribers: 'Agochar subscritores nas canles'\n    Hide Comment Likes: 'Agochar likes dos comentarios'\n    Hide Recommended Videos: 'Agochar vídeos recomendados'\n    Hide Trending Videos: 'Agochar vídeos en tendencias'\n    Hide Popular Videos: 'Agochar vídeos populares'\n    Hide Live Chat: 'Agochar conversa en vivo'\n    Hide Active Subscriptions: Agochar subscricións activas\n    Hide Playlists: Agochar listas de reprodución\n    Hide Live Streams: Ocultalas emisións en directo\n    Hide Sharing Actions: Ocultalas accións do uso compartido\n    Hide Videos on Watch: 'Agochar vídeos visualizados'\n    Hide Video Description: Ocultala descrición do vídeo\n    Hide Comments: Ocultar comentarios\n    Hide Chapters: Agochalos capítulos\n    Hide Upcoming Premieres: Ocultalas próximas estreas\n    Hide Channels: Ocultalos vídeos das canles\n    Hide Channels Placeholder: Nome ou ID da canle\n    Display Titles Without Excessive Capitalisation: Amosalos títulos sen usar moitas maiúsculas\n  Data Settings:\n    Data Settings: 'Axustes dos datos'\n    Select Export Type: 'Escoller tipo de exportación'\n    Import Subscriptions: 'Importar subscricións'\n    Export Subscriptions: 'Exportar subscricións'\n    Export FreeTube: 'Exportar Freetube'\n    Export YouTube: 'Exportar YouTube'\n    Export NewPipe: 'Exportar NewPipe'\n    Import History: 'Importar histórico'\n    Export History: 'Exportar histórico'\n    Profile object has insufficient data, skipping item: 'Este perfil ten datos insuficientes, omitindo o elemento'\n    All subscriptions and profiles have been successfully imported: 'Tódalas subscricións e perfís foron importados correctamente'\n    All subscriptions have been successfully imported: 'Tódalas subscricións foron importadas correctamente'\n    Invalid subscriptions file: 'Ficheiro de subcricións inválido'\n    Invalid history file: 'Ficheiro de histórico inválido'\n    Subscriptions have been successfully exported: 'As subscricións foron exportadas correctamente'\n    History object has insufficient data, skipping item: 'O historial ten datos insuficientes, omitindo o elemento'\n    All watched history has been successfully imported: 'O histórico de visualizacións foi importado correctamente'\n    All watched history has been successfully exported: 'O histórico de visualizacións foi exportado correctamente'\n    Unable to read file: 'Imposible ler o ficheiro'\n    Unable to write file: 'Imposible escribir o ficheiro'\n    Unknown data key: 'Chave de datos descoñecida'\n    How do I import my subscriptions?: 'Como podo importar as subscricións?'\n    Manage Subscriptions: Xestionar subscricións\n    Playlist insufficient data: Datos insuficientes para a lista de reprodución \"{playlist}\", saltándose o elemento\n    Import Playlists: Importalas listas de reprodución\n    Playlist File: Ficheiro da lista da reprodución\n    Subscription File: Ficheiro da subscrición\n    History File: Ficheiro do historial\n    All playlists has been successfully imported: Importáronse con éxito todalas listas de reprodución\n    All playlists has been successfully exported: Todalas listas de reprodución exportáronse correctamente\n    Export Playlists: Exportalas listas de reprodución\n\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar cando se omita o segmento do patrocinador\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API SponsorBlock (O predeterminado é https://sponsor.ajay.app)\n    Enable SponsorBlock: Activar SponsorBlock\n    SponsorBlock Settings: Configuración do SponsorBlock\n    Skip Options:\n      Prompt To Skip: Solicitar saltar\n      Skip Option: Omitila opción\n      Auto Skip: Salto automático\n      Show In Seek Bar: Mostrala na barra da busca\n      Do Nothing: Non fagas nada\n    Category Color: Cor da categoría\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Erro ao obter información de rede. O teu proxy está configurado correctamente?\n    City: Cidade\n    Region: Rexión\n    Country: País\n    Ip: IP\n    Your Info: A túa información\n    Test Proxy: Probar Proxy\n    Clicking on Test Proxy will send a request to: Ao premer en Probar Proxy, enviarase unha solicitude a\n    Proxy Port Number: Número do porto de Proxy\n    Proxy Host: Anfitrión de Proxy\n    Proxy Protocol: Protocolo do Proxy\n    Enable Tor / Proxy: Activar Tor / Proxy\n    Proxy Settings: Axustes do Proxy\n  External Player Settings:\n    Custom External Player Arguments: Argumentos do reprodutor externo personalizado\n    Custom External Player Executable: Reprodutor externo personalizado executable\n    Ignore Unsupported Action Warnings: Ignorar as advertencias de accións non soportadas\n    External Player: Reprodutor externo\n    External Player Settings: Configuración do reprodutor externo\n    Players:\n      None:\n        Name: Ningún\n  Parental Control Settings:\n    Parental Control Settings: Configuración do control parental\n    Hide Unsubscribe Button: Ocultalo botón para cancelala subscrición\n    Show Family Friendly Only: Mostrar só para as familias\n    Hide Search Bar: Ocultala barra de busca\n  Experimental Settings:\n    Experimental Settings: Configuracións experimentais\n    Warning: Estas opcións de configuración son experimentais, poden causar fallos mentres están activadas. É moi recomendable facer copias de seguridade. Use baixo o seu propio risco!\n    Replace HTTP Cache: Substitúe a caché HTTP\n  Password Settings:\n    Password Settings: Configuración do contrasinal\n    Set Password To Prevent Access: Establece un contrasinal para impedilo acceso á configuración\n    Set Password: Establecelo contrasinal\n    Remove Password: Eliminar contrasinal\n  Password Dialog:\n    Password: Contrasinal\n    Enter Password To Unlock: Introduce o contrasinal para desbloqueala configuración\nAbout:\n  #On About page\n  About: 'Sobre'\n  #& About\n  Donate: Doar\n  these people and projects: aquelas persoas e proxectos\n  Credits: Créditos\n  Translate: Traducir\n  room rules: normas do cuarto\n  Chat on Matrix: Conversa en Matrix\n  Mastodon: Mastodon\n  Email: Correo electrónico\n  Blog: Blog\n  Website: Páxina web\n  Please check for duplicates before posting: Comprobe se hai duplicados antes de publicar\n  GitHub issues: Problemas de GitHub\n  Report a problem: Informar dun problema\n  FAQ: Cuestións frecuentes\n  FreeTube Wiki: Wiki de FreeTube\n  Help: Axuda\n  GitHub releases: Lanzamentos de GitHub\n  Downloads / Changelog: Descargas / Rexistro de cambios\n  Source code: Código fonte\n  Beta: Beta\nProfile:\n  Profile Select: 'Selección de perfil'\n  All Channels: 'Tódalas canles'\n  Profile Manager: 'Xestor de perfís'\n  Create New Profile: 'Crear novo perfil'\n  Edit Profile: 'Editar perfil'\n  Color Picker: 'Selector de cor'\n  Custom Color: 'Cor personalizada'\n  Profile Preview: 'Vista previa do perfil'\n  Create Profile: 'Crear perfil'\n  Update Profile: 'Actualizar perfil'\n  Make Default Profile: 'Converter en perfil predeterminado'\n  Delete Profile: 'Eliminar perfil'\n  Are you sure you want to delete this profile?: 'Estás seguro de querer eliminar este perfil?'\n  All subscriptions will also be deleted.: 'Tamén se eliminarán tódalas subscricións.'\n  Your profile name cannot be empty: 'O nome do perfil non pode estar en branco'\n  Profile has been created: 'Creouse o perfil'\n  Profile has been updated: 'Actualizouse o perfil'\n  Your default profile has been set to {profile}: '{profile} é agora o teu perfil predeterminado'\n  Removed {profile} from your profiles: 'Eliminouse {profile} dos teus perfís'\n  Your default profile has been changed to your primary profile: 'O teu perfil predeterminado cambiouse ao teu perfil primario'\n  '{profile} is now the active profile': '{profile} é agora o perfil activo'\n  Subscription List: 'Listaxe de subcricións'\n  Other Channels: 'Outras canles'\n  '{number} selected': '{number} seleccionado'\n  Select All: 'Seleccionar todos'\n  Select None: 'Non seleccionar ningún'\n  Delete Selected: 'Eliminar seleccionados'\n  Add Selected To Profile: 'Engadir seleccionados ao perfil'\n  No channel(s) have been selected: 'Ningunha canle foi seleccionada'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Este é o teu perfil principal.  Estás seguro de querer eliminar as canles seleccionadas?  Eliminaranse as mesmas en calquera perfil no que se atopen.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Estás seguro de querer eliminar as canles seleccionadas?  Esta acción non as eliminará de ningún outro perfil.'\n#On Channel Page\n  Profile Filter: Filtro por perfís\n  Profile Settings: Configuración do perfil\nChannel:\n  Subscribe: 'Subscribirse'\n  Unsubscribe: 'Desubscribirse'\n  Channel has been removed from your subscriptions: 'Esta canle foi eliminada das túas subscricións'\n  Removed subscription from {count} other channel(s): 'Eliminouse a subscrición de {count} a outra(s) canle(s)'\n  Added channel to your subscriptions: 'Canle engadida ás túas subscricións'\n  Search Channel: 'Buscar na canle'\n  Your search results have returned 0 results: 'A busca non atopou resultados'\n  Videos:\n    Videos: 'Vídeos'\n    This channel does not currently have any videos: 'Esta canle aínda non ten ningún vídeo'\n    Sort Types:\n      Newest: 'Máis recentes'\n      Oldest: 'Máis antigos'\n      Most Popular: 'Máis populares'\n  Playlists:\n    Playlists: 'Listaxes de reprodución'\n    This channel does not currently have any playlists: 'Esta canle non ten ningunha listaxe de reprodución actualmente'\n    Sort Types:\n      Last Video Added: 'Último vídeo engadido'\n      Newest: 'O máis recente'\n      Oldest: 'O máis antigo'\n  About:\n    About: 'Sobre'\n    Channel Description: 'Descrición da canle'\n    Featured Channels: 'Canles destacadas'\n    Tags:\n      Tags: Etiquetas\n      Search for: Busca «{tag}»\n    Details: Detalles\n    Joined: Uniuse\n    Location: Localización\n  This channel does not exist: Esta canle non existe\n  This channel does not allow searching: Esta canle non permite buscas\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Esta canle ten unha limitación de idade e actualmente non se pode ver en FreeTube.\n  Channel Tabs: Pestanas das canles\n  Posts:\n    This channel currently does not have any posts: Esta canle actualmente non ten publicacións\nVideo:\n  Mark As Watched: 'Marcar como visto'\n  Remove From History: 'Eliminar do histórico'\n  Video has been marked as watched: 'O vídeo marcouse como visto'\n  Video has been removed from your history: 'O vídeo eliminouse do teu histórico'\n  Open in YouTube: 'Abrir no YouTube'\n  Copy YouTube Link: 'Copiar ligazón de YouTube'\n  Open YouTube Embedded Player: 'Abrir reprodutor integrado de YouTube'\n  Copy YouTube Embedded Player Link: 'Copiar ligazón do reprodutor integrado de YouTube'\n  Open in Invidious: 'Abrir no Invidious'\n  Copy Invidious Link: 'Copiar ligazón de Invidious'\n  Open Channel in YouTube: 'Abrir canle no YouTube'\n  Copy YouTube Channel Link: 'Copiar ligazón de YouTube da canle'\n  Open Channel in Invidious: 'Abrir canle no Invidious'\n  Copy Invidious Channel Link: 'Copiar ligazón de Invidious da canle'\n  Views: 'Visualizacións'\n  Loop Playlist: 'Reprodución en bucle'\n  Shuffle Playlist: 'Reprodución aleatoria'\n  Reverse Playlist: 'Inverter listaxe de reprodución'\n  Previous: 'Anterior'\n  Next: 'Seguinte'\n  Watched: 'Visto'\n  Autoplay: 'Reprodución automática'\n  Starting soon, please refresh the page to check again: 'Comezará en breve. Por favor, actualiza a páxina para verificares'\n  # As in a Live Video\n  Live: 'En vivo'\n  Live Now: 'En vivo agora'\n  Live Chat: 'Chat en vivo'\n  Enable Live Chat: 'Activar chat en vivo'\n  Live Chat is currently not supported in this build.: 'O chat en vivo non está soportado nesta versión.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Chat en vivo activado.  As mensaxes aparecerán aquí ao seren enviadas.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Chat en vivo actualmente non soportado coa API de Invidious.  Precísase dunha conexión directa con YouTube.'\n  Published:\n    In less than a minute: En menos dun minuto\n  Published on: 'Publicado'\n  Streamed on: 'Transmitido'\n  Started streaming on: 'A transmisión comezou'\n#& Videos\n  External Player:\n    Unsupported Actions:\n      looping playlists: listas de reprodución en bucle\n      shuffling playlists: Listas de reprodución en aleatorio\n      reversing playlists: inverter as listas de reprodución\n      opening specific video in a playlist (falling back to opening the video): abrir vídeo específico nunha lista de reprodución (volvendo a abrir o vídeo)\n      opening playlists: abrindo as listas de reprodución\n      setting a playback rate: axustar unha taxa de reprodución\n      starting video at offset: vídeo de inicio en compensado\n    UnsupportedActionTemplate: '{externalPlayer} non admite: {action}'\n    OpeningTemplate: Abrindo {videoOrPlaylist} en {externalPlayer}...\n    playlist: lista de reprodución\n    video: vídeo\n    OpenInTemplate: Aberto en {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Música Offtopic\n    interaction: Interacción\n    self-promotion: Autopromoción\n    outro: outro\n    intro: Intro\n    sponsor: Patrocinador\n    recap: Recapitulación\n    filler: Recheo\n  Video has been removed from your saved list: Eliminouse este vídeo da lista de gardados\n  Video has been saved: Gardouse o vídeo\n  Save Video: Gardar vídeo\n  Premieres: Estreos\n  Show Super Chat Comment: Mostralos comentarios do Super Chat\n  Scroll to Bottom: Desprácese ata abaixo\n  Upcoming: Próximamente\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Ver listaxe de reprodución completa'\n  Last Updated On: 'Última actualización'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lista de reprodución\nChange Format:\n  Change Media Formats: 'Mudar formato do vídeo'\n  Use Dash Formats: 'Utilizar formato Dash'\n  Use Legacy Formats: 'Utilizar formato antigo (Legacy)'\n  Use Audio Formats: 'Utilizar formato só de audio'\n  Dash formats are not available for this video: 'Formato Dash non dispoñible para este vídeo'\n  Audio formats are not available for this video: 'Formato só de audio non dispoñible para este vídeo'\nShare:\n  Share Video: 'Compartir vídeo'\n  Share Playlist: 'Compartir listaxe de reprodución'\n  Include Timestamp: 'Incluír marcación de tempo'\n  Copy Link: 'Copiar ligazón'\n  Open Link: 'Abrir ligazón'\n  Copy Embed: 'Copiar código integrado'\n  Open Embed: 'Abrir código integrado'\n  # On Click\n  Invidious URL copied to clipboard: 'Ligazón de Invidious copiada á área de transferencia'\n  Invidious Embed URL copied to clipboard: 'Ligazón integrada de Invidious copiada á área de transferencia'\n  Invidious Channel URL copied to clipboard: 'Ligazón de Invidious da canle copiada á área de transferencia'\n  YouTube URL copied to clipboard: 'Ligazón de YouTube copiada á área de transferencia'\n  YouTube Embed URL copied to clipboard: 'Ligazón integrada de YouTube copiada á área de transferencia'\n  YouTube Channel URL copied to clipboard: 'Ligazón de YouTube da canle copiada á área de transferencia'\n\n  Share Channel: Compartilo canle\nMini Player: 'Mini-reprodutor'\nComments:\n  Comments: 'Comentarios'\n  Click to View Comments: 'Premer para ver comentarios'\n  Getting comment replies, please wait: 'Obtendo respostas ao comentario. Por favor, agarda'\n  There are no more comments for this video: 'Non hai máis comentarios neste vídeo'\n  Hide Comments: 'Agochar comentarios'\n  Top comments: 'Comentarios destacados'\n  Newest first: 'Máis recentes'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Este vídeo non contén ningún comentario'\n  Load More Comments: 'Cargar máis comentarios'\n  Pinned by: Fixado por\n  Member: Membro\n  Show More Replies: Amosar máis respostas\n  View {replyCount} replies: Consulta {replyCount} respostas\n  Hearted: Corazón\nUp Next: 'Seguintes'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Escolle o back-end que FreeTube utiliza para obter os datos. A API local é un extractor incluído. A API de Invidious require un servidor Invidious ao que se conectar.'\n    Fallback to Non-Preferred Backend on Failure: 'Cando a túa API preferida teña un problema, FreeTube tentará usar automaticamente a túa API non preferida como método alternativo cando estea activo.'\n    Thumbnail Preference: 'Todalas miniaturas de FreeTube substituiranse por un fotograma do vídeo no lugar da miniatura predeterminada.'\n    Invidious Instance: 'A instancia de Invidious á que se conectará FreeTube para as chamadas da aplicacion.'\n    Region for Trending: 'A rexión das tendencias permíteche escoller os vídeos máis populares nun Estado.'\n    External Link Handling: \"Escolla o comportamento predeterminado cando se fai clic nunha ligazón, que non se pode abrir en FreeTube.\\nDe forma predeterminada, FreeTube abrirá a ligazón na que premeches no teu navegador predeterminado.\\n\"\n  Player Settings:\n    Proxy Videos Through Invidious: 'Conectarase a Invidious para obter vídeos no canto de recorrer directamente a YouTube.'\n    Default Video Format: 'Establecelos formatos utilizados cando se reproduce un vídeo. Os formatos DASH poden reproducir calidades superiores. Os formatos legados están limitados a un máximo de 720p pero usan menos ancho de banda. Os formatos de audio son fluxos de audio só.'\n    Scroll Playback Rate Over Video Player: Mentres o cursor está sobre o vídeo, manteña premida a tecla Control (tecla Comando no Mac) e desprácese coa roda do rato cara adiante ou cara atrás para controlala velocidade da reprodución. Manteña premida a tecla Control (tecla Comando no Mac) e prema co botón esquerdo do rato para voltar rapidamente á taxa de reprodución predeterminada (1x a menos que o modificase na configuración).\n    Skip by Scrolling Over Video Player: Usala roda de desprazamento para saltalo vídeo, estilo MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Cando está activado, FreeTube usará RSS no canto do método predeterminao para obter as subscricións. RSS é máis rápido e impide o bloqueo da IP, pero non proporciona certa información como a duración dun vídeo ou se é en vivo'\n\n# Toast Messages\n    Fetch Automatically: Cando estea activado, FreeTube buscará automaticamente o teu feed da subscrición, cando se abra unha nova ventá e cando cambies de perfil.\n  External Player Settings:\n    Custom External Player Arguments: Calquera argumento de liña de comandos personalizado, que desexa que se pase ao reprodutor externo.\n    Ignore Warnings: Suprime avisos para cando os reprodutores externos actuais non apoian a acción actual (e.g. Invertendo listas de reprodución, etc.).\n    Custom External Player Executable: Por defecto, FreeTube asumirá que o reprodutor externo elixido pode atoparse a través da variable de entorno PATH. Se é necesario, pódese establecer un camiño personalizado aquí.\n    External Player: Ao escoller un reprodutor externo, aparecerá unha icona para abrilo vídeo (lista de reprodución se é compatible) no reprodutor externo, na miniatura. Aviso, a configuración de Invidious non afecta aos reprodutores externos.\n    DefaultCustomArgumentsTemplate: \"(Default: '{defaultCustomArguments}')\"\n  Experimental Settings:\n    Replace HTTP Cache: Desactivouse a caché HTTP baseada no disco de Electrons e habilita unha caché das imaxes persoalizadas na memoria. Levará a un aumento no uso da RAM.\n  Distraction Free Settings:\n    Hide Channels: Introduce o nome dunha canle ou o ID de canle para ocultar todolos vídeos, listas de reprodución e a propia canle para que non aparezan na busca ou nas tendencias. O nome da canle introducido debe coincidir completamente e distingue entre maiúsculas e minúsculas.\nLocal API Error (Click to copy): 'Erro de API local (Preme para copiar)'\nInvidious API Error (Click to copy): 'Erro de API Invidious (Preme para copiar)'\nFalling back to Invidious API: 'Recorrendo á API Invidious'\nFalling back to Local API: 'Recorrendo á API local'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Este vídeo non está dispoñible porque faltan formatos. Isto pode ocorrer debido á non dispoñibilidade do país.'\nLoop is now disabled: 'Reprodución en bucle desactivada'\nLoop is now enabled: 'Reprodución en bucle activada'\nShuffle is now disabled: 'Reprodución aleatoria desactivada'\nShuffle is now enabled: 'Reprodución aleatoria activada'\nThe playlist has been reversed: 'A listaxe de reprodución foi invertida'\nPlaying Next Video: 'A reproducir próximo vídeo'\nPlaying Previous Video: 'A reproducir vídeo anterior'\nCanceled next video autoplay: 'Cancelouse a reprodución automática do seguinte vídeo'\n'The playlist has ended. Enable loop to continue playing': 'A listaxe de reprodución rematou.  Activa a reprodución en bucle para continuar reproducindo'\n\nYes: 'Si'\nNo: 'Non'\nPlaying Next Video Interval: Reproducindo o seguinte vídeo en pouco tempo. Prema para cancelar. | Reproducindo o seguinte vídeo en {nextVideoInterval} segundo. Prema para cancelar. | Reproducindo o seguinte vídeo en {nextVideoInterval} segundos. Prema para cancelar.\nUnknown YouTube url type, cannot be opened in app: O tipo de URL de YouTube descoñecido non se pode abrir no aplicativo\nMore: Máis\nOpen New Window: Abrir nova xanela\nNew Window: Nova ventá\nChannels:\n  Channels: Canles\n  Title: Lista de canles\n  Search bar placeholder: Busca canles\n  Count: Atopouse {number} canle(s).\n  Empty: A túa lista de canles atopase baleira.\n  Unsubscribe Prompt: Estás seguro de que queres cancelar a subscrición a \"{channelName}\"?\nSearch Bar:\n  Clear Input: Borrar entrada\nAre you sure you want to open this link?: Estás seguro de que queres abrir esta ligazón?\nPreferences: Preferencias\nExternal link opening has been disabled in the general settings: A apertura das ligazóns externas desactivouse na configuración xeral\nDefault Invidious instance has been cleared: Borrouse a instancia predeterminada de Invidious\nScreenshot Error: Produciuse un erro na captura de pantalla. {error}\nDefault Invidious instance has been set to {instance}: A instancia predeterminada de Invidious estableceuse en {instance}\nClipboard:\n  Copy failed: Produciuse un erro ao copialo no portapapeis\n  Cannot access clipboard without a secure connection: Non se pode acceder ao portapapeis sen unha conexión segura\nChapters:\n  Chapters: Capítulos\nScreenshot Success: Captura da pantalla gardada como \"{filePath}\"\nOk: De acordo\nGo to page: Ir a {page}\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Activar Ferramentas de Desenvolvedor\n  Zoom Out: Reducir\n  Zoom In: Agrandar\n  Fullscreen: Activar pantalla completa\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\n"
  },
  {
    "path": "static/locales/gsw.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Schwiizerdütsch'\n\n# Webkit Menu Bar\nFile: 'Datei'\nNew Window: 'Nois Fäischter'\nQuit: 'Beände'\nEdit: 'Bearbeite'\nUndo: 'Rückgängig'\nRedo: 'Widerherstellä'\nCut: 'Usschniide'\nCopy: 'Kopierä'\nPaste: 'Iifüege'\nDelete: 'Lösche'\nSelect all: 'Alles uswähle'\nToggle Developer Tools: 'Entwicklerwerchzüüg aktivierä/deaktivierä'\nActual size: 'Originalgrössi'\nZoom in: 'Vergrösserä'\nZoom out: 'Verchlinerä'\nToggle fullscreen: 'Vollbild aktivierä'\nWindow: 'Fäischter'\nMinimize: 'Minimierä'\nClose: 'Schlüsse'\nBack: 'Zrugg'\nForward: 'Füre'\nOpen New Window: 'Nois Fäischter ufmache'\n\nVersion {versionNumber} is now available!  Click for more details: 'Version {versionNumber}\n  isch jetzt verfüegbar! Klick für meh Details.'\nDownload From Site: 'Vo de Website abelade'\nA new blog is now available, {blogTitle}. Click to view more: 'En neue Blogiitrag\n  isch jetzt verfüegbar, {blogTitle}. Klick zum en aaluege'\nAre you sure you want to open this link?: 'Bisch du sicher, dass du de Link ufmache\n  wotsch?'\n\n# Search Bar\nSearch / Go to URL: 'Sueche / Gang zu de URL'\nSearch Filters:\n  Time:\n    Last Hour: letzte stunde\n    Time: Zeit\n    Any Time: jederzeit\n    Today: Hüt\n    This Week: Die Wuche\n    This Year: Die Jahr\n    This Month: Diesen Monet\n  Duration:\n    Duration: Dauer\n    Long (> 20 minutes): Lang (> 20 Minute)\n    All Durations: Alli Dauere\n    Short (< 4 minutes): Churz (< 4 Minute)\n    Medium (4 - 20 minutes): Mittel (< 4 - 20 Minute)\n  Features:\n    HD: HD\n    Location: Ort\n    HDR: HDR\n    VR180: VR180\n    Features: Funktionen\n    4K: 4K\n    Subtitles: Undertitel\n    Creative Commons: Kreativ Commons\n    3D: 3D\n    Live: Live\n    360 Video: 360-Grad Video\n  Search Results: Suechresultat\n  Sort By:\n    Most Relevant: Am Beschte Passend\n    Upload Date: Uflad-Datum\n    Rating: Bewärtig\n    View Count: Ansichtszahl\n  Type:\n    All Types: Alli Typa\n    Videos: Vidéos\n    Movies: Filme\n    Channels: Kanäle\n    Type: Typ\n  Fetching results. Please wait: Suech Resultat. Bitte warte\n  Search Filters: Suechfilter\n  There are no more results for this search: Es git kei meh Resultat für die Suech.\n  Fetch more results: Mehr Resultat sueche\nSettings:\n  # On Settings Page\n  Theme Settings: {}\n  SponsorBlock Settings: {}\nChannel: {}\nTooltips: {}\nSearch Listing:\n  Label:\n    4K: 4K\n    VR180: VR180\n    Subtitles: Undertitel\n    360 Video: 360°\n    New: Neu\n    3D: 3D\n    8K: 8K\n    Closed Captions: Gschlosseni Undertitel\nGlobal:\n  Videos: videos\n  Counts:\n    Video Count: 1 video | {count} videos\n    Channel Count: 1 Kanal| {count} Kanal\n    Subscriber Count: 1 Abonnent| {count} Abonnent\n    View Count: 1 Aufruf |{count} Aufrufe\n    Like Count: 1 like | {count} likes\n    Comment Count: 1 Kommentar| {count} Kommentar\n    Watching Count: 1 lueget zue {count} luege zue\n  Live: live\n  Shorts: shorts\n  Sort By: Sortieren nach\nSearch character limit: Die Suchanfrage ist länger als das erlaubte Limit von {searchCharacterLimit}\n  Zeichen\nPreferences: Ihstellige\nGo to page: gehe zu\nClose Banner: Banner schließen\nSearch Bar:\n  Remove: Entferne\n  Clear Input: Eingab lösche\nRight-click or hold to see history: Rechtsklick oder drucke, um d'Geschicht z'gseh\nSubscriptions:\n  Subscriptions: Abonnemente\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Entwicklerwerchzüüg aktivierä/deaktivierä\n  Zoom In: Vergrösserä\n  Zoom Out: Verchlinerä\n  Fullscreen: Vollbild aktivierä\nProfile:\n  Select All: Alles uswähle\n"
  },
  {
    "path": "static/locales/he.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'עברית'\n\n# Webkit Menu Bar\nFile: 'קובץ'\nQuit: 'יציאה'\nEdit: 'עריכה'\nUndo: 'הסגה'\nRedo: 'לבצע שוב'\nCut: 'גזירה'\nCopy: 'העתקה'\nPaste: 'הדבקה'\nDelete: 'מחיקה'\nSelect all: 'בחירה בהכול'\nToggle Developer Tools: 'הפעלת / השבתת כלים למפתחים'\nActual size: 'גודל בפועל'\nZoom in: 'התקרבות'\nZoom out: 'התרחקות'\nToggle fullscreen: 'מיתוג ממסך מלא'\nWindow: 'חלון'\nMinimize: 'מזעור'\nClose: 'סגירה'\nBack: 'אחורה'\nForward: 'קדימה'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'סרטונים'\n  Shorts: Shorts\n  Live: בשידור חי\n  Posts: פוסטים\n  Sort By: מיון לפי\n\n  Counts:\n    Video Count: סרטון אחד | {count} סרטונים\n    Channel Count: ערוץ אחד | {count} ערוצים\n    Subscriber Count: מנוי או מנויה 1 | {count} מנויים\n    View Count: צפייה אחת | {count} צפיות\n    Watching Count: עוקב/ת | {count} עוקבים\n    Like Count: לייק | {count} לייקים\n    Comment Count: תגובה | {count} תגובות\nVersion {versionNumber} is now available!  Click for more details: 'גרסה {versionNumber} זמינה מעתה!  לחיצה תציג פרטים נוספים'\nDownload From Site: 'הורדה מאתר'\nA new blog is now available, {blogTitle}. Click to view more: 'בלוג חדש זמין, {blogTitle}. לחיצה תציג פרטים נוספים'\n\n# Search Bar\nSearch / Go to URL: 'חיפוש / מעבר לכתובת'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'מסנני חיפוש'\n  Sort By:\n    Most Relevant: 'הכי רלוונטי'\n    Rating: 'דירוג'\n    Upload Date: 'תאריך העלאה'\n    View Count: 'מס׳ צפיות'\n  Time:\n    Time: 'זמן'\n    Any Time: 'כל זמן'\n    Last Hour: 'מהשעה האחרונה'\n    Today: 'היום'\n    This Week: 'השבוע'\n    This Month: 'החודש'\n    This Year: 'השנה'\n  Type:\n    Type: 'סוג'\n    All Types: 'כל הסוגים'\n    Videos: 'סרטונים'\n    Channels: 'ערוצים'\n    #& Playlists\n    Movies: סרטים\n  Duration:\n    Duration: 'משך זמן'\n    All Durations: 'הכול'\n    Short (< 4 minutes): 'קצר (מתחת ל־4 דקות)'\n    Long (> 20 minutes): 'ארוך (מעל 20 דקות)'\n  # On Search Page\n    Medium (4 - 20 minutes): בינוני (4 - 20‏ דקות)\n  Search Results: 'תוצאות חיפוש'\n  Fetching results. Please wait: 'נאספות תוצאות. נא להמתין'\n  Fetch more results: 'חיפוש תוצאות נוספות'\n# Sidebar\n  There are no more results for this search: אין תוצאות נוספות לחיפוש הזה\n  Features:\n    Features: יכולות\n    HD: HD\n    4K: 4K\n    3D: תלת־ממד\n    Subtitles: כתוביות\n    Live: שידור חי\n    360 Video: וידאו 360\n    HDR: HDR\n    VR180: VR180\n    Location: מקום\n    Creative Commons: קריאייטיב קומונז\n  Clear Filters: פינוי מסננים\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'מינויים'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'רשימת המינויים שלך ריקה כרגע. כדי לייבא את המינויים שלך ניתן לגשת להגדרות הנתונים ולבחור בייבוא מנויים או לחפש ערוצים ולהירשם אליהם.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: לפרופיל זה יש מספר רב של מינויים. עוברים לעדכוני RSS כדי להימנע מהגבלות קצב\n  Load More Videos: לטעון סרטונים נוספים\n  Error Channels: ערוצים עם שגיאות\n  Disabled Automatic Fetching: השבתת משיכת מינויים אוטומטית. יש לרענן את המינויים כדי לצפות בהם כאן.\n  Empty Channels: בערוצים אליהם נרשמת אין כלל סרטונים.\n  All Subscription Tabs Hidden: כל לשוניות המינויים מוסתרות. כדי לראות את התוכן כאן, נא לבטל את הסתרתן של כמה מהלשוניות תחת הסעיף „{subsection}” שב„{settingsSection}”.\n  Subscriptions Tabs: לשוניות מינויים\n  Load More Posts: טעינת רשומות נוספות\n  Empty Posts: בערוצים אליהם נרשמת אין כרגע רשומות.\nTrending:\n  Trending: 'הסרטונים החמים'\n  Trending Tabs: לשוניות מובילים\n  Gaming: משחקים\n  Sports: ספורט\nMost Popular: 'הכי פופולרי'\nPlaylists: 'רשימות נגינה'\nUser Playlists:\n  Your Playlists: 'רשימות הנגינה שלך'\n  Search bar placeholder: חיפוש רשימות נגינה\n  Empty Search Message: אין סרטונים ברשימת הנגינה הזו שעונים לחיפוש שלך\n  You have no playlists. Click on the create new playlist button to create a new one.: אין לך רשימות נגינה. נא ללחוץ על כפתור יצירת רשימת נגינה חדשה כדי ליצור רשימת נגינה חדשה.\n  Edit Playlist Info: עריכת פרטי רשימת נגינה\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: להסיר סרטון משוכפל מרשימת הנגינה הזאת? זאת פעולה בלתי הפיכה. | להסיר {playlistItemCount} סרטונים כפולים מרשימת הנגינה הזאת? זאת פעולה בלתי הפיכה.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: להסיר סרטון שנצפה מרשימת הנגינה הזאת? זאת פעולה בלתי הפיכה. | להסיר {playlistItemCount} סרטונים שנצפו מרשימת הנגינה הזאת? זאת פעולה בלתי הפיכה.\n  Delete Playlist: מחיקת רשימת נגינה\n  Copy Playlist: העתקת רשימת נגינה\n  Remove Watched Videos: הסרת סרטונים שנצפו\n  Remove Duplicate Videos: הסרת סרטונים כפולים\n  Are you sure you want to delete this playlist? This cannot be undone: למחוק את רשימת הנגינה הזו? זאת פעולה בלתי הפיכה.\n  Sort By:\n    EarliestUpdatedFirst: תאריך העדכון (הישן ביותר)\n    NameAscending: א-ת\n    NameDescending: ת-א\n    LatestPlayedFirst: תאריך הנגינה (החדש ביותר)\n    EarliestPlayedFirst: תאריך הנגינה (הישן ביותר)\n    LatestCreatedFirst: תאריך יצירה (החדש ביותר)\n    EarliestCreatedFirst: תאריך יצירה (הישן ביותר)\n    LatestUpdatedFirst: תאריך העדכון (החדש ביותר)\n  SinglePlaylistView:\n    Toast:\n      This playlist is already being used for quick bookmark.: רשימת הנגינה הזאת כבר משמשת למועדפים זריזים.\n      This playlist is now used for quick bookmark: רשימת הנגינה הזאת משמשת כעת לסימניות זריזות\n      This video cannot be moved up.: אי אפשר להעלות את הסרטון הזה למעלה.\n      This video cannot be moved down.: אי אפשר להוריד את הסרטון הזה למטה.\n      Video has been removed: הסרטון הוסר\n      There was a problem with removing this video: אירעה בעיה עם הסרת הסרטון הזה\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: רשימת הנגינה הזאת משמשת לסימניות מהירות במקום {oldPlaylistName}. לחיצה כאן תבטל את זה\n      This playlist does not exist: רשימת השידורים הזו לא קיימת\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: חלק מהסרטונים ברשימת השידורים עדיין לא הועלו. לחץ כאן כדי להעתיק בכל זאת.\n      Playlist name cannot be empty. Please input a name.: שם רשימת השידורים לא יכול להיות ריק. נא להזין שם.\n      \"{videoCount} video(s) have been removed\": 1 סרטון הוסר | {videoCount} סרטונים הוסרו\n      This playlist is protected and cannot be removed.: רשימת השידורים הזו מוגנת ולא ניתן למחוק אותה.\n      Playlist {playlistName} has been deleted.: רשימת השידורים {playlistName} נמחקה.\n      There were no videos to remove.: א היו סרטונים להסרה.\n      Reverted to use {oldPlaylistName} for quick bookmark: חזר להשתמש ב {oldPlaylistName} לסימנייה מהירה\n      Playlist has been updated.: רשימת השידורים עודכנה.\n      There was an issue with updating this playlist.: הייתה בעיה בעדכון רשימת השידורים הזו.\n      This playlist has a video with a duration error: רשימת הנגינה הזאת מכילה סרטון אחד לפחות שאין לו אורך, הם ימוינו כאילו המשך שלהם הוא אפס.\n      Video has been removed. Click here to undo.: הסרטון הוסר. לחיצה תחזיר אותו.\n    Search for Videos: חיפוש סרטונים\n  Cannot delete the quick bookmark target playlist.: לא ניתן למחוק את רשימת הנגינה ביעד הסימניות הזריזות.\n  This playlist currently has no videos.: ברשימת הנגינה אין כרגע סרטונים.\n  Create New Playlist: יצירת רשימת נגינה חדשה\n  Playlist Name: שם רשימת נגינה\n  AddVideoPrompt:\n    Save: שמירה\n    Search in Playlists: חיפוש ברשימות הנגינה\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} סרטונים יתווספו'\n    Allow Adding Duplicate Video(s): לאפשר להוסיף סרטונים כפולים\n    Added {count} Times: כבר נוסף | נוסף {count} פעמים\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} סרטונים כבר נוספו'\n    N playlists selected: '{playlistCount} נבחרו'\n    Select a playlist to add your N videos to: בחר רשימת שידורים להוספת הסרטון שלך | בחר רשימת שידורים להוספת {videoCount} הסרטונים שלך\n    Toast:\n      You haven't selected any playlist yet.: עדיין לא נבחרה רשימת שידורים.\n      \"Video(s) added to {playlistCount} playlists\": \"סרטונים נוספו לרשימת נגינה|סרטונים נוספו ל־{playlistCount} רשימות נגינה\"\n  CreatePlaylistPrompt:\n    Create: יצירה\n    New Playlist Name: שם חדש לרשימת נגינה\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: קיימת רשימת שידורים עם שם זה. נא לבחור שם אחר.\n      Playlist {playlistName} has been successfully created.: רשימת השידורים {playlistName} נוצרה בהצלחה.\n      There was an issue with creating the playlist.: הייתה בעיה ביצירת רשימת השידורים.\n  Playlists with Matching Videos: רשימות נגינה עם סרטונים תואמים\n  Add to Playlist: הוספת לרשימת נגינה\n  Remove from Favorites: הסרה מתוך {playlistName}\n  Move Video Up: העלאת הסרטון מעלה\n  Move Video Down: הורדת הסרטון מטה\n  Remove from Playlist: הסרת מרשימת הנגינה\n  Playlist Description: תיאור רשימת נגינה\n  Save Changes: שמירת השינויים\n  Cancel: ביטול\n  Add to Favorites: הוספה אל {playlistName}\n  Quick Bookmark Enabled: סימנייה מהירה מופעלת\n  Enable Quick Bookmark With This Playlist: אפשר סימנייה מהירה עם רשימת השידורים הזו\n  Export Playlist: ייצוא רשימת הנגינה הזאת\n  The playlist has been successfully exported: רשימת הנגינה יוצאה בהצלחה\n  TotalTimePlaylist: 'זמן כולל: {duration}'\n  Export list of URLs: ייצוא רשימת כתובות\nHistory:\n  # On History Page\n  History: 'היסטוריה'\n  Watch History: 'היסטוריית צפייה'\n  Your history list is currently empty.: 'ההיסטוריה שלך ריקה כרגע.'\n  Search bar placeholder: חיפוש בהיסטוריה\n  Empty Search Message: אין סרטונים בהיסטוריה שלך שעונים לחיפוש שלך\n  Case Sensitive Search: חיפוש תלוי רישיות\n  DateOldestHistory: תאריך הצפייה (הישן ביותר)\n  DateNewestHistory: תאריך הצפייה (החדש ביותר)\nSettings:\n  # On Settings Page\n  Settings: 'הגדרות'\n  General Settings:\n    General Settings: 'כללי'\n    Check for Updates: 'לבדוק אם קיימים עדכונים'\n    Check for Latest Blog Posts: 'לבדוק אם קיימים פוסטים חדשים בבלוג'\n    Fallback to Non-Preferred Backend on Failure: 'נסיגה למנגנון שאינו מועדף בעת כשל'\n    Enable Search Suggestions: 'לאפשר הצעות לחיפוש'\n    Default Landing Page: 'דף נחיתה כברירת מחדל'\n    Locale Preference: 'שפה מועדפת'\n    Preferred API Backend:\n      Preferred API Backend: 'מנגנון API מועדף'\n      Local API: 'API מקומי'\n      Invidious API: 'API של Invidious'\n    Video View Type:\n      Video View Type: 'סוג תצוגת הסרטונים'\n      Grid: 'טבלה'\n      List: 'רשימה'\n    Thumbnail Preference:\n      Thumbnail Preference: 'העדפת תמונות ממוזערות'\n      Default: 'ברירת מחדל'\n      Beginning: 'התחלה'\n      Middle: 'אמצע'\n      End: 'סוף'\n      Hidden: מוסתר\n      Blur: טשטוש\n    Region for Trending: 'אזור לסרטונים חמים'\n        #! List countries\n    View all Invidious instance information: הצגת כל פרטי העותק של Invidious\n    Current Invidious Instance: עותק נוכחי של Invidious\n    System Default: ברירת המחדל של המערכת\n    The currently set default instance is {instance}: עותק ברירת המחדל שהוגדר הוא {instance}\n    Set Current Instance as Default: הגדרת העותק הנוכחי כברירת מחדל\n    External Link Handling:\n      Open Link: פתיחת הקישור\n      Ask Before Opening Link: לשאול לפני פתיחת קישור\n      No Action: שום פעולה\n      External Link Handling: טיפול בקישורים חיצוניים\n    Clear Default Instance: ניקוי עותק ברירת המחדל\n    No default instance has been set: לא הוגדר עותק ברירת מחדל\n    Current instance will be randomized on startup: העותק הנוכחי יעבור ערבוב אקראי עם ההפעלה\n    Auto Load Next Page:\n      Label: טעינת העמוד הבא אוטומטית\n      Tooltip: טען דפים ותגובות נוספים באופן אוטומטי.\n    Open Deep Links In New Window: פתיחת כתובות שהועברו ל־FreeTube בחלון חדש\n    Minimize to system tray: מזעור לשורת המערכת\n  Theme Settings:\n    Theme Settings: 'ערכת עיצוב'\n    Match Top Bar with Main Color: 'התאמת האזור העליון לצבע הראשי'\n    Base Theme:\n      Base Theme: 'ערכת עיצוב בסיסית'\n      Black: 'שחור'\n      Dark: 'חשוך'\n      Light: 'בהיר'\n      Dracula: 'דרקולה'\n      System Default: ברירת המחדל של המערכת\n      Catppuccin Mocha: קטפוצ׳ין מוקה\n      Pastel Pink: ורוד פסטל\n      Hot Pink: ורוד עז\n      Nordic: נורדית\n      Solarized Dark: חשוך זוהר\n      Solarized Light: בהיר זוהר\n      Gruvbox Dark: תיבת גרוב כהה\n      Gruvbox Light: תיבת גרוב בהירה\n      Catppuccin Frappe: קטפוצ׳ין פראפה\n      Everforest Dark Hard: אוורפורסט כהה מאוד\n      Everforest Dark Medium: אוורפורסט כהה בינוני\n      Everforest Light Hard: אברפורסט לייט הארד\n      Everforest Light Medium: אברפורסט לייט מידיום\n      Everforest Dark Low: אברפורסט דארק לואו\n      Everforest Light Low: אברפורסט לייט לואו\n      Catppuccin Latte: קטפוצ׳ין לאטה\n    Main Color Theme:\n      Main Color Theme: 'צבע ראשי'\n      Red: 'אדום'\n      Pink: 'ורוד'\n      Purple: 'סגול'\n      Deep Purple: 'סגול כהה'\n      Indigo: 'כחול כהה'\n      Blue: 'כחול'\n      Light Blue: 'כחול בהיר'\n      Cyan: 'טורקיז'\n      Teal: 'טורקיז כהה'\n      Green: 'ירוק כהה'\n      Light Green: 'ירוק'\n      Lime: 'ירוק בהיר'\n      Yellow: 'צהוב'\n      Amber: 'צהוב כהה'\n      Orange: 'כתום'\n      Deep Orange: 'כתום כהה'\n      Dracula Cyan: 'דרקולה טורקיז'\n      Dracula Green: 'דרקולה ירוק כהה'\n      Dracula Orange: 'דרקולה כתום'\n      Dracula Pink: 'דרקולה ורוד'\n      Dracula Purple: 'דרקולה סגול'\n      Dracula Red: 'דרקולה אדום'\n      Dracula Yellow: 'דרקולה צהוב'\n      Catppuccin Mocha Rosewater: מוקה קפוצ׳ינו מי ורדים\n      Catppuccin Mocha Red: מוקה קפוצ׳ינו אדום\n      Catppuccin Mocha Maroon: מוקה קפוצ׳ינו ערמון\n      Catppuccin Mocha Peach: מוקה קפוצ׳ינו אפרסק\n      Catppuccin Mocha Yellow: מוקה קפוצ׳ינו צהוב\n      Catppuccin Mocha Sky: מוקה קפוצ׳ינו שמיים\n      Catppuccin Mocha Flamingo: מוקה קפוצ׳ינו פלמינגו\n      Catppuccin Mocha Mauve: מוקה קפוצ׳ינו ארגמן\n      Catppuccin Mocha Pink: מוקה קפוצ׳ינו ורוד\n      Catppuccin Mocha Green: מוקה קפוצ׳ינו ירוק\n      Catppuccin Mocha Sapphire: מוקה קפוצ׳ינו ספיר\n      Catppuccin Mocha Lavender: מוקה קפוצ׳ינו לבנדר\n      Catppuccin Mocha Teal: מוקה קפוצ׳ינו ירקרק-כחלחל\n      Catppuccin Mocha Blue: מוקה קפוצ׳ינו כחול\n      Solarized Green: ירוק זוהר\n      Solarized Orange: כתום זוהר\n      Solarized Yellow: צהוב זוהר\n      Solarized Red: אדום זוהר\n      Solarized Magenta: ארגמן זוהר\n      Solarized Blue: כחול זוהר\n      Solarized Violet: ויולט מואר בשמש\n      Solarized Cyan: סולרייזד כחול-ירוק\n      Gruvbox Light Orange: תיבת גרוב כתומה בהירה\n      Gruvbox Dark Green: תיבת גרוב ירוקה כהה\n      Gruvbox Dark Purple: תיבת גרוב סגולה כהה\n      Gruvbox Light Purple: תיבת גרוב סגולה בהירה\n      Gruvbox Dark Blue: תיבת גרוב כחולה כהה\n      Gruvbox Light Red: תיבת גרוב אדומה בהירה\n      Gruvbox Dark Yellow: תיבת גרוב צהובה כהה\n      Gruvbox Dark Orange: תיבת גרוב כתומה כהה\n      Gruvbox Dark Aqua: תיבת גרוב מים כהים\n      Gruvbox Light Blue: תיבת גרוב כחולה בהירה\n      Catppuccin Frappe Green: קטפוצ'ינו פרפה ירוק\n      Catppuccin Frappe Teal: קטפוצ'ינו פרפה טיל\n      Catppuccin Frappe Lavender: קטפוצ'ינו פרפה לבנדר\n      Catppuccin Frappe Yellow: קטפוצ'ינו פרפה צהוב\n      Everforest Dark Red: אברפסט אדום כהה\n      Everforest Dark Yellow: אברפורסט צהוב כהה\n      Everforest Dark Green: אברפורסט ירוק כהה\n      Everforest Dark Aqua: אברפורסט כחול מים כהה\n      Everforest Dark Blue: אברפורסט כחול כהה\n      Catppuccin Frappe Rosewater: קטפוצ'ין פרפה מי ורדים\n      Catppuccin Frappe Flamingo: קטפוצ'ין פרפה פלמינגו\n      Catppuccin Frappe Pink: קטפוצ'ין פרפה פלמינגו\n      Catppuccin Frappe Mauve: קטפוצ׳ין פראפה סגלגל\n      Catppuccin Frappe Red: קטפוצ׳ין פראפה אדום\n      Catppuccin Frappe Maroon: קטפוצ'ינו פרפה חום אדום\n      Catppuccin Frappe Peach: קטפוצ'ין פרפה אפרסק\n      Catppuccin Frappe Sky: קטפוצ'ינו פרפה סקיי\n      Catppuccin Frappe Sapphire: קטפוצ'ינו פרפה ספיר\n      Catppuccin Frappe Blue: קטפוצ'ינו פרפה כחול\n      Everforest Dark Orange: אברפורסט כתום כהה\n      Everforest Dark Purple: אברפורסט סגול כהה\n      Everforest Light Red: אברפורסט אדום בהיר\n      Everforest Light Orange: אברפורסט כתום בהיר\n      Everforest Light Yellow: אברפורסט צהוב בהיר\n      Everforest Light Green: אברפורסט ירוק בהיר\n      Everforest Light Aqua: אברפול לייט אקווה\n      Everforest Light Blue: אברפורסט כחול בהיר\n      Everforest Light Purple: אברפורסט סגול בהיר\n      Catppuccin Latte Mauve: קטפוצ׳ין לאטה סגלגל\n      Catppuccin Latte Red: קטפוצ׳ין לאטה אדום\n    Secondary Color Theme: 'ערכת צבע משנית'\n        #* Main Color Theme\n    UI Scale: יחס גודל הממשק\n    Expand Side Bar by Default: הרחבת סרגל צד כברירת מחדל\n    Disable Smooth Scrolling: השבתת גלילה חלקה\n    Hide Side Bar Labels: הסתרת התוויות בסרגל הצד\n    Hide FreeTube Header Logo: הסתרת הלוגו התחתון של FreeTube\n  Player Settings:\n    Player Settings: 'נגן'\n    Play Next Video: 'הפעלה אוטומטית של סרטונים מומלצים'\n    Turn on Subtitles by Default: 'הפעלת כתוביות כברירת מחדל'\n    Autoplay Videos: 'הפעלת סרטונים אוטומטית'\n    Proxy Videos Through Invidious: 'שימוש במתווך (פרוקסי) לניגון סרטונים דרך Invidious'\n    Autoplay Playlists: 'הפעלה אוטומטית של סרטוני פלייליסט'\n    Enable Theatre Mode by Default: 'הפעלת מצב קולנוע כברירת מחדל'\n    Default Volume: 'ברירת המחדל לעוצמת השמע'\n    Default Playback Rate: 'ברירת המחדל למהירות הצפייה'\n    Default Video Format:\n      Default Video Format: 'תצורת הסרטונים כברירת המחדל'\n      Dash Formats: 'תצורות DASH'\n      Legacy Formats: 'תצורות מיושנות'\n      Audio Formats: 'תצורות שמע'\n    Default Quality:\n      Default Quality: 'איכות ברירת המחדל'\n      Auto: 'אוטומטית'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: מתזמן ספירה לאחור של נגינה אוטומטית\n    Display Play Button In Video Player: הצגת כפתור הניגון בתוך נגן הווידאו\n    Scroll Volume Over Video Player: גלילה על הסרטון לשינוי עוצמת השמע\n    Scroll Playback Rate Over Video Player: גלילת מהירות הנגינה על גבי נגן הווידאו\n    Fast-Forward / Rewind Interval: משך קפיצה / חזרה\n    Max Video Playback Rate: קצב מרבי לנגינת וידאו\n    Video Playback Rate Interval: הפרש קצב נגינת וידאו\n    Screenshot:\n      Enable: הפעלת צילום מסך\n      Format Label: תצורת צילום מסך\n      Ask Path: לשאול באיזו תיקייה לשמור\n      File Name Label: תבנית שם קובץ\n      Error:\n        Forbidden Characters: תווים אסורים\n        Empty File Name: שם קובץ ריק\n      Folder Label: תיקיית צילומי מסך\n      Quality Label: איכות צילום מסך\n      Folder Button: בחירת תיקייה\n      File Name Tooltip: אפשר להשתמש במשתנים להלן. ‎%Y שנה ב־4 ספרות. ‎%M חודש ב־2 ספרות. ‎%D יום ב־2 ספרות. ‎%H שעה ב־2 ספרות. ‎%N דקה ב־2 ספרות. ‎%S שניות ב־2 ספרות. ‎%T מילישניות ב־3 ספרות. ‎%s השנייה בסרטון. ‎%t מילישניות בסרטון ב־3 ספרות. ‎%i מזהה הסרטון.\n    Enter Fullscreen on Display Rotate: מעבר למסך מלא עם סיבוב התצוגה\n    Skip by Scrolling Over Video Player: אפשר לדלג על ידי גלילה על נגן הווידאו\n    Autoplay Interruption Timer: מתזמן הפרעת ניגון אוטומטי\n    Default Viewing Mode:\n      Theater: תיאטרון\n      Default Viewing Mode: מצב צפייה כברירת מחדל\n      Full Screen: מסך מלא\n      Picture in Picture: תמונה בתוך תמונה\n      External Player: נגן חיצוני ({externalPlayerName})\n  Privacy Settings:\n    Privacy Settings: 'פרטיות'\n    Remember History: 'לזכור את היסטוריית הצפייה'\n    Save Watched Progress: 'שמירת משך הצפייה'\n    Clear Search Cache: 'ניקוי מטמון החיפוש'\n    Are you sure you want to clear out your search cache?: 'לנקות את מטמון החיפוש?'\n    Search cache has been cleared: 'מטמון החיפוש נוקה'\n    Remove Watch History: 'מחיקת הסטוריית הצפייה'\n    Are you sure you want to remove your entire watch history?: 'למחוק את היסטורית הצפייה?'\n    Watch history has been cleared: 'הסטוריית הצפייה נמחקה'\n    Remove All Subscriptions / Profiles: 'למחק את כל המינויים / פרופילים'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'למחוק כל את המינויים והפרופילים? זופעולה בלתי הפיכה.'\n    Save Watched Videos With Last Viewed Playlist: לשמור את הסרטונים שנצפו עם רשימת הנגינה לאחרונים שנצפו\n    Remove All Playlists: הסרת כל רשימות הנגינה\n    All playlists have been removed: כל רשימות הנגינה הוסרו\n    Are you sure you want to remove all your playlists?: האם אתה בטוח שברצונך למחוק את כל רשימות השידורים שלך?\n    Clear Search History and Cache: פינוי היסטוריית החיפוש והמטמון\n    Are you sure you want to clear out your search history and cache?: לפנות את היסטוריית החיפוש ואת המטמון שלך?\n    Search history and cache have been cleared: היסטוריית החיפוש והמטמון נמחקו\n    Remember Search History: לזכור את היסטוריית החיפוש\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: אוטומטי\n        Never: לעולם לא\n        Semi-auto: חצי אוטומטי\n      Tooltip: אוטומטי = שמירה בכל יציאה מעמוד הווידאו, כאשר הווידאו מסתיים ונמצאת שגיאה (למשל, הגבלת קצב והפסקת מושב הצפייה). חצי-אוטומטי = כמו אוטומטי, למעט יציאה מעמוד הווידאו וניתן לשמור את ההתקדמות ידנית באמצעות כפתור שנקרא שמור התקדמות נצפתה, הממוקם מתחת לנגן הווידאו.\n  Subscription Settings:\n    Subscription Settings: 'מינוי'\n    Fetch Feeds from RSS: 'ייבוא עדכונים בעזרת RSS'\n    Fetch Automatically: משיכת ערוץ העדכונים אוטומטית\n    Confirm Before Unsubscribing: אישור לפני ביטול מינוי\n    'Limit the number of videos displayed for each channel': הגבלת מספר הסרטונים שמופיעים בכל ערוץ\n    To: עד\n  Data Settings:\n    Data Settings: 'נתונים'\n    Select Export Type: 'נא לבחור את תסדיר הייצוא'\n    Import Subscriptions: 'ייבוא מינויים'\n    Export Subscriptions: 'ייצוא מינויים'\n    Export FreeTube: 'ייצוא בתסדיר של FreeTube'\n    Export YouTube: 'ייצוא בתסדיר של YouTube'\n    Export NewPipe: 'ייצוא בתסדיר של NewPipe'\n    Import History: 'ייבוא היסטוריה'\n    Export History: 'ייצוא היסטוריה'\n    Profile object has insufficient data, skipping item: 'לאובייקט הפרופיל אין מספיק נתונים, מדלג על פריט זה'\n    All subscriptions and profiles have been successfully imported: 'כל המינויים והפרופילים יובאו בהצלחה'\n    All subscriptions have been successfully imported: 'כל המינויים יובאו בהצלחה'\n    Invalid subscriptions file: 'קובץ מינויים בלתי קריא'\n    Invalid history file: 'קובץ היסטוריה בלתי קריא'\n    Subscriptions have been successfully exported: 'המינויים יוצאו בהצלחה'\n    History object has insufficient data, skipping item: 'לאובייקט ההיסטוריה אין מספיק מידע, נדלג על פריט זה'\n    All watched history has been successfully imported: 'כל היסטוריית הצפייה יובאה בהצלחה'\n    All watched history has been successfully exported: 'כל היסטוריית הצפייה יוצאה בהצלחה'\n    Unable to read file: 'לא ניתן לקרוא את הקובץ'\n    Unable to write file: 'לא ניתן ליצור את הקובץ'\n    Unknown data key: 'מפתח נתון לא ידוע'\n    How do I import my subscriptions?: 'איך לייבא את המינויים שלי?'\n    Manage Subscriptions: ניהול מינויים\n    All playlists has been successfully exported: כל רשימות הנגינה יוצאו בהצלחה\n    All playlists has been successfully imported: כל רשימות הנגינה יובאו בהצלחה\n    Export Playlists: ייצוא רשימות נגינה\n    Import Playlists: ייבוא רשימות נגינה\n    Playlist insufficient data: 'אין מספיק נתונים לרשימת הנגינה „{playlist}”, הפריט ידולג'\n    Playlist File: קובץ רשימות נגינה\n    Subscription File: קובץ מינויים\n    History File: קובץ היסטוריה\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"אפשרות זו מייצאת סרטונים מכל הרשימות לרשימת שידורים אחת בשם 'מועדפים'.\\n איך לייצא ולייבא סרטונים ברשימות לגרסה ישנה של FreeTube:\\n1. יצא את הרשימות שלך עם אפשרות זו מופעלת.\\n2. מחק את כל הרשימות הקיימות שלך באמצעות אפשרות הסרת כל הרשימות בהגדרות הפרטיות.\\n3. הפעל את הגרסה הישנה של FreeTube וייבא את הרשימות שיוצאו.\"\n      Label: ייצוא רשימות לגרסאות ישנות של FreeTube\n\n    Search history file: קובץ היסטוריית חיפוש\n    Search history: היסטוריית חיפוש\n    Import search history: ייבוא היסטוריית חיפוש\n    Export search history: ייצוא היסטוריית חיפוש\n    All search history has been successfully imported: כל היסטוריית החיפוש ייובאה בהצלחה\n    All search history has been successfully exported: כל היסטוריית החיפוש ייוצאה בהצלחה\n  Distraction Free Settings:\n    Hide Live Chat: הסתרת צ׳אט חי\n    Hide Popular Videos: הסתרת סרטונים נפוצים\n    Hide Trending Videos: הסתרת הסרטונים החמים\n    Hide Recommended Videos: הסתרת הסרטונים המומלצים\n    Hide Comment Likes: הסתרת לייקים על תגובות\n    Hide Channel Subscribers: הסתרת מנויי הערוץ\n    Hide Video Likes And Dislikes: הסתרת לייקים ודיסלייקים לסרטון\n    Distraction Free Settings: השבתת הסחות\n    Hide Video Views: הסתרת תצוגות סרטונים\n    Hide Active Subscriptions: הסתרת מינויים פעילים\n    Hide Playlists: הסתרת רשימות נגינה\n    Hide Live Streams: הסתרת תזרימים חיים\n    Hide Sharing Actions: הסתרת פעולות שיתוף\n    Hide Videos on Watch: 'הסתרת סרטונים לאחר הצפייה'\n    Hide Comments: הסתרת הערות\n    Hide Video Description: הסתרת תיאור וידאו\n    Hide Chapters: הסתרת פרקים\n    Hide Upcoming Premieres: הסתרת בכורות קרובות\n    Hide Channels: הסתרת סרטונים מהערוצים\n    Hide Channels Placeholder: ID של הערוץ\n    Display Titles Without Excessive Capitalisation: הצג כותרות ללא אותיות גדולות וסימני פיסוק מיותרים\n    Hide Featured Channels: הסתרת ערוצים מומלצים\n    Hide Channel Playlists: הסתרת לשונית „רשימות נגינה” של ערוץ\n    Hide Channel Shorts: הסתרת לשונית ה־„Shorts” של הערוץ\n    Sections:\n      Watch Page: עמוד הצפייה\n      Channel Page: עמוד ערוץ\n      Side Bar: סרגל צד\n      General: כללי\n      Subscriptions Page: עמוד מינויים\n    Hide Channel Podcasts: הסתרת לשונית ה„הסכתים” של הערוץ\n    Hide Channel Releases: הסתרת לשונית ה„שחרורים” של הערוץ\n    Hide Subscriptions Live: הסתרת שידורים חיים של המינויים\n    Hide Subscriptions Shorts: הסתרת Shorts של המינויים\n    Hide Subscriptions Videos: הסתרת סרטוני מינוי\n    Hide Profile Pictures in Comments: הסתרת תמונות הפרופיל בהערות\n    Hide Videos, Playlists and Channels Containing Text Placeholder: מילה, חלק מילה או ביטוי\n    Hide Channels Invalid: ID הערוץ שסופק לא תקין\n    Hide Channels Disabled Message: חלק מהערוצים נחסמו באמצעות ID ולא טופלו. התכונה נחסמת עד שה-ID האלו מתעדכנים\n    Hide Channels Already Exists: ID הערוץ כבר קיים\n    Hide Channels API Error: אירעה שגיאה באיחזור משתמש עם ה-ID שסופק. נא לבדוק שוב אם ה-ID נכון.\n    Hide Videos, Playlists and Channels Containing Text: הסתרת סרטונים ורשימות שידורים המכילים טקסט\n    Hide Channel Home: הסתרת לשונית ה„בית” של הערוץ\n    Show Added Items: הצגת פריטים שנוספו\n    Hide Channel Posts: הסתר את לשונית \"פוסטים\" של הערוץ\n    Hide Subscriptions Posts: הסתר פוסטים של מנויים\n    Hide Channel Courses: הסתר את לשונית \"קורסים\" של הערוץ\n  The app needs to restart for changes to take effect. Restart and apply change?: צריך להפעיל את היישומון מחדש כדי שהשינויים ייכנסו לתוקף. להפעיל מחדש ולהחיל את השינוי?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: קבלת פרטי הרשת נכשלה. המתווך שלך מוגדר כראוי?\n    City: עיר\n    Region: אזור\n    Country: מדינה\n    Ip: IP\n    Your Info: הפרטים שלך\n    Test Proxy: בדיקת המתווך\n    Clicking on Test Proxy will send a request to: לחיצה על בדיקת המתווך תשלח בקשה אל\n    Proxy Port Number: מספר פתחת מתווך\n    Proxy Host: מארח מתווך\n    Proxy Protocol: פרוטוקול מתווך\n    Enable Tor / Proxy: הפעלת Tor / מתווך\n    Proxy Settings: מתווך (פרוקסי)\n    Proxy Warning: ל־FreeTube אין מתווך מובנה אבל הוא יכול להתחבר למתווך חיצוני, כמו למשל כזה שרץ על המחשב שלך כמו Tor או מתווך חיצוני כגון מתווך SOCKS5 שמסופק על ידי איזשהו ספק VPN. אם האפשרות פעילה, נא לוודא שהמתווך/Tor שלך מוגדרים כראוי, או ש־FreeTube לא יוכל למשוך נתונים כלל.\n    Proxy Password: סיסמת מתווך\n    Proxy Username: שם משתמש במתווך\n  External Player Settings:\n    External Player: נגן חיצוני\n    External Player Settings: נגן חיצוני\n    Custom External Player Executable: קובץ בר־הרצה מותאם אישית לַנַּגָּן\n    Ignore Unsupported Action Warnings: התעלמות מאזהרות על פעולות שאינן נתמכות\n    Custom External Player Arguments: משתנים לנגן חיצוני בהתאמה אישית\n    Players:\n      None:\n        Name: ללא\n    Ignore Default Arguments: התעלם מפרמטרים ברירת מחדל\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: להודיע לגבי דילוג על קטע החסוּת\n    SponsorBlock Settings: חוסם מממנים\n    Enable SponsorBlock: הפעלת חוסם מממנים\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': כתובת ה־API של חוסם המממנים (ברירת המחדל היא https://sponsor.ajay.app)\n    Skip Options:\n      Skip Option: אפשרות דילוג\n      Auto Skip: דילוג אוטומטי\n      Show In Seek Bar: הצגה בסרגל האיתור\n      Do Nothing: לא לעשות כלום\n      Prompt To Skip: לשאול אם לדלג\n    Category Color: צבע קטגוריה\n    UseDeArrowTitles: להשתמש בכותרות סרטונים דרך DeArrow\n    UseDeArrowThumbnails: השתמש ב-DeArrow לתמונות מיניאטורה\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': כתובת API של DeArrow Thumbnail Generator (ברירת מחדל היא https://dearrow-thumb.ajay.app)\n  Parental Control Settings:\n    Parental Control Settings: בקרת הורים\n    Hide Search Bar: הסתרת סרגל החיפוש\n    Hide Unsubscribe Button: הסתרת כפתור ביטול מינוי\n    Show Family Friendly Only: הצגת דברים ידידותיים למשפחה בלבד\n    Hide Uploader on Watch page: הסתרת הגורם המעלה בעמוד המעקב\n  Experimental Settings:\n    Experimental Settings: ניסיוני\n    Replace HTTP Cache: החלפת מטמון HTTP\n    Warning: הגדרות אלו הן ניסיוניות, הן גורמות לקריסות כשהן מופעלות. מומלץ מאוד לבצע גיבויים. השימוש על אחריותך בלבד!\n  Password Dialog:\n    Password: סיסמה\n    Enter Password To Unlock: נא למלא סיסמה כדי לשחרר את ההגדרות\n  Password Settings:\n    Password Settings: סיסמה\n    Set Password: הגדרת סיסמה\n    Remove Password: הסרת סיסמה\n    Set Password To Prevent Access: יש להגדיר סיסמה כדי למנוע גישה להגדרות\n  Sort Settings Sections (A-Z): מיון אזורי הגדרות (א-ת)\n  Return to Settings Menu: חזרה לתפריט ההגדרות\nAbout:\n  #On About page\n  About: 'על אודות'\n  #& About\n  Website: אתר\n  Blog: בלוג\n  Credits: תודות\n  FAQ: שו״ת\n  Email: דוא״ל\n  Beta: בטא\n  Donate: תרומה\n  Help: עזרה\n  these people and projects: האנשים והמיזמים האלו\n  Translate: תרגום\n  room rules: כללי החדר\n  Chat on Matrix: צ׳אט ב־Matrix\n  Mastodon: ‎Mastodon\n  Please check for duplicates before posting: נא לבדוק כפילויות בטרם פרסום תקלה\n  GitHub issues: תקלות ב־GitHub\n  Report a problem: דיווח על תקלה\n  FreeTube Wiki: הוויקי של FreeTube\n  GitHub releases: מהדורות ב־GitHub\n  Downloads / Changelog: הורדות / יומן שינויים\n  Source code: קוד מקור\n  Discussions: דיונים\n  AGPLv3: AGPLv3\nProfile:\n  Profile Select: 'בחירת פרופיל'\n  All Channels: 'כל הערוצים'\n  Profile Manager: 'מנהל הפרופילים'\n  Create New Profile: 'יצירת פרופיל חדש'\n  Edit Profile: 'עריכת פרופיל'\n  Color Picker: 'בורר הצבעים'\n  Custom Color: 'צבע אחר'\n  Profile Preview: '‮לוגו הפרופיל'\n  Create Profile: 'יצירת פרופיל'\n  Update Profile: 'עדכון פרופיל'\n  Make Default Profile: 'להפוך לפרופיל ברירת המחדל'\n  Delete Profile: 'מחיקת פרופיל'\n  Are you sure you want to delete this profile?: 'רוצים למחוק את הפרופיל?'\n  All subscriptions will also be deleted.: 'גם כל המינויים יימחקו.'\n  Your profile name cannot be empty: 'לא ניתן לרוקן את הפרופיל שלך'\n  Profile has been created: 'הפרופיל נוצר'\n  Profile has been updated: 'הפרופיל עודכן'\n  Your default profile has been set to {profile}: 'פרופיל ברירת המחדל שלך הוגדר לפרופיל {profile}'\n  Removed {profile} from your profiles: '{profile} נמחק מהפרופילים שלך'\n  Your default profile has been changed to your primary profile: 'פרופיל ברירת המחדל שלך השתנה לפרופיל הראשי שלך'\n  '{profile} is now the active profile': '{profile} הוא הפרופיל הפעיל מעתה'\n  Subscription List: 'רשימת מינויים'\n  Other Channels: 'ערוצים אחרים'\n  '{number} selected': '{number} נבחר'\n  Select All: 'לבחור הכול'\n  Select None: 'לבטל בחירה'\n  Delete Selected: 'למחוק את הנבחרים'\n  Add Selected To Profile: 'הוספת הנבחרים לפרופיל'\n  No channel(s) have been selected: 'לא נבחרו ערוצים'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'זה הפרופיל הראשי שלך. למחוק את הערוצים שבחרת?  הערוצים האלו ימחקו מכל הפרופילים בהם הם נמצאים.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'למחוק את הערוצים שבחרת? הערוצים לא יימחקו משאר הפרופילים.'\n#On Channel Page\n  Profile Filter: מסנן פרופילים\n  Profile Settings: הפרופיל\n  Toggle Profile List: החלפת תצוגת רשימת פרופילים\n  Edit Profile Name: ערוך שם הפרופיל\n  Close Profile Dropdown: סגור תפריט הפרופיל\n  Create Profile Name: צור שם פרופיל\n  Profile Name: שם הפרופיל\n  Open Profile Dropdown: פתח תפריט הפרופיל\nChannel:\n  Subscribe: 'הרשמה למינוי'\n  Unsubscribe: 'ביטול המינוי'\n  Channel has been removed from your subscriptions: 'הערוץ נמחק מרשימת המינויים שלך'\n  Removed subscription from {count} other channel(s): 'הוסר מינוי מ־{count} ערוצים נוספים'\n  Added channel to your subscriptions: 'הערוץ נוסף לרשימת המנויים שלך'\n  Search Channel: 'חיפוש בערוץ'\n  Your search results have returned 0 results: 'לא נמצאו תוצאות'\n  Videos:\n    Videos: 'סרטונים'\n    This channel does not currently have any videos: 'לערוץ זה אין סרטונים כרגע'\n    Sort Types:\n      Newest: 'הכי חדשים'\n      Oldest: 'הכי ישנים'\n      Most Popular: 'הכי פופולריים'\n  Playlists:\n    Playlists: 'רשימות נגינה'\n    This channel does not currently have any playlists: 'לערוץ זה אין רשימות נגינה כרגע'\n    Sort Types:\n      Last Video Added: 'הסרטון האחרון שנוסף'\n      Newest: 'הכי חדשות'\n      Oldest: 'הכי ישנות'\n  About:\n    About: 'על אודות'\n    Channel Description: 'תיאור הערוץ'\n    Featured Channels: 'ערוצים מומלצים'\n    Tags:\n      Tags: תגיות\n      Search for: חיפוש אחר „{tag}”\n    Details: פרטים\n    Joined: הצטרפות\n    Location: מקום\n  This channel does not allow searching: הערוץ הזה לא מאפשר חיפוש\n  Channel Tabs: לשוניות ערוצים\n  This channel does not exist: הערוץ הזה לא קיים\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: הערוץ מוגבל לפי גיל וכרגע אי אפשר לצפות בו ב־FreeTube.\n  Posts:\n    This channel currently does not have any posts: אין רשומות בערוץ הזה כרגע\n    votes: '{votes} הצבעות'\n    Reveal Answers: חשיפת התשובות\n    Hide Answers: הסתרת התשובות\n    View Full Post: צפה בפוסט המלא\n    Viewing Posts Only Supported By Invidious: צפייה בפוסטים מתאפשרת רק באמצעות Invidious. עבור ללשונית הקהילה של הערוץ כדי לצפות בתוכן שם ללא Invidious.\n    Video hidden by FreeTube: סרטון מוסתר על ידי FreeTube\n  Live:\n    Live: חי\n    This channel does not currently have any live streams: לערוץ הזה אין שידורים חיים כרגע\n  Shorts:\n    This channel does not currently have any shorts: אין כרגע Shorts בערוץ הזה\n  Podcasts:\n    Podcasts: הסכתים\n    This channel does not currently have any podcasts: בערוץ הזה אין הסכתים כרגע\n  Releases:\n    Releases: שחרורים\n    This channel does not currently have any releases: בערוץ הזה אין שחרורים כרגע\n  Home:\n    Home: בית\n    View Playlist: הצגת רשימת נגינה\n  Courses:\n    Courses: קורסים\n    This channel does not currently have any courses: ערוץ זה אינו כולל כרגע קורסים\nVideo:\n  Mark As Watched: 'סימון כנצפה'\n  Remove From History: 'הסרה מהיסטוריית הצפייה'\n  Video has been marked as watched: 'הסרטון סומן כנצפה'\n  Video has been removed from your history: 'הסרטון נמחק מהיסטוריית הצפייה שלך'\n  Open in YouTube: 'פתיחה ב־YouTube'\n  Copy YouTube Link: 'העתקת קישור ל־YouTube'\n  Open YouTube Embedded Player: 'פתיחה בנגן המוטמע של YouTube'\n  Copy YouTube Embedded Player Link: 'העתקת קישור לנגן המוטמע של YouTube'\n  Open in Invidious: 'פתיחה ב־Invidious'\n  Copy Invidious Link: 'העתקת קישור ל־Invidious'\n  Views: 'צפיות'\n  Loop Playlist: 'ניגון רשימת נגינה במחזוריות'\n  Shuffle Playlist: 'ערבוב רשימת הנגינה'\n  Reverse Playlist: 'נגינת רשימת הנגינה בסדר הפוך'\n  Previous: 'הקודם'\n  Next: 'הבא'\n  # Context is \"X People Watching\"\n  Watched: 'נצפה'\n  Autoplay: 'ניגון אוטומטי'\n  Starting soon, please refresh the page to check again: 'מתחילים בקרוב, נא לרענן את העמוד בשביל לבדוק שוב'\n  # As in a Live Video\n  Live: 'שידור חי'\n  Live Now: 'בשידור חי'\n  Live Chat: 'צ׳אט'\n  Enable Live Chat: 'הפעלת צ׳אט'\n  Live Chat is currently not supported in this build.: 'הצ׳אט כרגע לא נתמך בגרסה זו.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'הצ׳אט מופעל. ההודעות תופענה פה כאשר תישלחנה.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'מנגנון הצ׳אט כרגע לא נתמך ע״י ה־API של Invidious. דרוש חיבור ישיר ל־YouTube.'\n  Published:\n    In less than a minute: עוד פחות מדקה\n  Published on: 'פורסם'\n#& Videos\n  Copy Invidious Channel Link: העתקת קישור ערוץ ה־Invidious\n  Open Channel in Invidious: פתיחת הערוץ ב־Invidious\n  Copy YouTube Channel Link: העתקת קישור ערוץ ה־YouTube\n  Open Channel in YouTube: פתיחת הערוץ ב־YouTube\n  Started streaming on: ההזרמה החלה ב־\n  Streamed on: הוזרם ב־\n  Video has been removed from your saved list: הסרטון הוסר מרשימת השמורים שלך\n  Video has been saved: סרטון נשמר\n  Save Video: שמירת סרטון\n  Sponsor Block category:\n    outro: סיום\n    self-promotion: קידום עצמי\n    interaction: אינטראקציה\n    sponsor: נותן חסות\n    intro: פתיח\n    music offtopic: מוזיקה - לא בהקשר\n    filler: ממלא מקום\n    recap: סיכום\n  External Player:\n    video: סרטון\n    playlist: רשימת נגינה\n    OpenInTemplate: פתיחה בתוך {externalPlayer}\n    OpeningTemplate: '{videoOrPlaylist} נפתח ב־{externalPlayer}…'\n    UnsupportedActionTemplate: 'ב־{externalPlayer} אין תמיכה בפעולה: {action}'\n    Unsupported Actions:\n      opening playlists: פתיחת רשימות נגינה\n      setting a playback rate: הגדרת מהירות נגינה\n      starting video at offset: התחלת סרטון בהיסט\n      reversing playlists: היפוך סדר רשימות נגינה\n      shuffling playlists: ערבוב רשימות נגינה\n      looping playlists: לולאה על רשימות נגינה\n      opening specific video in a playlist (falling back to opening the video): פתיחת סרטון מסוים ברשימת נגינה (ייסוג לפתיחת הסרטון)\n  Premieres: בכורות\n  Scroll to Bottom: גלילה לתחתית\n  Show Super Chat Comment: הצגת הערת סופר צ׳אט\n  Upcoming: בקרוב\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': הצ׳אט לא זמין לשידור הזה. יכול להיות שהוא הושבת על ידי המעלה.\n  Player:\n    Theatre Mode: מצב תיאטרון\n    TranslatedCaptionTemplate: '{language} (תורגם מ\"{originalLanguage}\")'\n    Audio Tracks: מסלולי שמע\n    Exit Theatre Mode: צא ממצב תיאטרון\n    Full Window: מסך מלא\n    Exit Full Window: צא ממסך מלא\n    Take Screenshot: לעשות צילום מסך\n    Show Stats: הצג נתונים\n    Stats:\n      Video ID: 'ID סרטון: {videoId}'\n      Resolution: 'רזולוציה: {height}‎‏x‏{width}{''@''}{frameRate}'\n      Stats: נתונים\n      Media Formats: 'פורמטים מדיה: {formats}'\n      Player Dimensions: 'ממדי הנגן: {height}x‏{width}'\n      Bitrate: 'קצב סיביות: {bitrate} קסל״ש'\n      Buffered: 'מטופל: %{bufferedPercentage}‏‏‎‏‏‏‏‏'\n      Volume: 'עוצמת קול: %{volumePercentage}'\n      Bandwidth: 'רוחב פס: kbps ‏‏‏‏‎‎‎{bandwidth}‏‎'\n      Dropped Frames / Total Frames: 'פריימים שנפלו: {droppedFrames} / פריימים כולל: {totalFrames}'\n      CodecAudio: 'קודק: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'קודקים: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'קודקים: {videoCodec} / {audioCodec}'\n    Hide Stats: הסתר נתונים\n    You appear to be offline: נראה שהחיבור שלך נקטע.\n    Playback will resume automatically when your connection comes back: הפלייבק יחודש אוטומטית כאשר החיבור שלך יחזור.\n    Skipped segment: דילגתי על {segmentCategory}\n    Autoplay is off: הפעלה אוטומטית כבויה\n    Autoplay is on: הניגון האוטומטי פעיל\n  Hide Channel: הסתר ערוץ\n  Unhide Channel: הצג ערוץ\n  More Options: אפשרויות נוספות\n  IP block: YouTube חסמו את כתובת ה־IP לצפייה בסרטונים. נא לנסות לעבור ל־VPN או למתווך אחרים.\n  MembersOnly: אי אפשר לצפות בסרטונים לחברים בלבד עם FreeTube כיוון שהם דורשים כניסה ל־Google וחברות בתשלום לערוץ של מי שהעלה.\n  AgeRestricted: אי אפשר לצפות בסרטונים שמוגבלים בגיל עם FreeTube כיוון שהם דורשים כניסה עם Google ושימוש בחשבון YouTube עם גיל מאומת.\n  Unlisted: לא מופיע\n  DeArrow:\n    Show Modified Details: הצגת פרטים לאחר שינוי\n    Show Original Details: הצגת פרטים מקוריים\n#& Playlists\n  Save Watched Progress: שמור התקדמות נצפית\n  DRMProtected: סרטונים המוגנים ב-DRM אינם יכולים להתנגן ב-FreeTube, מכיוון שהם דורשים רכיבים סגורים ובעלים. אם אתה רוצה לצפות בסרטון הזה, אנא צפה בו באתר הרשמי של YouTube בדפדפן אינטרנט עם תמיכה ב-DRM.\n  Watched Progress Saved: התקדמות שנשמרה נצפתה\n  Popout Live Chat: צ׳אט קופץ\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'זמן שנותר לפרסומת מקדימה: {remindingTimeSeconds} שנ׳'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'זמן שנותר לטיפול בתשדיר (SABR): {remindingTimeSeconds} שנ׳'\nPlaylist:\n  #& About\n  View Full Playlist: 'צפייה ברשימת הנגינה המלאה'\n  Last Updated On: 'עודכן לאחרונה ב־'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: רשימת נגינה\n  Sort By:\n    AuthorDescending: יוצר (ת-א)\n    DateAddedOldest: תאריך ההוספה (הישן ביותר)\n    AuthorAscending: יוצר (א-ת)\n    VideoTitleAscending: כותר (א-ת)\n    Custom: מותאם\n    VideoTitleDescending: כותר (ת-א)\n    DateAddedNewest: תאריך ההוספה (החדש ביותר)\n    VideoDurationAscending: משך (הקצרים ביותר)\n    VideoDurationDescending: משך (הארוכים ביותר)\n    PublishedNewest: תאריך הפרסום (החדש ביותר)\n    PublishedOldest: תאריך הפרסום (הישן ביותר)\nChange Format:\n  Change Media Formats: 'שינוי תסדירי המדיה'\n  Use Dash Formats: 'שימוש בתסדירי DASH'\n  Use Legacy Formats: 'שימוש בתסדירים המיושנים'\n  Use Audio Formats: 'שימוש בתסדירי שמע'\n  Dash formats are not available for this video: 'לא קיימים תסדירי DASH לסרטון הזה'\n  Audio formats are not available for this video: 'לא קיימים תסדירי שמע לסרטון הזה'\n  Legacy formats are not available for this video: פורמטים ישנים אינם זמינים לסרטון זה\nShare:\n  Share Video: 'שיתוף הסרטון'\n  Share Playlist: 'שיתוף רשימת נגינה'\n  Include Timestamp: 'לשמור נקודת זמן'\n  Copy Link: 'העתקת קישור'\n  Open Link: 'פתיחת קישור'\n  Copy Embed: 'העתקת הטמעה'\n  Open Embed: 'פתיחת הטמעה'\n  # On Click\n  Invidious URL copied to clipboard: 'קישור ל־Invidious הועתק'\n  Invidious Embed URL copied to clipboard: 'קישור הטמעה של Invidious הועתק'\n  YouTube URL copied to clipboard: 'קישור ל־YouTube הועתק'\n  YouTube Embed URL copied to clipboard: 'קישור הטמעה של YouTube הועתק'\n  YouTube Channel URL copied to clipboard: כתובת ערוץ ה־YouTube הועתקה ללוח הגזירים\n  Invidious Channel URL copied to clipboard: כתובת ערוץ ה־Invidious הועתק ללוח הגזירים\n  Share Channel: שיתוף ערוץ\n  Share Post: שיתוף רשומה\nMini Player: 'נגן מזערי'\nComments:\n  Comments: 'תגובות'\n  Click to View Comments: 'לחיצה לצפייה בתגובות'\n  Getting comment replies, please wait: 'תשובות לתגובה נטענות, נא להמתין'\n  There are no more comments for this video: 'לסרטון הזה אין תגובות'\n  Hide Comments: 'הסתרת תגובות'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'לסרטון זה אין תגובות'\n  Load More Comments: 'טעינת תגובות נוספות'\n  Newest first: החדשות ביותר תחילה\n  Top comments: תגובות מובילות\n  Show More Replies: הצגת תגובות נוספות\n  Pinned by: ננעץ על ידי\n  Member: חבר\n  View {replyCount} replies: הצגת תגובה|הצגת {replyCount} תגובות\n  Hearted: סומן בלב\n  Subscribed: נרשמת\n  There are no comments available for this post: אין תגובות זמינות לפוסט זה\n  Hide {replyCount} replies: הסתרת תגובה|הסתרת {replyCount} תגובות\n  View 1 reply from {channelName}: הצגת תגובה מאת {channelName}\n  View {replyCount} replies from {channelName} and others: הצגת {replyCount} תגובות מאת {channelName} ואחרים\nUp Next: 'הסרטון הבא'\n\n# Toast Messages\nLocal API Error (Click to copy): 'בעיה ב־API המקומי (יש ללחוץ להעתקה)'\nInvidious API Error (Click to copy): 'בעיה ב־API של Invidious (יש ללחוץ להעתקה)'\nFalling back to Invidious API: 'מתבצעת נסיגה ל־API של Invidious'\nFalling back to Local API: 'מתבצעת נסיגה ל־API המקומי'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'חסרות תצורות לסרטון הזה. הדבר יכול להיגרם בגלל חוסר זמינות למדינה.'\nLoop is now disabled: 'ניגון בלולאה מושבת'\nLoop is now enabled: 'ניגון בלולאה הופעל'\nShuffle is now disabled: 'ערבוב מושבת'\nShuffle is now enabled: 'ערבוב מופעל'\nThe playlist has been reversed: 'רשימת נגינה זו התהפכה'\nPlaying Next Video: 'הסרטון הבא מתנגן'\nPlaying Previous Video: 'הסרטון הקודם מתנגן'\nCanceled next video autoplay: 'ניגון הסרטון הבא אוטומטית בוטל'\n'The playlist has ended. Enable loop to continue playing': 'רשימת הנגינה הסתיימה.  יש להפעיל לולאה כדי להמשיך לנגן'\n\nYes: 'כן'\nNo: 'לא'\nTooltips:\n  General Settings:\n    Fallback to Non-Preferred Backend on Failure: כאשר ל־API המועדף עליך יש בעיה, FreeTube ינסה להשתמש ב־API בעדיפות הנמוכה יותר באופן אוטומטי כשיטת נסיגה כאשר האפשרות פעילה.\n    Preferred API Backend: נא לבחור את המנגנון לשימוש FreeTube כדי לקבל נתונים. ה־API המקומי הוא מחלץ מובנה. ה־API של Invidious דורש התחברות לשרת Invidious.\n    Invidious Instance: העותק של Invidious שאליו FreeTube יתחבר לקבלת פניות API.\n    Thumbnail Preference: כל התמונות הממוזערות ברחבי FreeTube יוחלפו בתמונית מתוך הסרטון, בצורה מטושטשת או מוסתרת במקום התמונה הממוזערת כברירת המחדל.\n    External Link Handling: \"נא לבחור את התנהגות ברירת המחדל כשנלחץ קישור שלא ניתן לפתוח ב־FreeTube.\\nכברירת מחדל FreeTube יפתח את הקישור שנלחץ בדפדפן ברירת המחדל שלך.\\n\"\n    Region for Trending: מגמות אזוריות מאפשרות לך לבחור סרטונים חמים של איזו מדינה שמעניין אותך לראות.\n    Open Deep Links In New Window: כתובות שמועברות ל־FreeTube, כגון העברת הרחבות דפדפן או ארגומנטים בשורת הפקודה, תיפתחנה בחלון חדש.\n  Player Settings:\n    Proxy Videos Through Invidious: יתבצע חיבור ל־Invidious כדי להגיש סרטונים במקום להתחבר ישירות ל־YouTube.\n    Default Video Format: קביעת התסדירים בעת ניגון סרטונים. תסדירי DASH יכולים להתנגן באיכויות גבוהות יותר. התסדירים המיושנים מוגבלים ל־360 פיקסלים לכל היותר אך משתמשים בפחות רוחב פס. תסדירי שמע הם הזרמות של שמע בלבד.\n    Scroll Playback Rate Over Video Player: כאשר הסמן מעל הסרטון, יש ללחוץ ולהחזיק את מקש ה־Control (או Command ב־Mac) ולגלול עם גלגלת העכבר קדימה או אחורה כדי לשלוט בקצב הנגינה. לחיצה והחזקה של מקש Control (או Command ב־Mac) ולחיצה על הכפתור השמאלי בעכבר מחזירה במהירות לקצב הנגינה כברירת מחדל (1x אלמלא בוצע שינוי בהגדרות).\n    Skip by Scrolling Over Video Player: ניתן להשתמש בגלגלת כדי לדלג בתוך הסרטון, כמו ב־MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: כאשר זה מופעל, FreeTube ישתמש ב-RSS במקום בשיטה המוגדרת כברירת מחדל כדי לתפוס את זרם המנויים שלך. RSS מהיר יותר ומונע חסימת IP, אך אינו מספק מידע מסוים כמו משך הווידאו, מצב חי או פוסטים\n    Fetch Automatically: כאשר האפשרות מופעלת, FreeTube ימשוך אוטומטית את רשימת המנויים שלך בעת הפעלת התוכנה ובפתיחת חלון חדש.\n  External Player Settings:\n    DefaultCustomArgumentsTemplate: '(ברירת מחדל: ‚{defaultCustomArguments}’)'\n    Ignore Warnings: 'להשבית אזהרות כאשר הנגן החיצוני הנוכחי לא תומך בפעולה הנוכחית (למשל: היפוך רשימת נגינה וכו׳).'\n    External Player: בחירה בנגן חיצוני תציג סמל, לפתיחת הווידאו (רשימת הנגינה אם יש תמיכה) בנגן חיצוני, על גבי התמונה הממוזערת. אזהרה, הגדרות Invidious לא משפיעות על נגנים חיצוניים.\n    Custom External Player Executable: כברירת מחדל FreeTube יניח שהנגן החיצוני הנבחר נגיש דרך משתנה הסביבה PATH. במקרה הצורך, ניתן להגדיר כאן נתיב משלך.\n    Custom External Player Arguments: ארגומנטים כלשהם משלך לשורת הפקודה להעברה הלאה לנגן החיצוני.\n    Ignore Default Arguments: אל תשלח אף ארגומנט סטנדרטי לנגן החיצוני, מלבד כתובת הסרטון (למשל, קצב הפלייבק, כתובת הרשימה, וכו'). ארגומנטים מותאמים ימשיכו להיות מועברים.\n  Experimental Settings:\n    Replace HTTP Cache: משבית את מטמון ה־HTTP מבוסס הכונן ומפעיל מטמון תמונות מותאם אישית בזיכרון. יגדיל את צריכת הזיכרון (RAM).\n  Distraction Free Settings:\n    Hide Channels: יש למלא את שם או מזהה הערוץ כדי להסתיר את כל הסרטונים, רשימות הנגינה ואת הערוץ עצמו כך שלא יופיע בחיפוש, במובילים, בנפוצים ביותר או במומלצים. שם הערוץ שמילאת צריך להיות תואם במלואו ותואם מבחינת רישיות (אותיות גדולות/קטנות).\n    Hide Subscriptions Live: הגדרה זו נדרסת על ידי ההגדרה הכללית „{appWideSetting}”, בסעיף „{subsection}” שב„{settingsSection}”\n    Hide Videos, Playlists and Channels Containing Text: הכנס מילה, חלק ממילה או ביטוי (ללא הבחנה בין אותיות גדולות וקטנות) כדי להסתיר את כל הסרטונים והרשימות שבשמם המקורי מופיע הביטוי, בכל FreeTube, למעט ההיסטוריה, הרשימות שלך וסרטונים בתוך רשימות.\n    Hide Videos on Watch: הסתרת סרטונים שנצפו מלשוניות סרטונים, Shorts וחי בעמודי המינוי והערוץ. לא משפיע על לשונית הבית בעמודי הערוצים\n  SponsorBlock Settings:\n    UseDeArrowTitles: החלפת כותרות הסרטונים עם כותרות ששלחו משתמשים ב־DeArrow.\n    UseDeArrowThumbnails: החלפת התמונות הממוזערות של הסרטונים בתמונות ממוזערות מ־DeArrow.\nMore: עוד\nOpen New Window: פתיחת חלון חדש\nSearch Bar:\n  Clear Input: פינוי הקלט\n  Remove: הסרה\nAre you sure you want to open this link?: לפתוח את הקישור הזה?\nUnknown YouTube url type, cannot be opened in app: סוג כתובת לא ידוע ל־YouTube, לא ניתן לפתיחה ביישום\nDefault Invidious instance has been set to {instance}: עותק Invidious שהוגדר כברירת מחדל הוא {instance}\nDefault Invidious instance has been cleared: נוקתה העדפת עותק ברירת המחדל של Invidious\nExternal link opening has been disabled in the general settings: פתיחת הקישורים החיצוניים מושבתת בהגדרות הכלליות\nPlaying Next Video Interval: הסרטון הבא יתחיל מייד. לחיצה לביטול. | הסרטון הבא יתנגן בעוד שנייה. לחיצה לביטול. | הסרטון הבא יתנגן בעוד {nextVideoInterval} שניות. לחיצה לביטול.\nScreenshot Success: צילום המסך נשמר\nScreenshot Error: צילום המסך נכשל. {error}\nNew Window: חלון חדש\nChannels:\n  Search bar placeholder: חיפוש ערוצים\n  Empty: רשימת הערוצים שלך ריקה כרגע.\n  Count: '{number} ערוצים נמצאו.'\n  Channels: ערוצים\n  Title: רשימת ערוצים\n  Unsubscribe Prompt: לבטל את המינוי על „{channelName}”?\nChapters:\n  Chapters: פרקים\n  Key Moments: רגעי שיא\nClipboard:\n  Copy failed: ההעתקה ללוח הגזירים נכשלה\n  Cannot access clipboard without a secure connection: לא ניתן לגשת ללוח הגזירים ללא חיבור מאובטח\nPreferences: העדפות\nOk: אישור\nHashtag:\n  This hashtag does not currently have any videos: לתגית ההקבץ הזו אין סרטונים כרגע\n  Hashtag: תגית הקבץ\nClose Banner: סגירת כרזה\nGo to page: מעבר אל {page}\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: כתוביות\n    Closed Captions: כתוביות לכבדי שמיעה\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: חדש\n    3D: תלת־ממד\nSearch character limit: שאילתת החיפוש חורגת ממגבלת התווים {searchCharacterLimit}\nFeed:\n  Feed Last Updated: 'הערוץ {feedName} התעדכן לאחרונה: {date}'\n  Refresh Feed: רענון {subscriptionName}\nAge Restricted:\n  This video is age restricted: הסרטון הזה מוגבל\n  This channel is age restricted: הערוץ הזה מוגבל בגיל\nYes, Restart: כן, להפעיל מחדש\nYes, Delete: כן, למחוק\nYes, Open Link: כן, לפתוח את הקישור\nCancel: ביטול\ncheckmark: ✓\nTag already exists: התגית „{tagName}” כבר קיימת\nMoments Ago: לפני מס׳ רגעים\nDisplay Label: '{label}:‏ {value}'\nChannel Unhidden: '{channel} הוסר ממסנן ערוצים'\nChannel Hidden: '{channel} נוסף למסנן ערוצים'\nTrimmed input must be at least N characters long: הקלט המקוצץ חייב להיות באורך של לפחות תו אחד | הקלט המקוצץ חייב להיות באורך של לפחות {length} תווים\nKeys:\n  arrowright: חץ ימינה\n  arrowup: חץ למעלה\n  arrowdown: חץ למטה\n  arrowleft: חץ שמאלה\n  ctrl: Ctrl\n  alt: Alt\n  enter: הכנס\n  plus: פלוס\n  shift: משמרת\nRight-click or hold to see history: לחיצה ימנית או החזקה כדי לראות היסטוריה\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nDescription:\n  Collapse Description: להציג פחות\n  Expand Description: …עוד\nAutoplay Interruption Timer: ניגון אוטומטי בוטל עקב {autoplayInterruptionIntervalHours} שעות של חוסר פעילות\nKeyboardShortcutPrompt:\n  Focus Search: התמקדות על סרגל החיפוש\n  Next Chapter: הפרק הבא\n  Search in New Window: חיפוש בחלון חדש\n  Zoom Out: התרחקות\n  Zoom In: התקרבות\n  Reset Zoom: איפוס המרחק / קנה מידת ממשק המשתמש\n  Close Window: סגירת החלון\n  Next Frame: התמונית הבאה (תוך כדי השהייה)\n  Last Frame: התמונית הקודמת (תוך כדי השהייה)\n  Last Chapter: הפרק האחרון\n  Skip by Tenths: דילוג בתוך הווידאו באחוזים (3 דילוגים ל־30% ממשך הנגינה)\n  Volume Up: הגברת עוצמת השמע\n  Volume Down: הנמכת עוצמת השמע\n  Full Window: מסך מלא/רגיל\n  Toggle Developer Tools: הצגת/הסתרת כלי פיתוח\n  Minimize Window: מזעור החלון\n  Take Screenshot: צילום המסך\n  Theatre Mode: מעבר/חזרה ממצב תיאטרון\n  Fullscreen: כניסה / יציאה ממסך מלא\n  History Backward: חזור אחורה בעמוד אחד\n  Small Fast Forward: קדימה X שניות בהתבסס על מרווח ההקדמה וקצב ההפעלה הנוכחי של הווידאו\n  Sections:\n    Video:\n      Playback: 'וידאו: השמעה'\n      General: 'וידאו: כללי'\n    App:\n      General: 'אפליקציה: כללי'\n      Situational: 'אפליקציה: מצבית'\n  Navigate to Settings: נווטו לדף ההגדרות\n  Small Rewind: חזרה אחורה ב־X שניות בהתבסס על מרווח החזרה ואחוז הנגינה הנוכחי של הסרטון\n  Play: הפעל/השהה\n  Decrease Video Speed: הפחתת מהירות הווידאו בהתאם לטווח קצב ההפעלה של הווידאו\n  Navigate to History: נווטו לדף ההיסטוריה\n  Refresh: רענן את הפיד עם התוכן העדכני ביותר\n  Focus Secondary Search: מקד את תשומת הלב על שורת החיפוש המשנית (אם יש אחת כזו)\n  Show Keyboard Shortcuts: הצג קיצורי מקלדת\n  Captions: הפעל/כבה כתוביות\n  Keyboard Shortcuts: קיצורי מקשים\n  Large Fast Forward: קדימה 10 שניות / הקפצת וידאו בהתאם לקצב ההפעלה הנוכחי\n  Mute: כבה/הפעל שקט\n  Increase Video Speed: הגדל את מהירות הווידאו בהתבסס על טווח קצב ההפעלה של הווידאו\n  Stats: הצג סטטיסטיקות וידאו\n  Picture in Picture: הפעל/י את מצב Picture-in-Picture\n  History Forward: לך קדימה עמוד אחד\n  New Window: צור חלון חדש\n  Large Rewind: חזור אחורה ב-10 שניות / חזור אחורה בסרטון בהתאם לקצב ההפעלה הנוכחי\n  Home: חתירה לתחילת הסרטון\n  End: חתירה לסוף הסרטון\n  Skip to Next Video: דילוג לסרטון הבא ברשימת הנגינה או הסרטון המומלץ הבא\n  Skip to Previous Video: דילוג לסרטון הקודם ברשימת הנגינה\nshortcutLabelSeparator: ｜\nCompact side navigation: ניווט צד מצומצם\nExpand side navigation: הרחבת ניווט צד\n"
  },
  {
    "path": "static/locales/hi.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'हिन्दी'\n\n# Webkit Menu Bar\nFile: 'फ़ाइल'\nQuit: 'बाहर आएं'\nEdit: 'संपादित करें'\nUndo: 'अनडू करें'\nRedo: 'फिर से करें'\nCut: 'काटें'\nCopy: 'कापी करें'\nPaste: 'पेस्ट करें'\nDelete: 'मिटाएं'\nSelect all: 'सबको चुनें'\nToggle Developer Tools: 'डेवलपर टूल टॉगल करें'\nActual size: 'वास्तविक आकार'\nZoom in: 'ज़ूम इन'\nZoom out: 'ज़ूम आउट'\nToggle fullscreen: 'फ़ुलस्क्रीन टॉगल करें'\nWindow: 'विंडो'\nMinimize: 'मिनिमाइज़ करें'\nClose: 'बंद करें'\nBack: 'पीछे जाएँ'\nForward: 'आगे जाएँ'\n\nVersion {versionNumber} is now available!  Click for more details: 'संस्करण {versionNumber} अब उपलब्ध है! अधिक विवरण के लिए क्लिक करें'\nDownload From Site: 'साइट से डाउनलोड करें'\nA new blog is now available, {blogTitle}. Click to view more: 'एक नया ब्लॉग अब उपलब्ध है, {blogTitle}। अधिक देखने के लिए क्लिक करें'\n\nGlobal:\n  Sort By: 'इसके अनुसार क्रमबद्ध करें'\n\n# Search Bar\n  Shorts: शॉर्ट्स\n  Videos: वीडियो\n  Live: लाइव\nSearch / Go to URL: 'खोज / यूआरएल पर जाएं'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'खोज फ़िल्टर'\n  Sort By:\n    Most Relevant: 'सबसे प्रासंगिक'\n    Rating: 'मूल्यांकन'\n    Upload Date: 'अपलोड की तारीख़'\n    View Count: 'दृश्य गणना'\n  Time:\n    Time: 'समय'\n    Any Time: 'किसी भी समय'\n    Last Hour: 'पिछले घंटे'\n    Today: 'आज'\n    This Week: 'इस हफ़्ते'\n    This Month: 'इस महीने'\n    This Year: 'इस साल'\n  Type:\n    Type: 'प्रकार'\n    All Types: 'सब प्रकार के'\n    Videos: 'वीडियो'\n    Channels: 'चैनल'\n    #& Playlists\n    Movies: चलचित्र\n  Duration:\n    Duration: 'अवधि'\n    All Durations: 'सभी अवधियाँ'\n    Short (< 4 minutes): 'छोटे (<4 मिनट)'\n    Long (> 20 minutes): 'बड़े (>20 मिनट)'\n  # On Search Page\n    Medium (4 - 20 minutes): माध्यम (4 - 20 minutes)\n  Search Results: 'खोज के परिणाम'\n  Fetching results. Please wait: 'परिणाम ला रहे है। कृपया प्रतीक्षा करे'\n  Fetch more results: 'ज़्यादा परिणाम लाए'\n# Sidebar\n  There are no more results for this search: इस खोज के लिए और कोई परिणाम नहीं है\n  Features:\n    Location: जगह\n    Features: विशेषताएँ\n    HD: HD\n    3D: 3D\n    Live: सीधा प्रसारण\n    4K: 4K\n    Subtitles: उपशीर्षक\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'सब्सक्रिप्शन'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'यह प्रोफ़ाइल के पास बहुत सारे सब्सक्रिप्शनस है।  RSS को बलपूर्वक प्रयोग करके रेट लिमिटिंग से बचाएं'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'आपके सब्सक्रिप्शन सूची वर्तमान में ख़ाली है। उन्हें यहां देखने के लिए सब्सक्रिप्शन जोड़ना प्रारंभ करें।'\n  Load More Videos: 'और वीडियो लोड करें'\n  Error Channels: त्रुटि वाले चैनल\n  Disabled Automatic Fetching: आपने स्वचालित सदस्यता लाना अक्षम कर दिया है। सदस्यताओं को यहां देखने के लिए उन्हें रीफ़्रेश करें।\n  Empty Channels: आपके सब्सक्राइब किए गए चैनल में वर्तमान में कोई वीडियो नहीं है।\nTrending:\n  Trending: 'रुझान में'\n  Trending Tabs: ट्रेंडिंग टैब्स\n  Gaming: गेमिंग\n  Sports: खेल-कूद\nMost Popular: 'सबसे लोकप्रिय'\nPlaylists: 'प्लेलिस्ट'\nUser Playlists:\n  Your Playlists: 'आपकी प्लेलिस्ट'\n  Empty Search Message: इस प्लेलिस्ट में आपकी खोज से मेल खाने वाला कोई वीडियो नहीं है\n  Search bar placeholder: प्लेलिस्ट में खोजें\nHistory:\n  # On History Page\n  History: 'इतिहास'\n  Watch History: 'देखने का इतिहास'\n  Your history list is currently empty.: 'आपकी इतिहास सूची वर्तमान में खाली है।'\n  Empty Search Message: आपके इतिहास में ऐसा कोई वीडियो नहीं है जो आपकी खोज से मेल खाता हो\n  Search bar placeholder: इतिहास में खोजें\nSettings:\n  # On Settings Page\n  Settings: 'सेटिंग्स'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'परिवर्तनों को प्रभावी करने के लिए ऐप को पुनः आरंभ करने की आवश्यकता है। पुनः आरंभ करें और परिवर्तन लागू करें?'\n  General Settings:\n    General Settings: 'जनरल सेटिंग्स'\n    Check for Updates: 'अपडेट के लिए जाँच शुरु करें'\n    Check for Latest Blog Posts: 'नवीनतम ब्लॉग पोस्ट के लिए जाँच करें'\n    Fallback to Non-Preferred Backend on Failure: 'विफलता पर गैर-पसंदीदा बैकएंड पर फ़ॉलबैक'\n    Enable Search Suggestions: 'खोज सुझाव सक्षम करें'\n    Default Landing Page: 'डिफ़ॉल्ट लैंडिंग पृष्ठ'\n    Locale Preference: 'स्थानीय प्रेफरन्स'\n    Preferred API Backend:\n      Preferred API Backend: 'पसंदीदा एपीआई बैकएंड'\n      Local API: 'स्थानीय एपीआई'\n      Invidious API: 'इनविडियस एपीआई'\n    Video View Type:\n      Video View Type: 'वीडियो दृश्य प्रकार'\n      Grid: 'ग्रिड'\n      List: 'सूची'\n    Thumbnail Preference:\n      Thumbnail Preference: 'थंमनेल प्रेफरन्स'\n      Default: 'डिफ़ॉल्ट'\n      Beginning: 'शुरुआत'\n      Middle: 'मध्य'\n      End: 'अंत'\n    Region for Trending: 'ट्रेंडिंग के लिए क्षेत्र'\n        #! List countries\n    No default instance has been set: कोई डिफ़ॉल्ट इंस्टेंस सेट नहीं किया गया है\n    External Link Handling:\n      Open Link: लिंक खोलें\n      Ask Before Opening Link: लिंक खोलने से पहले पूछें\n      External Link Handling: बाहरी लिंक हैंडलिंग\n      No Action: कोई कार्रवाई नहीं\n    System Default: सिस्टम डिफ़ॉल्ट\n    Current instance will be randomized on startup: स्टार्टअप पर वर्तमान इंस्टेंस यादृच्छिक किया जाएगा\n    The currently set default instance is {instance}: वर्तमान में निर्धारित डिफ़ॉल्ट इंस्टेंस {instance} है\n    Clear Default Instance: डिफ़ॉल्ट इंस्टेंस साफ़ करें\n    View all Invidious instance information: इनविडियस इंस्टेंस की सभी जानकारी देखें\n    Set Current Instance as Default: वर्तमान इंस्टेंस को डिफ़ॉल्ट के रूप में सेट करें\n    Current Invidious Instance: वर्तमान इनविडियस इंस्टेंस\n  Theme Settings:\n    Theme Settings: 'थीम सेटिंग्स'\n    Match Top Bar with Main Color: 'टॉप बार को मेन कलर से मैच करें'\n  Player Settings:\n    Proxy Videos Through Invidious: 'इनविडियस के माध्यम से प्रॉक्सी वीडियो'\nAbout:\n  #On About page\n  Email: ईमेल करें\nChannel:\n  Videos:\n    Videos: वीडियो\nVideo:\n  Open in Invidious: 'इनविडियस में खोलें'\n  Copy Invidious Link: 'इनविडियस लिंक को कॉपी करें'\n  Open Channel in Invidious: 'इनविडियस में चैनल खोलें'\n  Copy Invidious Channel Link: 'इनवीडियस चैनल लिंक कॉपी करें'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'लाइव चैट वर्तमान में Invidious API के साथ समर्थित नहीं है। YouTube से सीधा कनेक्शन आवश्यक है।'\nShare:\n  Invidious URL copied to clipboard: 'इनवीडियस URL क्लिपबोर्ड पर कापी किया गया'\n  Invidious Embed URL copied to clipboard: 'इनवीडियस एम्बेड URL क्लिपबोर्ड पर कापी किया गया'\n  Invidious Channel URL copied to clipboard: 'इनविडियस चैनल URL क्लिपबोर्ड पर कॉपी किया गया'\nTooltips:\n  General Settings:\n    Preferred API Backend: 'वह बैकएंड चुनें जिसका उपयोग FreeTube डेटा प्राप्त करने के लिए करता है। स्थानीय एपीआई एक अंतर्निहित चिमटा है। Invidious API को कनेक्ट करने के लिए Invidious सर्वर की आवश्यकता होती है।'\n    Invidious Instance: 'वह इनविडियस इंस्टेंस जिससे FreeTube API कॉल के लिए कनेक्ट होगा।'\n  Player Settings:\n    Proxy Videos Through Invidious: 'YouTube से सीधा संबंध बनाने के बजाय वीडियो परोसने के लिए Invidious से जुड़ेंगे। एपीआई वरीयता को ओवरराइड करता है।'\n  External Player Settings:\n    External Player: बाहरी प्लेयर चुनने पर, थंबनेल पर बाहरी प्लेयर में वीडियो खोलने के लिए (प्लेलिस्ट अगर समर्थित है) एक आइकन प्रदर्शित होगा। चेतावनी, द्वेषपूर्ण सेटिंग्स बाहरी खिलाड़ियों को प्रभावित नहीं करती हैं।\nInvidious API Error (Click to copy): 'कपटपूर्ण एपीआई त्रुटि (कॉपी करने के लिए क्लिक करें)'\nFalling back to Invidious API: 'Invidious API पर वापस आना'\nMore: अधिक\nNew Window: नई विंडो\nOpen New Window: नई विंडो खोलें\nChannels:\n  Channels: चैनल\n  Search bar placeholder: चैनल खोजें\n  Count: '{number} चैनल मिला(मिले)।'\n  Title: चैनल सूची\n  Empty: आपकी चैनल सूची वर्तमान में खाली है।\n  Unsubscribe Prompt: क्या आप वाकई \"{channelName}\" की सदस्यता छोड़ना चाहते हैं?\nAre you sure you want to open this link?: क्या आप वाकई इस लिंक को खोलना चाहते हैं?\nSearch Bar:\n  Clear Input: इनपुट खाली करें\n  Remove: हटाए\nDefault Invidious instance has been set to {instance}: डिफ़ॉल्ट इनविडियस इंस्टेंस को {instance} पर सेट कर दिया गया है\nDefault Invidious instance has been cleared: डिफ़ॉल्ट इनविडियस इंस्टेंस साफ़ कर दिया गया है\nPreferences: प्रेफरन्स\nSearch character limit: खोज क्वेरी {searchCharacterLimit} वर्ण सीमा से अधिक है\nRight-click or hold to see history: इतिहास देखने के लिए दायाँ क्लिक करें या दबाए रखें\nGo to page: जाओ\nClose Banner: बैनर बंद करें\nSearch Listing:\n  Label:\n    Subtitles: उपशीर्षक\n    Closed Captions: सीमित अनुशीर्षक\n    New: नया\n    4K: 4K\n    8K: 8K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: डेवलपर टूल टॉगल करें\n  Zoom In: ज़ूम इन\n  Zoom Out: ज़ूम आउट\n  Fullscreen: फ़ुलस्क्रीन टॉगल करें\nProfile:\n  Select All: सबको चुनें\n"
  },
  {
    "path": "static/locales/hr.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Hrvatski'\n\n# Webkit Menu Bar\nFile: 'Datoteka'\nQuit: 'Zatvori program'\nEdit: 'Uredi'\nUndo: 'Poništi'\nRedo: 'Ponovi'\nCut: 'Izreži'\nCopy: 'Kopiraj'\nPaste: 'Umetni'\nDelete: 'Izbriši'\nSelect all: 'Odaberi sve'\nToggle Developer Tools: 'Uključi/Isključi alate za programere'\nActual size: 'Stvarna veličina'\nZoom in: 'Uvećaj prikaz'\nZoom out: 'Umanji prikaz'\nToggle fullscreen: 'Uključi/Isključi cjeloekranski prikaz'\nWindow: 'Prozor'\nMinimize: 'Smanji prozor'\nClose: 'Zatvori'\nBack: 'Natrag'\nForward: 'Naprijed'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videa'\n  Shorts: Shorts videozapisi\n  Live: Uživo\n  Posts: Objave\n  Sort By: Redoslijed\n\n# Search Bar\n  Counts:\n    Video Count: 1 video | {count} videa\n    Subscriber Count: 1 pretplatnik | {count} pretplatnika\n    View Count: 1 prikaz | {count} prikaza\n    Watching Count: 1 gledatelj | {count} gledatelja\n    Channel Count: 1 kanal | {count} kanala\n    Comment Count: 1 komentar | {count} komentara\n    Like Count: 1 lajk | {count} lajkova\nSearch / Go to URL: 'Pretraži / Idi na URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtri pretrage'\n  Sort By:\n    Most Relevant: 'Najrelevantniji'\n    Rating: 'Ocjena'\n    Upload Date: 'Datum prijenosa'\n    View Count: 'Broj gledanja'\n  Time:\n    Time: 'Vrijeme'\n    Any Time: 'Bilo kada'\n    Last Hour: 'Zadnji sat'\n    Today: 'Danas'\n    This Week: 'Ovaj tjedan'\n    This Month: 'Ovaj mjesec'\n    This Year: 'Ova godina'\n  Type:\n    Type: 'Vrsta'\n    All Types: 'Sve vrste'\n    Videos: 'Videa'\n    Channels: 'Kanali'\n    #& Playlists\n    Movies: Filmovi\n  Duration:\n    Duration: 'Trajanje'\n    All Durations: 'Sva trajanja'\n    Short (< 4 minutes): 'Kratko (< 4 min)'\n    Long (> 20 minutes): 'Dugo (> 20 min)'\n  # On Search Page\n    Medium (4 - 20 minutes): Srednje (4 do 20 minuta)\n  Search Results: 'Rezultati pretrage'\n  Fetching results. Please wait: 'Rezultati se dohvaćaju. Pričekaj'\n  Fetch more results: 'Dohvati još rezultata'\n# Sidebar\n  There are no more results for this search: Nema daljnjih rezultata za ovu pretragu\n  Features:\n    Subtitles: Titlovi\n    HD: HD\n    Location: Lokacija\n    HDR: HDR\n    VR180: VR180\n    4K: 4K\n    Features: Značajke\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Uživo\n    360 Video: 360 video\n  Clear Filters: Isprazni filtre\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Pretplate'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tvoj popis pretplata je trenutačno prazan. Ako želiš uvesti tvoje pretplate, idi u postavke podataka i odaberi „Uvezi pretplate” ili traži kanale i pretplati se na njih.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Ovaj profil sadrži velik broj pretplata. Za izbjegavanje ograničenja stope koristit će se RSS\n  Load More Videos: Učitaj još videa\n  Error Channels: Kanali s greškama\n  Empty Channels: Tvoji pretplaćeni kanali trenutačno nemaju videa.\n  Disabled Automatic Fetching: Automatsko dohvaćanje pretplata je deaktivirano. Aktualiziraj pretplate da bi se ovdje prikazale.\n  Subscriptions Tabs: Kartica pretplata\n  All Subscription Tabs Hidden: Sve kartice pretplata su skrivene. Za prikaz sadržaja na ovom mjestu, sakrij neke kartice u pododjeljku „{subsection}” u „{settingsSection}”.\n  Empty Posts: Kanali na koje si pretplaćen/a trenutačno nemaju objave.\n  Load More Posts: Učitaj još objava\nTrending:\n  Trending: 'U trendu'\n  Trending Tabs: Kartice „U trendu”\n  Gaming: Igre\n  Sports: Sportovi\nMost Popular: 'Najpopularniji'\nPlaylists: 'Zbirke'\nUser Playlists:\n  Your Playlists: 'Tvoje zbirke'\n  Search bar placeholder: Traži zbirke\n  Empty Search Message: U ovoj zbirci nema videa koji odgovaraju tvojem pretraživanju\n  This playlist currently has no videos.: Ova zbirka trenutačno nema nijedan video.\n  Create New Playlist: Stvori novu zbirku\n  Add to Playlist: Dodaj u zbirku\n  Move Video Up: Premjesti video prema gore\n  Move Video Down: Premjesti video prema dolje\n  Remove from Playlist: Ukloni iz zbirke\n  Playlist Name: Ime zbirke\n  Playlist Description: Opis zbirke\n  Cancel: Odustani\n  Edit Playlist Info: Uredi podatke zbirke\n  Copy Playlist: Kopiraj zbirku\n  Delete Playlist: Ukloni zbirku\n  Are you sure you want to delete this playlist? This cannot be undone: Stvarno želiš izbrisati ovu zbirku? To se ne može poništiti.\n  Sort By:\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: Datum stvaranja (najnoviji)\n    EarliestCreatedFirst: Datum stvaranja (najstariji)\n    LatestUpdatedFirst: Datum aktualiziranja (najnoviji)\n    EarliestUpdatedFirst: Datum aktualiziranja (najstariji)\n    LatestPlayedFirst: Datum reproduciranja (najnoviji)\n    EarliestPlayedFirst: Datum reproduciranja (najstariji)\n  Remove Watched Videos: Ukloni gledana videa\n  Save Changes: Spremi promjene\n  You have no playlists. Click on the create new playlist button to create a new one.: Nemaš zbirke. Za stvaranje nove zbirke pritisni gumb za stvaranje nove zbirke.\n  SinglePlaylistView:\n    Toast:\n      Playlist {playlistName} has been deleted.: Zbirka „{playlistName}” je uklonjena.\n      This playlist is protected and cannot be removed.: Ova je zbirka zaštićena i ne može se ukloniti.\n      This playlist does not exist: Ova zbirka ne postoji\n      This video cannot be moved up.: Ovaj se video ne može premjestiti prema gore.\n      This video cannot be moved down.: Ovaj se video ne može premjestiti prema dolje.\n      Playlist name cannot be empty. Please input a name.: Ime zbirke ne može biti prazano. Upiši ime.\n      Playlist has been updated.: Zbirka je aktualizirana.\n      \"{videoCount} video(s) have been removed\": 1 video je uklonjen | {videoCount} videa su uklonjena\n      Video has been removed: Video je uklonjen\n      There was a problem with removing this video: Došlo je do problema pri uklanjanju ovog videa\n      There was an issue with updating this playlist.: Došlo je do problema s aktualiziranjem ove zbirke.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Neka videa zbirke još nisu učitani. Pritisni ovdje za kopiranje.\n      There were no videos to remove.: Nije bilo videa za uklanjanje.\n      This playlist is now used for quick bookmark: Ova se zbirka sada koristi za brze zabilješke\n      Reverted to use {oldPlaylistName} for quick bookmark: Vraćeno na korištenje zbirke „{oldPlaylistName}” za brze zabilješke\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Ova se zbirka sada koristi za brze zabilješke umjesto zbirke „{oldPlaylistName}”. Pritisni ovdje za poništavanje\n      This playlist is already being used for quick bookmark.: Ova se zbirka već koristi za brze zabilješke.\n      This playlist has a video with a duration error: Ova zbirka sadrži barem jedan video koji nema trajanje. Video će se svrstati kao da je njegovo trajanje nula.\n      Video has been removed. Click here to undo.: Video je uklonjen. Klikni ovdje za poništavanje uklanjanja.\n    Search for Videos: Traži videa\n  AddVideoPrompt:\n    N playlists selected: 'Odabrano: {playlistCount}'\n    Search in Playlists: Traži u zbirkama\n    Save: Spremi\n    Toast:\n      You haven't selected any playlist yet.: Još nisi odabrao/la nijednu zbirku.\n      \"Video(s) added to {playlistCount} playlists\": \"Videa dodana u 1 zbirku | Videa dodana u {playlistCount} zbirke | Videa dodana u {playlistCount} zbirki\"\n    Select a playlist to add your N videos to: Odaberi zbirku za dodavanje tvog videa | Odaberi zbirku za dodavanje tvojih {videoCount} videa\n    Added {count} Times: Već dodano | Dodano {count} puta\n    Allow Adding Duplicate Video(s): Dozvoli dodavanje duplih videa\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": 'Broj videa koji će se dodati: {videoCount} od {totalVideoCount}'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": 'Broj videa koji su već dodani: {videoCount} od {totalVideoCount}'\n  CreatePlaylistPrompt:\n    Create: Stvori\n    Toast:\n      There was an issue with creating the playlist.: Došlo je do problema s izradom zbirke.\n      There is already a playlist with this name. Please pick a different name.: Zbirka s ovim imenom već postoji. Odaberi jedno drugo ime.\n      Playlist {playlistName} has been successfully created.: Zbirka „{playlistName}” je uspješno stvorena.\n    New Playlist Name: Ime nove zbirke\n  Add to Favorites: Dodaj u zbirku „{playlistName}”\n  Remove from Favorites: Ukloni iz zbirke „{playlistName}”\n  Enable Quick Bookmark With This Playlist: Aktiviraj brze zabilješke s ovom zbirkom\n  Playlists with Matching Videos: Zbirke s poklapajućim videima\n  Quick Bookmark Enabled: Brze zabilješke aktivirano\n  Cannot delete the quick bookmark target playlist.: Nije moguće izbrisati zbirku cilja za brze zabilješke.\n  Remove Duplicate Videos: Ukloni dupla videa\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Stvarno želiš ukloniti 1 duplikat videa iz ove zbirke? To se ne može poništiti. | Stvarno želiš ukloniti {playlistItemCount} duplakata videa iz ove zbirke? To se ne može poništiti.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Stvarno želiš ukloniti 1 gledani video iz ove zbirke? To se ne može poništiti. | Stvarno želiš ukloniti {playlistItemCount} gledana/ih videa iz ove zbirke? To se ne može poništiti.\n  Export Playlist: Izvezi ovu zbirku\n  The playlist has been successfully exported: Zbirka je uspješno izvezena\n  TotalTimePlaylist: 'Ukupno vrijeme: {duration}'\n  Export list of URLs: Izvezi popisa URL-ova\nHistory:\n  # On History Page\n  History: 'Povijest'\n  Watch History: 'Povijest gledanja'\n  Your history list is currently empty.: 'Tvoj popis povijesti je trenutačno prazan.'\n  Search bar placeholder: Pretraži povijest\n  Empty Search Message: U ovoj zbirci nema videa u tvojoj povijesti koji odgovaraju tvojem pretraživanju\n  Case Sensitive Search: Razlikuj velika i mala slova tijekom pretraživanja\n  DateOldestHistory: Datum gledanja (najstariji)\n  DateNewestHistory: Datum gledanja (najnoviji)\nSettings:\n  # On Settings Page\n  Settings: 'Postavke'\n  General Settings:\n    General Settings: 'Opće'\n    Fallback to Non-Preferred Backend on Failure: 'U slučaju problema koristi sekundarni pozadinski sustav'\n    Enable Search Suggestions: 'Aktiviraj prijedloge pretrage'\n    Default Landing Page: 'Standardna početna stranica'\n    Locale Preference: 'Jezik'\n    Preferred API Backend:\n      Preferred API Backend: 'Primarno sučelje'\n      Local API: 'Lokalno sučelje'\n      Invidious API: 'Invidious sučelje'\n    Video View Type:\n      Video View Type: 'Način prikaza videa'\n      Grid: 'Popločeno'\n      List: 'Popis'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Minijature'\n      Default: 'Standardno'\n      Beginning: 'Početak'\n      Middle: 'Sredina'\n      End: 'Kraj'\n      Hidden: Skriveno\n      Blur: Neoštro\n    Region for Trending: 'Regija za videa u trendu'\n        #! List countries\n    Check for Latest Blog Posts: Traži najnovije objave na blogu\n    Check for Updates: Traži nove verzije\n    View all Invidious instance information: Pogledaj podatke svih Invidious instanci\n    System Default: Standard sustava\n    Clear Default Instance: Izbriši standardnu instancu\n    Set Current Instance as Default: Postavi trenutačnu instancu kao standardnu\n    Current instance will be randomized on startup: Trenutačna instanca će se slučajno odrediti nakon pokretanja računala\n    No default instance has been set: Nema standardno postavljene instance\n    The currently set default instance is {instance}: Trenutačno postavljena standardna instanca je {instance}\n    Current Invidious Instance: Trenutačna Invidious instanca\n    External Link Handling:\n      No Action: Bez radnje\n      Ask Before Opening Link: Pitaj prije otvaranja poveznice\n      Open Link: Otvori poveznicu\n      External Link Handling: Rukovanje eksternim poveznicama\n    Auto Load Next Page:\n      Label: Automatski učitaj sljedeću stranicu\n      Tooltip: Automatski učitaj dodatne stranice i komentare.\n    Open Deep Links In New Window: Otvori URL-ove proslijeđene FreeTubeu u novom prozoru\n    Minimize to system tray: Smanji na programsku traku\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Uskladi gornju traku s glavnom bojom'\n    Base Theme:\n      Base Theme: 'Osnova teme'\n      Black: 'Crna'\n      Dark: 'Tamna'\n      Light: 'Svijetla'\n      Dracula: 'Dracula'\n      System Default: Standard sustava\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastelno ružičasta\n      Hot Pink: Vruća ružičasta\n      Nordic: Nordic\n      Solarized Dark: Solarna tamna\n      Solarized Light: Solarna svijetla\n      Gruvbox Dark: Gruvbox tamna\n      Gruvbox Light: Gruvbox svijetla\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: Everforest tamna tvrda\n      Everforest Dark Medium: Everforest Dark srednji\n      Everforest Dark Low: Everforest Tamno nisko\n      Everforest Light Hard: Everforest svjetlo tvrdo\n      Everforest Light Medium: Everforest svjetlo srednje\n      Everforest Light Low: Everforest svjetlo nisko\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Glavna boja teme'\n      Red: 'Crvena'\n      Pink: 'Ružičasta'\n      Purple: 'Ljubičasta'\n      Deep Purple: 'Tamnoljubičasta'\n      Indigo: 'Modroljubičasta'\n      Blue: 'Plava'\n      Light Blue: 'Svjetloplava'\n      Cyan: 'Cijan'\n      Teal: 'Modrozelena'\n      Green: 'Zelena'\n      Light Green: 'Svjetlozelena'\n      Lime: 'Limunasta'\n      Yellow: 'Žuta'\n      Amber: 'Žutosmeđa'\n      Orange: 'Narančasta'\n      Deep Orange: 'Tamnonarančasta'\n      Dracula Cyan: 'Drakula cijan'\n      Dracula Green: 'Drakula zelena'\n      Dracula Orange: 'Drakula narančasta'\n      Dracula Pink: 'Drakula ružičasta'\n      Dracula Purple: 'Drakula ljubičasta'\n      Dracula Red: 'Drakula crvena'\n      Dracula Yellow: 'Drakula žuta'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha ružina vodica\n      Catppuccin Mocha Flamingo: Catppuccin Mocha flamingo\n      Catppuccin Mocha Pink: Catppuccin Mocha ružičasta\n      Catppuccin Mocha Mauve: Catppuccin Mocha ljubičasta\n      Catppuccin Mocha Red: Catppuccin Mocha crvena\n      Catppuccin Mocha Maroon: Catppuccin Mocha kestenjasta\n      Catppuccin Mocha Peach: Catppuccin Mocha breskva\n      Catppuccin Mocha Yellow: Catppuccin Mocha žuta\n      Catppuccin Mocha Teal: Catppuccin Mocha plavozelena\n      Catppuccin Mocha Sky: Catppuccin Mocha nebo\n      Catppuccin Mocha Sapphire: Catppuccin Mocha safir\n      Catppuccin Mocha Blue: Catppuccin Mocha plava\n      Catppuccin Mocha Lavender: Catppuccin Mocha lavanda\n      Catppuccin Mocha Green: Catppuccin Mocha zelena\n      Solarized Blue: Solarna plava\n      Solarized Green: Solarna zelena\n      Solarized Yellow: Solarna žuta\n      Solarized Orange: Solarna narančasta\n      Solarized Red: Solarna crvena\n      Solarized Magenta: Solarna magenta\n      Solarized Violet: Solarna ljubičasta\n      Solarized Cyan: Solarna cijan\n      Gruvbox Light Orange: Gruvbox svjetlonarančasta\n      Gruvbox Dark Green: Gruvbox tamnozelena\n      Catppuccin Frappe Pink: Catppuccin Frappe ružičasta\n      Catppuccin Frappe Rosewater: Catppuccin Frappe ružina vodica\n      Catppuccin Frappe Flamingo: Catppuccin Frappe flamingo\n      Catppuccin Frappe Mauve: Catppuccin Frappe purpurna\n      Catppuccin Frappe Red: Catppuccin Frappe crvena\n      Catppuccin Frappe Maroon: Catppuccin Frappe kestenjasta\n      Catppuccin Frappe Peach: Catppuccin Frappe breskva\n      Catppuccin Frappe Yellow: Catppuccin Frappe žuta\n      Catppuccin Frappe Green: Catppuccin Frappe zelena\n      Catppuccin Frappe Teal: Catppuccin Frappe tirkiz\n      Catppuccin Frappe Sky: Catppuccin Frappe nebo\n      Catppuccin Frappe Sapphire: Catppuccin Frappe safir\n      Catppuccin Frappe Blue: Catppuccin Frappe plava\n      Catppuccin Frappe Lavender: Catppuccin Frappe lavanda\n      Gruvbox Dark Yellow: Gruvbox tamnožuta\n      Gruvbox Dark Blue: Gruvbox tamnoplava\n      Gruvbox Dark Purple: Gruvbox tamnoljubičasta\n      Gruvbox Dark Aqua: Gruvbox tamna voda\n      Gruvbox Dark Orange: Gruvbox tamnonarančasta\n      Gruvbox Light Red: Gruvbox svjetlocrvena\n      Gruvbox Light Blue: Gruvbox svjetloplava\n      Gruvbox Light Purple: Gruvbox svjetloljubičasta\n      Everforest Dark Green: Everforest tamno zelena\n      Everforest Dark Red: Everforest tamno crvena\n      Everforest Dark Orange: Everforest tamno narančasta\n      Everforest Dark Yellow: Everforest Tamnožuta\n      Everforest Dark Purple: Everforest tamnoljubičasta\n      Everforest Dark Aqua: Everforest Tamna voda\n      Everforest Dark Blue: Everforest Tamnoplava\n      Everforest Light Red: Everforest svijetlo crvena\n      Everforest Light Orange: Everforest svijetlo narančasta\n      Everforest Light Yellow: Everforest Svijetlo žuta\n      Everforest Light Green: Everforest svijetlo zelena\n      Everforest Light Aqua: Everforest svjetlo vodena\n      Everforest Light Blue: Everforest svijetlo plava\n      Everforest Light Purple: Everforest svijetlo ljubičasta\n      Catppuccin Latte Mauve: Catppuccin Latte ljubičasta\n      Catppuccin Latte Red: Catppuccin Latte crvena\n    Secondary Color Theme: 'Sekundarna boja teme'\n        #* Main Color Theme\n    UI Scale: Uvećanje korisničkog sučelja\n    Disable Smooth Scrolling: Deaktiviraj neisprekidano pomicanje\n    Expand Side Bar by Default: Standardno proširi bočnu traku\n    Hide Side Bar Labels: Sakrij oznake bočnih traka\n    Hide FreeTube Header Logo: Sakrij FreeTube logotip u zaglavlju\n  Player Settings:\n    Player Settings: 'Player'\n    Play Next Video: 'Automatski reproduciraj preporučena videa'\n    Turn on Subtitles by Default: 'Standardno uključi titlove'\n    Autoplay Videos: 'Pokreni videa automatski'\n    Proxy Videos Through Invidious: 'Koristi Invidious kao posrednika videa'\n    Autoplay Playlists: 'Automatski reproduciraj videa zbirki'\n    Enable Theatre Mode by Default: 'Standardno aktiviraj kazališni modus'\n    Default Volume: 'Standardna glasnoća'\n    Default Playback Rate: 'Standardna brzina reprodukcije'\n    Default Video Format:\n      Default Video Format: 'Standardni videoformat'\n      Dash Formats: 'DASH formati'\n      Legacy Formats: 'Stari formati'\n      Audio Formats: 'Audioformati'\n    Default Quality:\n      Default Quality: 'Standardna kvaliteta'\n      Auto: 'Automatski'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Timer za odbrojavanje automatske reprodukcije\n    Scroll Volume Over Video Player: Mijenjaj glasnoću u video playeru\n    Display Play Button In Video Player: Prikaži gumb za pokretanje u video playeru\n    Fast-Forward / Rewind Interval: Interval za premotavanje naprijed/natrag\n    Scroll Playback Rate Over Video Player: Mijenjaj brzinu reprodukcije u video playeru\n    Video Playback Rate Interval: Interval brzine reprodukcije videa\n    Max Video Playback Rate: Maksimalna brzina reprodukcije videa\n    Screenshot:\n      Enable: Aktiviraj snimanje ekrana\n      Format Label: Format snimke ekrana\n      Quality Label: Kvaliteta snimke ekrana\n      Error:\n        Forbidden Characters: Zabranjeni znakovi\n        Empty File Name: Prazno ime datoteke\n      Folder Label: Mapa snimke ekrana\n      Folder Button: Odaberi mapu\n      Ask Path: Zatraži mapu za spremanje\n      File Name Label: Format imena datoteke\n      File Name Tooltip: Možeš koristiti sljedeće varijable. %Y godina 4 znamenke. %M mjesec 2 znamenke. %D dan 2 znamenke. %H sat 2 znamenke. %N minuta 2 znamenke. %S sekunda 2 znamenke. %T milisekunda 3 znamenke. %s video sekunda. %t milisekunda videa 3 znamenke. %i ID videa.\n    Enter Fullscreen on Display Rotate: Koristi cjeloekranski prikaz pri okretanju ekrana\n    Skip by Scrolling Over Video Player: Preskoči pomicanjem preko video playera\n    Autoplay Interruption Timer: Timer za prekidanje automatske reprodukcije\n    Default Viewing Mode:\n      Theater: Kino\n      Default Viewing Mode: Standardni modus gledanja\n      Full Screen: Cijeli ekran\n      Picture in Picture: Slika u slici\n      External Player: Eksterni player ({externalPlayerName})\n  Privacy Settings:\n    Privacy Settings: 'Privatnost'\n    Remember History: 'Zapamti povijest gledanja'\n    Save Watched Progress: 'Spremi napredak gledanja'\n    Clear Search Cache: 'Isprazni predmemoriju pretrage'\n    Are you sure you want to clear out your search cache?: 'Stvarno želiš isprazniti predmemoriju pretrage?'\n    Search cache has been cleared: 'Predmemorija pretrage je ispražnjena'\n    Remove Watch History: 'Ukloni povijest gledanja'\n    Are you sure you want to remove your entire watch history?: 'Stvarno želiš ukloniti cijelu povijest gledanja?'\n    Watch history has been cleared: 'Povijest gledanja je ispražnjena'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Stvarno želiš ukloniti sve pretplate i profile? Ovo je nepovratna radnja.\n    Remove All Subscriptions / Profiles: Ukloni sve pretplate/profile\n    Save Watched Videos With Last Viewed Playlist: Spremi gledana videa sa zadnjom gledanom zbirkom\n    Remove All Playlists: Ukloni sve zbirke\n    All playlists have been removed: Sve zbirke su uklonjene\n    Are you sure you want to remove all your playlists?: Stvarno želiš ukloniti sve tvoje zbirke?\n    Remember Search History: Zapamti povijest pretraživanja\n    Clear Search History and Cache: Izbriši povijest pretraživanja i predmemoriju\n    Search history and cache have been cleared: Povijest pretraživanja i predmemorija su izbrisani\n    Are you sure you want to clear out your search history and cache?: Stvarno želiš izbrisati povijest pretraživanja i predmemoriju?\n    Watched Progress Saving Mode:\n      Modes:\n        Semi-auto: Poluautomatski\n        Never: Nikada\n        Auto: Automatski\n      Tooltip: Automatski = Sprema se prilikom svakog izlaska s video stranice, kada video završi i kada dođe do greške (npr. ograničenje brzine ili istekla sesija gledanja). Poluautomatski = Kao automatski, osim prilikom izlaska s video stranice. Napredak gledanja može se ručno spremiti pomoću gumba \"Spremi napredak gledanja\", koji se nalazi ispod video playera.\n  Subscription Settings:\n    Subscription Settings: 'Pretplata'\n    Fetch Feeds from RSS: 'Dohvati feedove s RSS-a'\n    Fetch Automatically: Automatski dohvati feed\n    Confirm Before Unsubscribing: Izbjegni slučajno otkazivanje pretplate\n\n    'Limit the number of videos displayed for each channel': Ograniči broj prikazanih videa za svaki kanal\n    To: Na\n  Data Settings:\n    Unknown data key: Nepoznat podatkovni ključ\n    Unable to write file: Datoteka se ne može zapisati\n    Unable to read file: Datoteka se ne može čitati\n    All watched history has been successfully exported: Sva povijest gledanja je uspješno izvezena\n    All watched history has been successfully imported: Sva povijest gledanja je uspješno uvezena\n    History object has insufficient data, skipping item: Objekt povijesti nema dovoljno podataka. Preskače se\n    Subscriptions have been successfully exported: Pretplate su uspješno izvezene\n    Invalid history file: Nevaljana datoteka povijesti\n    Invalid subscriptions file: Nevaljana datoteka pretplata\n    All subscriptions have been successfully imported: Sve pretplate su uspješno uvezene\n    All subscriptions and profiles have been successfully imported: Sve pretplate i profili su uspješno uvezeni\n    Profile object has insufficient data, skipping item: Objekt profila nema dovoljno podataka. Preskače se\n    Export History: Izvezi povijest\n    Import History: Uvezi povijest\n    Export NewPipe: Izvezi NewPipe\n    Export YouTube: Izvezi YouTube\n    Export FreeTube: Izvezi FreeTube\n    Export Subscriptions: Izvezi pretplate\n    Import Subscriptions: Uvezi pretplate\n    Select Export Type: Odaberi vrstu izvoza\n    Data Settings: Podaci\n    How do I import my subscriptions?: Kako uvesti pretplate?\n    Manage Subscriptions: Upravljaj pretplatama\n    Import Playlists: Uvezi zbirke\n    Export Playlists: Izvezi zbirke\n    Playlist insufficient data: Nedovoljno podataka za „{playlist}” zbirku, element se preskače\n    All playlists has been successfully imported: Sve zbirke su uspješno uvezene\n    All playlists has been successfully exported: Sve zbirke su uspješno izvezene\n    Subscription File: Datoteka pretplate\n    History File: Datoteka povijesti\n    Playlist File: Datoteka zbirke\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Ova opcija izvozi videa iz svih zbirki u jednu zbirku pod nazivom „Favoriti”.\\nKako izvesti i uvesti videa u zbirkama za stariju FreeTube verziju:\\n 1. Izvezi svoje zbirke s ovom opcijom aktiviranom.\\n2. Izbriši sve svoje postojeće zbirke pomoću opcije „Ukloni sve zbirke” u postavkama privatnosti.\\n3. Pokreni stariju FreeTube verziju i uvezi izvezene zbirke.\\\"\"\n      Label: Izvezi zbirke za starije FreeTube verzije\n    Search history file: Datoteka povijesti pretraživanja\n    Search history: Povijest pretraživanja\n    Import search history: Uvezi povijesti pretraživanja\n    Export search history: Izvezi povijesti pretraživanja\n    All search history has been successfully imported: Sva povijest pretraživanja je uspješno uvezena\n    All search history has been successfully exported: Sva povijest pretraživanja je uspješno izvezena\n  Distraction Free Settings:\n    Hide Trending Videos: Sakrij videa u trendu\n    Hide Recommended Videos: Sakrij preporučena videa\n    Hide Channel Subscribers: Sakrij pretplatnike na kanal\n    Hide Live Chat: Sakrij razgovor uživo\n    Hide Popular Videos: Sakrij popularna videa\n    Hide Comment Likes: Sakrij ocjene komentara\n    Hide Video Likes And Dislikes: Sakrij broj sviđanja videa\n    Hide Video Views: Sakrij broj gledanja videa\n    Distraction Free Settings: Nesmetan rad\n    Hide Active Subscriptions: Sakrij aktivne pretplate\n    Hide Playlists: Sakrij zbirke\n    Hide Comments: Sakrij komentare\n    Hide Sharing Actions: Sakrij radnje dijeljenja\n    Hide Videos on Watch: 'Sakrij video nakon gledanja'\n    Hide Video Description: Sakrij opis videa\n    Hide Live Streams: Sakrij prijenose uživo\n    Hide Chapters: Sakrij poglavlja\n    Hide Upcoming Premieres: Sakrij nadolazeće premijere\n    Hide Channels: Sakrij videa iz kanala\n    Hide Channels Placeholder: ID kanala\n    Display Titles Without Excessive Capitalisation: Prikaži naslove bez pretjeranog korištenja velikih slova i interpunkcije\n    Hide Featured Channels: Sakrij istaknute kanale\n    Hide Channel Playlists: Sakrij karticu „Zbirke” kanala\n    Hide Channel Shorts: Sakrij karticu „Kratka videa” kanala\n    Sections:\n      Watch Page: Stranica gledanja\n      General: Opće\n      Side Bar: Bočna traka\n      Channel Page: Stranica kanala\n      Subscriptions Page: Stranica pretplata\n    Hide Channel Podcasts: Sakrij karticu „Podcasti” kanala\n    Hide Channel Releases: Sakrij karticu „Izdanja” kanala\n    Hide Subscriptions Shorts: Sakrij pretplate kratkih videa\n    Hide Subscriptions Live: Sakrij pretplate videa uživo\n    Hide Subscriptions Videos: Sakrij pretplate videa\n    Hide Profile Pictures in Comments: Sakrij slike profila u komentarima\n    Hide Channels Invalid: Navedeni ID kanala nije bio ispravan\n    Hide Channels Disabled Message: Neki su kanali blokirani upotrebom ID-a i nisu obrađeni. Funkcija je blokirana tijekom aktualiziranje tih ID-ova\n    Hide Channels Already Exists: ID kanala već postoji\n    Hide Channels API Error: Greška pri dohvaćanju korisnika s navedenim ID-om. Ponovo provjeri točnost ID-a.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Riječ, fragment riječi ili fraza\n    Hide Videos, Playlists and Channels Containing Text: Sakrij videa i zbirke koji sadrže tekst\n    Hide Channel Home: Sakrij karticu „Početna” kanala\n    Show Added Items: Prikaži dodane stavke\n    Hide Channel Courses: Sakrij karticu \"Tečajevi\" kanala\n    Hide Channel Posts: Sakrij karticu „Objave” kanala\n    Hide Subscriptions Posts: Sakrij objave o pretplatama\n  The app needs to restart for changes to take effect. Restart and apply change?: Promjene će se primijeniti nakon ponovnog pokeretanja programa. Ponovo pokrenuti program?\n  Proxy Settings:\n    Country: Zemlja\n    Error getting network information. Is your proxy configured properly?: Greška pri dohvaćanju mrežnih podataka. Je li tvoj posrednik pravilno konfiguriran?\n    City: Grad\n    Region: Regija\n    Ip: IP\n    Your Info: Tvoji podaci\n    Test Proxy: Provjeri posrednika\n    Clicking on Test Proxy will send a request to: Pritiskom gumba „Provjeri posrednika” šalje se zahtjev na\n    Proxy Port Number: Broj priključka posrednika\n    Proxy Host: Računalo posrednika\n    Proxy Protocol: Protokol posrednika\n    Enable Tor / Proxy: Aktiviraj Tor/Posrednik\n    Proxy Settings: Posrednik\n    Proxy Warning: FreeTube nema ugrađeni proxy, ali se može povezati s eksternim proxyjem, poput onog koji radi na tvom računalu poput Tor-a ili eksternog proxyja, poput SOCKS5 proxyja koji pružaju neki VPN-ovi. Ako je aktiviran, provjeri je li tvoj proxy/Tor pravilno konfiguriran, inače FreeTube neće moći dohvatiti nikoje podatke.\n    Proxy Username: Korisničko ime za proxy\n    Proxy Password: Lozinka za proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Obavijesti kad se preskoči segment sponzora\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API-a za blokiranja sponzora (standardno je https://sponsor.ajay.app)\n    Enable SponsorBlock: Aktiviraj blokiranja sponzora\n    SponsorBlock Settings: Blokiranja sponzora\n    Skip Options:\n      Auto Skip: Automatsko preskakanje\n      Show In Seek Bar: Prikaži u traci napretka\n      Skip Option: Opcija preskakanja\n      Prompt To Skip: Poziv za preskakanje\n      Do Nothing: Ne čini ništa\n    Category Color: Boja kategorije\n    UseDeArrowTitles: Koristi DeArrow Video naslove\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL za API DeArrow generatora minijatura (Standardna adresa je: https://dearrow-thumb.ajay.app)'\n    UseDeArrowThumbnails: Koristi DeArrow za minijature\n  External Player Settings:\n    Custom External Player Arguments: Argumenti prilagođenog eksternog playera\n    Custom External Player Executable: Izvršna datoteka prilagođenog eksternog playera\n    Ignore Unsupported Action Warnings: Zanemari upozorenja o nepodržanim radnjama\n    External Player: Eksterni player\n    External Player Settings: Eksterni player\n    Players:\n      None:\n        Name: Bez\n    Ignore Default Arguments: Zanemari zadane argumente\n  Parental Control Settings:\n    Parental Control Settings: Roditeljski nadzor\n    Hide Unsubscribe Button: Sakrij gumb za odjavu\n    Hide Search Bar: Sakrij traku pretrage\n    Show Family Friendly Only: Prikaži samo prikladne za obitelji\n    Hide Uploader on Watch page: Sakrij prenositelja na stranici gledanja\n  Experimental Settings:\n    Warning: Ovo su eksperimentalne postavke. Kad su aktivirane mogu prouzročiti prekid programa. Preporučujemo spremanje sigurnosnih kopija. Koristi na vlastitu odgovornost!\n    Experimental Settings: Eksperimentalno\n    Replace HTTP Cache: Zamijeni HTTP predmemoriju\n  Password Dialog:\n    Enter Password To Unlock: Za otključavanje postavki upiši lozinku\n    Password: Lozinka\n  Password Settings:\n    Password Settings: Lozinka\n    Set Password: Postavi lozinku\n    Remove Password: Ukloni lozinku\n    Set Password To Prevent Access: Postavi lozinku za sprečavanja pristupa postavkama\n  Sort Settings Sections (A-Z): Razvrstaj odjeljke postavki (A-Z)\n  Return to Settings Menu: Vrati se na izbornik postavki\nAbout:\n  #On About page\n  About: 'Informacije'\n  #& About\n  Website: Web-stranica\n  Blog: Blog\n  Credits: Zasluge\n  FAQ: Često postavljena pitanja\n  Email: E-adresa\n  Beta: Beta\n  Donate: Doniraj\n  Help: Pomoć\n  Chat on Matrix: Razgovaraj na Matrixu\n  Please check for duplicates before posting: Prije slanja greške, provjeri, je li ista greška već prijavljena\n  these people and projects: ovi ljudi i projekti\n  Translate: Prevodi\n  room rules: pravila sobe\n  Mastodon: Mastodon\n  GitHub issues: GitHub problemi\n  Report a problem: Prijavi grešku\n  FreeTube Wiki: FreeTube Wiki\n  GitHub releases: GitHub izdanja\n  Downloads / Changelog: Preuzimanja/dnevnik promjena\n  Source code: Izvorni kod\n  Discussions: Diskusije\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: 'Licenca: {licenseLink}'\n  Please read the {roomRulesLink}: Pročitaj {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube omogućuju {creditsPageLink}\nProfile:\n  All Channels: 'Svi kanali'\n  Profile Manager: 'Upravljač profila'\n  Create New Profile: 'Stvori novi profil'\n  Edit Profile: 'Uredi profil'\n  Color Picker: 'Birač boja'\n  Custom Color: 'Prilagođena boja'\n  Profile Preview: 'Pregled profila'\n  Create Profile: 'Stvori profil'\n  Update Profile: 'Aktualiziraj profil'\n  Make Default Profile: 'Postavi kao standardni profil'\n  Delete Profile: 'Izbriši profil'\n  Are you sure you want to delete this profile?: 'Stvarno želiš izbrisati ovaj profil?'\n  All subscriptions will also be deleted.: 'Izbrisat će se i sve pretplate.'\n  Your profile name cannot be empty: 'Ime profila ne smije biti prazno'\n  Profile has been created: 'Profil je stvoren'\n  Profile has been updated: 'Profil je aktualiziran'\n  Your default profile has been set to {profile}: 'Tvoj standardni profil je postavljen na {profile}'\n  Removed {profile} from your profiles: '{profile} je uklonjen iz tvojih profila'\n  Your default profile has been changed to your primary profile: 'Tvoj standardni profil je promijenjen u tvoj primarni profil'\n  '{profile} is now the active profile': '{profile} je sada aktivni profil'\n#On Channel Page\n  Profile Select: Biranje profila\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Stvarno želiš izbrisati odabrane kanale? Ovime se kanali ne brišu iz drugih profila.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Ovo je tvoj primarni profil. Stvarno želiš izbrisati odabrane kanale? Ti kanali će se izbrisati iz svih profila u kojima se pronađu.\n  No channel(s) have been selected: Nije odabran nijedan kanal\n  Add Selected To Profile: Dodaj odabrane u profil\n  Delete Selected: Izbriši odabrane\n  Select None: Odaberi ništa\n  Select All: Odaberi sve\n  '{number} selected': 'Broj odabranih: {number}'\n  Other Channels: Ostali kanali\n  Subscription List: Popis pretplata\n  Profile Filter: Filtar profila\n  Profile Settings: Profil\n  Toggle Profile List: Uključi/Isključi popis profila\n  Profile Name: Ime profila\n  Edit Profile Name: Uredi ime profila\n  Create Profile Name: Stvori ime profila\n  Open Profile Dropdown: Otvori rasklopiv izbornik profila\n  Close Profile Dropdown: Zatvori rasklopiv izbornik profila\nChannel:\n  Subscribe: 'Pretplati se'\n  Unsubscribe: 'Otkaži pretplatu'\n  Search Channel: 'Pretraži kanal'\n  Your search results have returned 0 results: 'Pretraživanje je vratilo 0 rezultata'\n  Videos:\n    Videos: 'Videa'\n    This channel does not currently have any videos: 'Na ovom kanalu trenutačno nema videa'\n    Sort Types:\n      Newest: 'Najnoviji'\n      Oldest: 'Najstariji'\n      Most Popular: 'Najpopularniji'\n  Playlists:\n    Playlists: 'Zbirke'\n    This channel does not currently have any playlists: 'Ovaj kanal trenutačno ne sadrži nijednu zbirku'\n    Sort Types:\n      Last Video Added: 'Zadnji dodani video'\n      Newest: 'Najnoviji'\n      Oldest: 'Najstariji'\n  About:\n    About: 'Informacije'\n    Channel Description: 'Opis kanala'\n    Featured Channels: 'Istaknuti kanali'\n    Tags:\n      Tags: Oznake\n      Search for: Traži „{tag}”\n    Details: Detalji\n    Joined: Pridruženo\n    Location: Lokacija\n  Added channel to your subscriptions: Kanal je dodan tvojim pretplatama\n  Removed subscription from {count} other channel(s): Uklonjena pretplata iz {count} drugih kanala\n  Channel has been removed from your subscriptions: Kanal je uklonjen iz tvojih pretplata\n  Channel Tabs: Kartice kanala\n  This channel does not exist: Ovaj kanal ne postoji\n  This channel does not allow searching: Ovaj kanal ne dozvoljava pretraživanje\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Ovaj je kanal dobno ograničen i trenutačno se ne može gledati na FreeTubeu.\n  Live:\n    Live: Uživo\n    This channel does not currently have any live streams: Ovaj kanal trenutačno nema prijenosa uživo\n  Posts:\n    This channel currently does not have any posts: Ovaj kanal trenutačno nema objava\n    Reveal Answers: Prikaži odgovore\n    Hide Answers: Sakrij odgovore\n    votes: '{votes} glasa'\n    Video hidden by FreeTube: Video skriven od FreeTubea\n    View Full Post: Pogledaj cijelu objavu\n    Viewing Posts Only Supported By Invidious: Prikazivanje postova podržava samo Invidious. Idi na karticu zajednice kanala za prikaz sadržaja bez Invidiousa.\n  Shorts:\n    This channel does not currently have any shorts: Ovaj kanal trenutačno nema kratka videa\n  Releases:\n    Releases: Izdanja\n    This channel does not currently have any releases: Ovaj kanal trenutačno nema izdanja\n  Podcasts:\n    Podcasts: Podcasti\n    This channel does not currently have any podcasts: Ovaj kanal trenutačno nema podcastova\n  Home:\n    Home: Početna\n    View Playlist: Pogledaj zbirku\n  Courses:\n    Courses: Tečajevi\n    This channel does not currently have any courses: Ovaj kanal trenutno nema tečajeve\nVideo:\n  Mark As Watched: 'Označi kao pogledano'\n  Remove From History: 'Ukloni iz povijesti'\n  Video has been marked as watched: 'Video je označen kao pogledan'\n  Video has been removed from your history: 'Video je uklonjen iz tvoje povijesti'\n  Open in YouTube: 'Otvori na YouTube stranici'\n  Copy YouTube Link: 'Kopiraj poveznicu na YouTube'\n  Open YouTube Embedded Player: 'Otvori ugrađeni YouTube player'\n  Copy YouTube Embedded Player Link: 'Kopiraj poveznicu na ugrađeni YouTube player'\n  Open in Invidious: 'Otvori na Invidious stranici'\n  Copy Invidious Link: 'Kopiraj poveznicu na Invidious'\n  Views: 'Gledanja'\n  Watched: 'Pogledano'\n  # As in a Live Video\n  Live: 'Uživo'\n  Live Now: 'Sada uživo'\n  Live Chat: 'Razgovor uživo'\n  Enable Live Chat: 'Aktiviraj razgovor uživo'\n  Live Chat is currently not supported in this build.: 'Razgovor uživo trenutačno nije podržan u ovoj verziji.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Razgovor uživo je aktiviran. Poruke razgovora pojavit će se ovdje nakon slanja.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Razgovor uživo trenutačno nije podržan s Invidious sučeljem. Potrebna je izravna veza s YouTubeom.'\n  Published:\n    In less than a minute: Manje od jedne minute\n  Published on: 'Objavljeno'\n#& Videos\n  Autoplay: Automatska reprodukcija\n  Previous: Prethodno\n  Next: Dalje\n  Reverse Playlist: Obrni redoslijed zbirke\n  Shuffle Playlist: Slučajni redoslijed zbirke\n  Loop Playlist: Ponavljaj zbirku\n  Starting soon, please refresh the page to check again: Uskoro počinje. Aktualiziraj stranicu za ponovnu provjeru\n  Copy Invidious Channel Link: 'Kopiraj poveznicu na Invidious kanal'\n  Open Channel in Invidious: 'Otvori kanal na Invidious stranici'\n  Copy YouTube Channel Link: 'Kopiraj poveznicu na YouTube kanal'\n  Open Channel in YouTube: 'Otvori kanal na YouTube stranici'\n  Started streaming on: Početak prijenosa\n  Streamed on: Prijenos\n  Video has been removed from your saved list: Video je uklonjen iz tvojeg popisa spremljenih\n  Video has been saved: Video je spremljen\n  Save Video: Spremi video\n  Sponsor Block category:\n    music offtopic: Druga vrsta glazbe\n    interaction: Interakcija\n    self-promotion: Samopromocija\n    outro: Kraj\n    intro: Uvod\n    sponsor: Sponzor\n    recap: Rekapitulacija\n    filler: Dodatni materijal\n  External Player:\n    Unsupported Actions:\n      starting video at offset: pokretanje videa pri odmaku\n      looping playlists: ponavljanje zbirki\n      shuffling playlists: slučajni redoslijed zbirki\n      reversing playlists: preokretanje redoslijeda zbirki\n      opening playlists: otvaranje zbirki\n      opening specific video in a playlist (falling back to opening the video): otvaranje određenog videa u zbirki (vraćanje na otvaranje videa)\n      setting a playback rate: postavljanje brzine reprodukcije\n    UnsupportedActionTemplate: '{externalPlayer} ne podržava: {action}'\n    OpeningTemplate: Otvara se {videoOrPlaylist} u {externalPlayer} …\n    playlist: zbirka\n    video: video\n    OpenInTemplate: Otvori u {externalPlayer}\n  Premieres: Premijere\n  Show Super Chat Comment: Prikaži Super Chat komentar\n  Scroll to Bottom: Pomakni se skroz dolje\n  Upcoming: Predstojeći\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Razgovor uživo nije dostupan za ovaj prijenos. Možda ga je autor deaktivirao.\n  Unhide Channel: Prikaži kanal\n  Hide Channel: Sakrij kanal\n  More Options: Više opcija\n  Player:\n    Stats:\n      Stats: Statistika\n      CodecsVideoAudio: 'Kodeci: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Bitrate: 'Brzina: {bitrate} kbps'\n      Resolution: 'Rezolucija: {width}x{height}{''@''}{frameRate}'\n      CodecsVideoAudioNoItags: 'Kodeci: {videoCodec} / {audioCodec}'\n      Volume: 'Glasnoća: {volumePercentage}%'\n      Video ID: 'ID videa: {videoId}'\n      Media Formats: 'Formati medija: {formats}'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Ispušteni kadrovi: {droppedFrames} / Ukupni broj kadrova: {totalFrames}'\n      Bandwidth: 'Propusnost: {bandwidth} kbps'\n      Player Dimensions: 'Veličina playera: {width}x{height}'\n      Buffered: 'Učitano: {bufferedPercentage}%'\n    You appear to be offline: Čini se da ne postoji veza s internetom.\n    Skipped segment: Preskočen segment „{segmentCategory}”\n    Take Screenshot: Snimi snimku ekrana\n    Show Stats: Prikaži statistiku\n    Hide Stats: Sakrij statistiku\n    Playback will resume automatically when your connection comes back: Reprodukcija će se automatski nastaviti nakon što se veza ponovo uspostavi.\n    TranslatedCaptionTemplate: '{language} (izvorni jezik prijevoda: {originalLanguage})'\n    Exit Full Window: Zatvori cjeloekranski prikaz\n    Theatre Mode: Kinematografski modus\n    Audio Tracks: Audio snimke\n    Exit Theatre Mode: Zatvori kinematografski modus\n    Full Window: Cjeloekranski prikaz\n    Autoplay is off: Automatska reprodukcija je isključena\n    Autoplay is on: Automatska reprodukcija je uključena\n  MembersOnly: Videa koja su namijenjena samo za članove ne mogu se gledati putem FreeTubea jer zahtijevaju prijavu na Google i plaćeno članstvo na kanalu prenositelja.\n  Unlisted: Skriveni za javnost\n  IP block: YouTube je blokirao tvoju IP adresu za gledanje videa. Pokušaj se prebaciti na jedan drugi VPN ili proxy.\n  AgeRestricted: Videa s dobnim ograničenjem se ne mogu gledati s FreeTubeom jer zahtijevaju prijavu na Google i korištenje YouTube računa s dobnom provjerom.\n  DeArrow:\n    Show Original Details: Prikaži detalje originala\n    Show Modified Details: Prikaži detalje promjena\n  DRMProtected: DRM-om zaštićena videa ne mogu se reproducirati u FreeTubeu jer zahtijevaju vlasničke komponente zatvorenog koda. Ako želiš gledati ovaj video, gledaj ga na službenoj YouTube web stranici u web pregledniku s aktiviranim DRM-om.\n#& Playlists\n  Watched Progress Saved: Napredak gledanja spremljen\n  Save Watched Progress: Spremi napredak gledanja\n  Popout Live Chat: Skočni prozor za razgovor uživo\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Oglas završava za: {remindingTimeSeconds} s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Preostalo vrijeme prije ponovnog pokušaja: {remindingTimeSeconds} s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Pogledaj cijelu zbirku'\n  Last Updated On: 'Zadnje aktualiziranje'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Zbirka\n  Sort By:\n    DateAddedNewest: Datum dodavanja (najnoviji)\n    DateAddedOldest: Datum dodavanja (najstariji)\n    AuthorAscending: Autor (A-Z)\n    AuthorDescending: Autor (Z-A)\n    VideoTitleAscending: Naslov (A-Z)\n    VideoTitleDescending: Naslov (Z-A)\n    Custom: Prilagođeno\n    VideoDurationDescending: Trajanje (najduže)\n    VideoDurationAscending: Trajanje (najkraće)\n    PublishedNewest: Datum objavljivanja (najnoviji)\n    PublishedOldest: Datum objavljivanja (najstariji)\nChange Format:\n  Change Media Formats: 'Promijeni videoformate'\n  Use Dash Formats: 'Koristi DASH formate'\n  Use Legacy Formats: 'Koristi stare formate'\n  Use Audio Formats: 'Koristi audioformate'\n  Audio formats are not available for this video: Audioformati nisu dostupni za ovaj video\n  Dash formats are not available for this video: DASH formati nisu dostupni za ovaj video\n  Legacy formats are not available for this video: Stari formati nisu dostupni za ovaj video\nShare:\n  Share Video: 'Dijeli video'\n  Share Playlist: 'Dijeli zbirku'\n  Copy Link: 'Kopiraj poveznicu'\n  Open Link: 'Otvori poveznicu'\n  Copy Embed: 'Kopiraj ugrađenu verziju'\n  Open Embed: 'Otvori ugrađenu verziju'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL je kopiran u međuspremnik'\n  Invidious Embed URL copied to clipboard: 'URL ugrađene Invidious verzije kopiran je u međuspremnik'\n  YouTube URL copied to clipboard: 'YouTube URL je kopiran u međuspremnik'\n  YouTube Embed URL copied to clipboard: 'URL ugrađene YouTube verzije kopiran je u međuspremnik'\n  Include Timestamp: Uključi vremensku oznaku\n  YouTube Channel URL copied to clipboard: 'URL YouTube kanala kopiran je u međuspremnik'\n  Invidious Channel URL copied to clipboard: 'URL Invidious kanala kopiran je u međuspremnik'\n  Share Channel: Dijeli kanal\n  Share Post: Dijeli objavu\nMini Player: 'Mali player'\nComments:\n  Comments: 'Komentari'\n  Click to View Comments: 'Pritisni za prikaz komentara'\n  Getting comment replies, please wait: 'Preuzimaju se odgovori na komentare. Pričekaj'\n  Hide Comments: 'Sakrij komentare'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Za ovaj video nema komentara'\n  Load More Comments: 'Učitaj još komentara'\n  There are no more comments for this video: Nema daljnjih komentara za ovaj video\n  Newest first: Najprije najnovije\n  Top comments: Najpopularniji komentari\n  Show More Replies: Prikaži više odgovora\n  Pinned by: Prikvačio/la\n  Member: Član\n  Hearted: Omiljeno\n  View {replyCount} replies: Pogledaj 1 odgovor | Pogledaj {replyCount} odgovora\n  Subscribed: Pretplaćeno\n  There are no comments available for this post: Za ovaj post nema komentara\n  Hide {replyCount} replies: Sakrij 1 odgovor | Sakrij {replyCount} odgovora\n  View 1 reply from {channelName}: Pogledaj 1 odgovor od {channelName}\n  View {replyCount} replies from {channelName} and others: Pogledaj {replyCount} odgovora od {channelName} i drugih\nUp Next: 'Sljedeći'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Greška lokalnog sučelja (pritisni za kopiranje)'\nInvidious API Error (Click to copy): 'Greška Invidious sučelja (pritisni za kopiranje)'\nFalling back to Invidious API: 'Koristit će se Invidious sučelje'\nFalling back to Local API: 'Koristit će se lokalno sučelje'\nLoop is now disabled: 'Ponavljanje je sada deaktivirano'\nLoop is now enabled: 'Ponavljanje je sada aktivirano'\nShuffle is now disabled: 'Slučajni redoslijed je sada deaktiviran'\nShuffle is now enabled: 'Slučajni redoslijed je sada aktiviran'\nPlaying Next Video: 'Reprodukcija sljedećeg videa'\nPlaying Previous Video: 'Reprodukcija prethodnog videa'\nCanceled next video autoplay: 'Automatska reprodukcija sljedećeg videa je prekinuta'\n'The playlist has ended. Enable loop to continue playing': 'Dosegnut je kraj zbirke. Aktiviraj ponavljanje za nastavljanje reprodukcije'\n\nYes: 'Da'\nNo: 'Ne'\nThe playlist has been reversed: Redoslijed zbirke je obrnut\nA new blog is now available, {blogTitle}. Click to view more: Dostupan je novi blog, {blogTitle}. Pritisni za prikaz detalja\nDownload From Site: Preuzmi s web-stranice\nVersion {versionNumber} is now available!  Click for more details: Dostupna je verzija {versionNumber}! Pritisni za prikaz detalja\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Ovaj video nije dostupan zbog nedostajućih formata. Uzrok tome može biti nedostupnost u zemlji.\nTooltips:\n  Player Settings:\n    Default Video Format: Postavi formate za reprodukciju videa. DASH formati mogu reproducirati višu kvalitetu slike. Stari formati su ograničeni na 360 p, ali su zato brži. Audioformati sadrže samo prijenose audiosnimaka.\n    Proxy Videos Through Invidious: Za reprodukciju videa povezat će se s Invidiousom umjesto izravnog povezivanja s YouTubeom.\n    Scroll Playback Rate Over Video Player: Dok se pokazivač nalazi na videu, pritisni i drži tipku Control (Command tipka na Macu) i pomiči kotačić miša naprijed ili natrag za upravljanje brzine reprodukcije. Pritisni i drži tipku Control (Command tipka na Macu) i pritisni lijevom tipkom miša za brzo vraćanje na standardnu brzinu reprodukcije (jednostruka brzina, ukoliko nije promijenjena u postavkama).\n    Skip by Scrolling Over Video Player: Koristi kotačić za pregledavanje videa, MPV stil.\n  General Settings:\n    Invidious Instance: Invidious primjerak na koji će se FreeTube povezati za pozive API-a.\n    Thumbnail Preference: U FreeTubeu će se sve minijature zamijeniti s jednim kadrom videa – zamućeno ili skriveno – umjesto standardne minijature.\n    Fallback to Non-Preferred Backend on Failure: Ako primarno odabrano sučelje ima problema, FreeTube će automatski pokušati koristiti sekundarno sučelje kao zamjensku metodu, ako je aktivirano.\n    Preferred API Backend: Odaberi pozadinski sustav koji FreeTube koristi za dobivanje podataka. Lokalno sučelje je ugrađeni sustav. Invidious sučelje zahtijeva Invidious poslužitelja na koji će se povezati.\n    Region for Trending: 'Regija trendova omogućuje biranje prikaza videa u trendu za određenu zemlju.'\n    External Link Handling: \"Odaberi standardno ponašanje kad se pritisne poveznica koja se ne može otvoriti u FreeTubeu.\\nFreeTube takve poveznice otvara u tvom standardnom pregledniku.\\n\"\n    Open Deep Links In New Window: URL adrese koje su proslijeđene na FreeTube, kao što su proširenja preglednika za preusmjeravanje ili argumenti naredbenog retka, otvaraju se u novom prozoru.\n  Subscription Settings:\n    Fetch Feeds from RSS: Kada je aktivirano, FreeTube će koristiti RSS umjesto vlastite standardne metode za dohvaćanje podataka tvoje pretplate. RSS je brži i sprečava blokiranje IP adresa, ali ne pruža određene podatke kao što su trajanje videa, stanje „uživo” ili postovi\n    Fetch Automatically: Kada je aktivirano, FreeTube će automatski dohvatiti feed tvoje pretplate pri pokretanju programa i kada se otvori novi prozor.\n  External Player Settings:\n    External Player: Biranjem eksternog playera prikazat će se ikona, za otvaranje videa (zbirka, ako je podržana) u vanjskom playeru, na minijaturi. Upozorenje, Invidious postavke ne utječu na eksterne playere.\n    Custom External Player Arguments: Svi prilagođeni argumenti naredbenog retka, koje želiš da se proslijede eksternom playeru.\n    Ignore Warnings: Nemoj prikazati upozorenja kad trenutačni eksterni player ne podržava trenutačnu radnju (npr. preokretanje redoslijeda zbirke itd.).\n    Custom External Player Executable: Prema standardnim postavkama, FreeTube će pretpostaviti da se odabrani eksterni player može pronaći putem varijable okruženja PATH (putanja). Ako je potrebno, ovdje se može postaviti prilagođena putanja.\n    DefaultCustomArgumentsTemplate: '(Standardno: „{defaultCustomArguments}”)'\n    Ignore Default Arguments: Ne šalji bilo koje standardne argumente eksternom playeru osim URL-a videa (npr. brzina reprodukcije, URL zbirke itd.). Prilagođeni argumenti će se i dalje prosljediti.\n  Experimental Settings:\n    Replace HTTP Cache: Deaktivira Electronovu HTTP predmemoriju temeljenu na disku i aktivira prilagođenu predmemoriju slika u memoriji. Povećava korištenje RAM-a.\n  Distraction Free Settings:\n    Hide Channels: Upiši ID kanala za skrivanje svih videa, zbirki kao i samog kanala u prikazu pretrage, trendova, najpopularniji i preporučeni. Upisani ID kanala se mora potpuno poklapati i razlikuje velika i mala slova.\n    Hide Subscriptions Live: Ovu postavku nadjačava programska postavka „{appWideSetting}”, u odjeljku „{subsection}” u „{settingsSection}”\n    Hide Videos, Playlists and Channels Containing Text: Upiši riječ, fragment riječi ili izraz (ne razlikuje velika i mala slova) za skrivanje svih videa i zbirki s tim sadržajem u njihovim izvornim naslovima u cijelom FreeTubeu, isključujući samo povijest, tvoje zbirke i videa unutar zbirki.\n    Hide Videos on Watch: Skriva gledana videa s kartica „Videa”, „Kratka videa” i „Uživo” na stranicama „Pretplata” i „Kanal”. To ne utječe na karticu „Početna” na stranicama „Kanal”\n  SponsorBlock Settings:\n    UseDeArrowTitles: Zamijeni naslove videa koje su poslali korisnici s DeArrow naslovima.\n    UseDeArrowThumbnails: Zamijeni minijature videa s DeArrow minijaturama.\nPlaying Next Video Interval: Trenutna reprodukcija sljedećeg videa. Pritisni za prekid. | Reprodukcija sljedećeg videa za {nextVideoInterval} sekunde. Pritisni za prekid. | Reprodukcija sljedećeg videa za {nextVideoInterval} sekundi. Pritisni za prekid.\nMore: Još\nUnknown YouTube url type, cannot be opened in app: Nepoznata vrsta URL adrese na YouTubeu, ne može se otvoriti u programu\nOpen New Window: Otvori novi prozor\nDefault Invidious instance has been cleared: Standardna Invidious instanca je izbrisana\nDefault Invidious instance has been set to {instance}: Standardna Invidious instanca je postavljena na {instance}\nExternal link opening has been disabled in the general settings: Otvaranje eksterne poveznice je deaktivirano u općim postavkama\nSearch Bar:\n  Clear Input: Izbriši unos\n  Remove: Ukloni\nAre you sure you want to open this link?: Stvarno želiš otvoriti ovu poveznicu?\nScreenshot Success: Snimka ekrana je spremljena\nScreenshot Error: Neuspjela snimka ekrana. {error}\nNew Window: Novi prozor\nChannels:\n  Channels: Kanali\n  Title: Popis kanala\n  Search bar placeholder: Pretraži kanale\n  Count: '{number} kanala pronađena.'\n  Empty: Tvoj popis kanala je trenutačno prazan.\n  Unsubscribe Prompt: Stvarno želiš prekinuti pretplatu na „{channelName}”?\nClipboard:\n  Copy failed: Neuspjelo kopiranje u međuspremnik\n  Cannot access clipboard without a secure connection: Pristup međuspremniku nije moguć bez sigurne veze\nChapters:\n  Chapters: Poglavlja\n  Key Moments: Ključni trenuci\nPreferences: Korisničke postavke\nOk: U redu\nHashtag:\n  This hashtag does not currently have any videos: Ovaj hashtag trenutačno nema videa\n  Hashtag: Hashtag\nGo to page: Idi na {page}\nChannel Hidden: '{channel} je dodan u filtar kanala'\nChannel Unhidden: '{channel} je uklonjen iz filtra kanala'\nTrimmed input must be at least N characters long: Skraćeni unos mora imati barem 1 znak | Skraćeni unos mora imati barem {length} znaka\nTag already exists: Oznaka „{tagName}” već postoji\nAge Restricted:\n  This channel is age restricted: Ovaj je dobno ograničeni kanal\n  This video is age restricted: Ovaj je dobno ograničeni video\nClose Banner: Zatvori natpis\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nFeed:\n  Feed Last Updated: 'Zadnje aktualiziranje feeda {feedName}: {date}'\n  Refresh Feed: Aktualiziraj {subscriptionName}\nMoments Ago: nedavno\nYes, Delete: Da, izbriši\nYes, Open Link: Da, otvori poveznicu\nCancel: Odustani\nYes, Restart: Da, pokreni ponovo\nSearch character limit: Upit za pretraživanje premašuje ograničenje od {searchCharacterLimit} znakova\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Titlovi\n    Closed Captions: Titlovi za gluhe\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Novi\n    3D: 3D\nRight-click or hold to see history: Pritisni desnu tipku miša ili zadrži za prikaz povijest\nDescription:\n  Expand Description: … više\n  Collapse Description: Prikaži manje\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Tipkovni prečaci\n  Close Window: Zatvori prozor\n  Toggle Developer Tools: Uključi/Isključi alate za programere\n  Volume Up: Povećaj glasnoću\n  Volume Down: Smanji glasnoću\n  History Backward: Idi jednu stranicu natrag\n  New Window: Stvori novi prozor\n  Show Keyboard Shortcuts: Prikaži tipkovne prečace\n  Focus Secondary Search: Fokusiraj sekundarnu traku pretrage (ako postoji)\n  Captions: Uključi/Isključi titlove\n  Stats: Prikaži statistiku videa\n  Navigate to Settings: Idi na stranicu „Postavke”\n  Navigate to History: Idi na stranicu „Povijest”\n  Refresh: Osvježi feed s najnovijim sadržajem\n  Picture in Picture: Uključi/Isključi modus „Slika u slici”\n  Play: Uključi/Isključi reprodukciju/pauza\n  Full Window: Uključi/Isključi prikaz u cijelom prozoru\n  Theatre Mode: Uključi/Isključi kinematografski modus\n  Take Screenshot: Snimi snimku ekrana\n  Minimize Window: Sklopi prozor\n  Focus Search: Fokusiraj traku pretrage\n  Search in New Window: Traži u novom prozoru\n  History Forward: Idi jednu stranicu naprijed\n  Last Chapter: Zadnje poglavlje\n  Next Chapter: Sljedeće poglavlje\n  Fullscreen: Uključi/Isključi cjeloekranski prikaz\n  Mute: Uključi/Isključi zvuk\n  Sections:\n    Video:\n      General: 'Video: Općenito'\n      Playback: 'Video: Reprodukcija'\n    App:\n      Situational: 'Program: Situacijski'\n      General: 'Program: Opće'\n  Reset Zoom: Resetiraj razinu zumiranja / veličinu korisničkog sučelja\n  Zoom In: Uvećaj prikaz\n  Last Frame: Prethodni kadar (prilikom pauze)\n  Next Frame: Sljedeći kadar (prilikom pauze)\n  Zoom Out: Umanji prikaz\n  Skip by Tenths: Postotno preskakanje kroz video (3 preskakanja do 30 % trajanja)\n  Decrease Video Speed: Smanji brzinu videa na temelju intervala brzine reprodukcije videa\n  Small Fast Forward: Premotaj X sekundi naprijed na temelju intervala premotavanja naprijed i trenutačne brzine reprodukcije videa\n  Small Rewind: Premotaj X sekundi natrag na temelju intervala premotavanja natrag i trenutačne brzine reprodukcije videa\n  Large Rewind: Premotaj 10 sekundi natrag / Premotaj video natrag na temelju trenutačne brzine reprodukcije videa\n  Large Fast Forward: Premotaj 10 sekundi naprijed / Premotaj video naprijed na temelju trenutačne brzine reprodukcije videa\n  Increase Video Speed: Povećaj brzinu videa na temelju intervala brzine reprodukcije videa\n  Home: Premotaj na početak videa\n  End: Premotaj na kraj videa\n  Skip to Next Video: Skoči na sljedeći video u zbirci ili na sljedeći preporučeni video\n  Skip to Previous Video: Skoči na prethodni video u zbirci\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Strelica dolje\n  arrowleft: Strelica lijevo\n  arrowright: Strelica desno\n  arrowup: Strelica gore\n  shift: Shift\n  enter: Enter\n  plus: Plus\nAutoplay Interruption Timer: Automatska reprodukcija je prekinuta zbog {autoplayInterruptionIntervalHours} sata neaktivnosti\nshortcutLabelSeparator: ｜\nCompact side navigation: Sažmi bočnu navigaciju\nExpand side navigation: Proširi bočnu navigaciju\n"
  },
  {
    "path": "static/locales/hu.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Magyar'\n\n# Webkit Menu Bar\nFile: 'Fájl'\nQuit: 'Kilépés'\nEdit: 'Szerkesztés'\nUndo: 'Visszavonás'\nRedo: 'Ismét'\nCut: 'Kivágás'\nCopy: 'Másolás'\nPaste: 'Beillesztés'\nDelete: 'Törlés'\nSelect all: 'Összes kiválasztása'\nToggle Developer Tools: 'Fejlesztői eszközök be-/kikapcsolása'\nActual size: 'Tényleges méret'\nZoom in: 'Nagyítás'\nZoom out: 'Kicsinyítés'\nToggle fullscreen: 'Teljes képernyős nézet be-/kikapcsolása'\nWindow: 'Ablak'\nMinimize: 'Kis méret'\nClose: 'Bezárás'\nBack: 'Vissza'\nForward: 'Előre'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videók'\n  Shorts: Rövidek\n  Live: Élő\n  Posts: Bejegyzések\n  Sort By: Rendezési szempont\n\n  Counts:\n    Video Count: 1 videó | {count} videó\n    Channel Count: 1 csatorna | {count} csatorna\n    Subscriber Count: 1 feliratkozó | {count} feliratkozó\n    View Count: 1 megtekintés | {count} megtekintés\n    Watching Count: 1 néző | {count} néző\n    Like Count: 1 embernek tetszik | {count} embernek tetszik\n    Comment Count: 1 hozzászólás | {count} hozzászólás\nVersion {versionNumber} is now available!  Click for more details: 'A(z) {versionNumber} verzió már elérhető! Kattintson a további részletekért'\nDownload From Site: 'Letöltés a webhelyről'\nA new blog is now available, {blogTitle}. Click to view more: 'Egy új blog érhető el: {blogTitle}. Kattintson a további információk megtekintéséhez'\n\n# Search Bar\nSearch / Go to URL: 'Keresés / Ugrás webcímre'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Keresési szűrők'\n  Sort By:\n    Most Relevant: 'Legpontosabbak'\n    Rating: 'Értékelés'\n    Upload Date: 'Feltöltés dátuma'\n    View Count: 'Megtekintések száma'\n  Time:\n    Time: 'Időpont'\n    Any Time: 'Bármikor'\n    Last Hour: 'Elmúlt óra'\n    Today: 'Ma'\n    This Week: 'Ezen a héten'\n    This Month: 'Ebben a hónapban'\n    This Year: 'Idén'\n  Type:\n    Type: 'Típus'\n    All Types: 'Összes típus'\n    Videos: 'Videók'\n    Channels: 'Csatornák'\n    #& Playlists\n    Movies: Filmek\n  Duration:\n    Duration: 'Időtartam'\n    All Durations: 'Bármilyen időtartam'\n    Short (< 4 minutes): 'Rövid (kevesebb, mint 4 perc)'\n    Long (> 20 minutes): 'Hosszú (hosszabb, mint 20 perc)'\n  # On Search Page\n    Medium (4 - 20 minutes): Közepes (4-20 perc)\n  Search Results: 'Keresési eredmények'\n  Fetching results. Please wait: 'Eredmények lekérése. Kis türelmet kérünk'\n  Fetch more results: 'További eredmények lekérése'\n# Sidebar\n  There are no more results for this search: Nincs több találat erre a keresésre\n  Features:\n    HD: HD\n    Subtitles: Feliratok\n    Creative Commons: Creative Commons\n    3D: 3D\n    4K: 4K\n    Location: Helyszín\n    HDR: HDR\n    VR180: VR180\n    Features: Szolgáltatások\n    Live: Élő\n    360 Video: 360 videó\n  Clear Filters: Szűrők törlése\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Feliratkozások'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'A feliratkozások listája jelenleg üres. Ha importálni szeretné feliratkozásait, akkor lépjen az Adatok beállításaiba és válassza a feliratkozások importálása lehetőséget, vagy kereshet csatornákat és feliratkozhat rájuk.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Ez a profil nagyszámú feliratkozást tartalmaz. RSS kényszerítése a sebességkorlátozás elkerülésére\n  Load More Videos: További videók betöltése\n  Error Channels: Hibás csatornák\n  Disabled Automatic Fetching: Ön letiltotta a feliratkozások automatikus lekérdezését. Frissítse a feliratkozásokat, hogy itt láthassa őket.\n  Empty Channels: A feliratkozott csatornák jelenleg nem tartalmaznak videókat.\n  All Subscription Tabs Hidden: Az összes feliratkozási lap el van rejtve. Az itteni tartalom megtekintéséhez törölje néhány lap rejtését a(z) „{settingsSection}” „{subsection}” szakaszában.\n  Subscriptions Tabs: Feliratkozások lapok\n  Load More Posts: További bejegyzések betöltése\n  Empty Posts: A feliratkozott csatornáinak jelenleg nincsenek bejegyzései.\nTrending:\n  Trending: 'Felkapott'\n  Trending Tabs: Felkapott lapok\n  Gaming: Játék\n  Sports: Sportok\nMost Popular: 'Legnépszerűbb'\nPlaylists: 'Lejátszási listák'\nUser Playlists:\n  Your Playlists: 'Saját lejátszási listák'\n  Search bar placeholder: Lejátszási listák keresése\n  Empty Search Message: Ebben a lejátszási listában nincsenek olyan videók, amelyek megfelelnek a keresésnek\n  AddVideoPrompt:\n    Search in Playlists: Keresés a lejátszási listában\n    Save: Mentés\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"A videó(k) hozzá lettek adva 1 lejátszási listához | A videó(k) lettek adva {playlistCount} lejátszási listához\"\n      You haven't selected any playlist yet.: Még nem választott ki egyetlen lejátszási listát sem.\n    Select a playlist to add your N videos to: Válasszon ki egy lejátszási listát a videó hozzáadásához | Válasszon ki egy lejátszási listát a {videoCount} videó hozzáadásához\n    N playlists selected: '{playlistCount} kiválasztva'\n    Added {count} Times: Hozzáadva {count} Alkalommal\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} A videók hozzáadásra fognak kerülni'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Videó már hozzá lett adva'\n    Allow Adding Duplicate Video(s): Duplikált videó(k) hozzáadásának engedélyezése\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Nem voltak eltávolítható videók.\n      Video has been removed: A videó el lett távolítva\n      Playlist has been updated.: Lejátszási lista frissítve.\n      There was an issue with updating this playlist.: Volt egy probléma a lejátszási lista frissítésével.\n      This video cannot be moved up.: Ez a videó nem mozgatható feljebb.\n      This playlist is protected and cannot be removed.: Ez a lejátszási lista védett, és nem távolítható el.\n      Playlist {playlistName} has been deleted.: '{playlistName} lejátszási lista törölve.'\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Néhány videó a lejátszási listában még nem töltődött be. Kattintson ide a másoláshoz ennek ellenére.\n      This playlist does not exist: Ez a lejátszási lista nem létezik\n      Playlist name cannot be empty. Please input a name.: A lejátszási lista neve nem lehet üres. Adjon meg egy nevet.\n      There was a problem with removing this video: Probléma adódott a videó eltávolításával\n      \"{videoCount} video(s) have been removed\": 1 videó el lett távolítva | {videoCount} videó el lett távolítva\n      This video cannot be moved down.: Ez a videó nem mozgatható lejjebb.\n      This playlist is now used for quick bookmark: Ez a lejátszási lista most gyors könyvjelzőként van használva\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: A(z) {oldPlaylistName} helyett mostantól ez a lejátszási lista szolgál gyors könyvjelzőként. Kattintson ide a visszavonáshoz\n      Reverted to use {oldPlaylistName} for quick bookmark: Visszaállítva a(z) {oldPlaylistName} használatára a gyors könyvjelzőhöz\n      This playlist is already being used for quick bookmark.: Ez a lejátszási lista már használatban van mint gyors könyvjelző.\n      This playlist has a video with a duration error: Ez a lejátszási lista legalább egy olyan videót tartalmaz, amelynek nincs időtartama, ezért úgy lesz rendezve, mintha az időtartamuk nulla lenne.\n      Video has been removed. Click here to undo.: Videó eltávolítva. Kattintson ide a visszavonáshoz.\n    Search for Videos: Videók keresése\n  Are you sure you want to delete this playlist? This cannot be undone: Biztosan törölni szeretné ezt a lejátszási listát? Ezt nem lehet visszacsinálni.\n  Sort By:\n    LatestPlayedFirst: Lejátszás dátuma (legújabb)\n    EarliestCreatedFirst: Létrehozás dátuma (legrégebbi)\n    LatestCreatedFirst: Létrehozás dátuma (legújabb)\n    EarliestUpdatedFirst: Frissítés dátuma (legrégebbi)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Lejátszás dátuma (legrégebbi)\n    LatestUpdatedFirst: Frissítés dátuma (legújabb)\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Nincsenek lejátszási listái. Kattintson az új lejátszási lista létrehozása gombra egy új lejátszási lista létrehozásához.\n  Remove from Playlist: Eltávolítás a lejátszási listáról\n  Save Changes: Változtatások mentése\n  CreatePlaylistPrompt:\n    Create: Létrehozás\n    Toast:\n      There was an issue with creating the playlist.: Volt egy probléma a lejátszási lista létrehozásával.\n      Playlist {playlistName} has been successfully created.: A lejátszási lista {playlistName} sikeresen létrehozva.\n      There is already a playlist with this name. Please pick a different name.: Már van egy lejátszási lista ezzel a névvel. Válasszon egy másik nevet.\n    New Playlist Name: Új lejátszási lista neve\n  This playlist currently has no videos.: Ez a lejátszási lista jelenleg nem tartalmaz videókat.\n  Add to Playlist: Hozzáadás a lejátszási listához\n  Move Video Down: Videó lefelé mozgatása\n  Playlist Name: Lejátszási lista neve\n  Remove Watched Videos: Megtekintett videók eltávolítása\n  Move Video Up: Videó felfelé mozgatása\n  Cancel: Mégse\n  Delete Playlist: Lejátszási lista törlése\n  Create New Playlist: Új lejátszási lista létrehozása\n  Edit Playlist Info: Lejátszási lista adatainak szerkesztése\n  Copy Playlist: Lejátszási lista másolása\n  Playlist Description: Lejátszási lista leírása\n  Add to Favorites: Hozzáadás a(z) {playlistName} lejátszási listához\n  Remove from Favorites: Eltávolítás a(z) {playlistName} lejátszási listából\n  Enable Quick Bookmark With This Playlist: Gyors könyvjelző engedélyezése ezzel a lejátszási listával\n  Playlists with Matching Videos: Lejátszási listák a kapcsolódó videókkal\n  Cannot delete the quick bookmark target playlist.: Nem lehet törölni a gyors könyvjelző cél lejátszási listát.\n  Quick Bookmark Enabled: Gyors könyvjelző engedélyezve\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Biztosan eltávolít 1 duplikált videót ebből a lejátszási listából? Ez a művelet nem vonható vissza. | Biztosan eltávolít {playlistItemCount} duplikált videót ebből a lejátszási listából? Ez a művelet nem vonható vissza.\n  Remove Duplicate Videos: Duplikált videók eltávolítása\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Biztosan eltávolít 1 megtekintett videót ebből a lejátszási listából? Ez a művelet nem vonható vissza. | Biztosan eltávolít {playlistItemCount} megtekintett videót ebből a lejátszási listából? Ez a művelet nem vonható vissza.\n  Export Playlist: Ezen lejátszási lista exportálása\n  The playlist has been successfully exported: A lejátszási lista sikeresen exportálva lett\n  TotalTimePlaylist: 'Teljes időtartam: {duration}'\n  Export list of URLs: Webcímek listába történő exportálása\nHistory:\n  # On History Page\n  History: 'Előzmények'\n  Watch History: 'Korábbi megtekintések'\n  Your history list is currently empty.: 'Az előzmények listája jelenleg üres.'\n  Search bar placeholder: Keresés az előzmények között\n  Empty Search Message: Nincsenek olyan videók az előzmények között, amelyek megfelelnek a keresésnek\n  Case Sensitive Search: Kis- nagybetű érzéken keresés\n  DateNewestHistory: Megtekintés dátuma (legújabb)\n  DateOldestHistory: Megtekintés dátuma (legrégebbi)\nSettings:\n  # On Settings Page\n  Settings: 'Beállítások'\n  General Settings:\n    General Settings: 'Általános'\n    Check for Updates: 'Frissítések keresése'\n    Check for Latest Blog Posts: 'Legújabb blogbejegyzések keresése'\n    Fallback to Non-Preferred Backend on Failure: 'A nem előnyben részesített háttéralkalmazás visszatérése meghibásodás esetén'\n    Enable Search Suggestions: 'Keresési javaslatok engedélyezése'\n    Default Landing Page: 'Alapértelmezett kezdőlap'\n    Locale Preference: 'Területi beállítás'\n    Preferred API Backend:\n      Preferred API Backend: 'Előnyben részesített háttér API'\n      Local API: 'Helyi API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Videónézet típusa'\n      Grid: 'Rács'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Bélyegkép beállítása'\n      Default: 'Alapértelmezett'\n      Beginning: 'Eleje'\n      Middle: 'Középső'\n      End: 'Vég'\n      Hidden: Rejtett\n      Blur: Elhomályosítás\n    Region for Trending: 'Felkapottak régiója'\n        #! List countries\n    View all Invidious instance information: Az Invidious példányok listájának megtekintése\n    System Default: Rendszer alapértelmezett\n    Current Invidious Instance: Jelenlegi Invidious példány\n    Clear Default Instance: Alapértelmezett példány eltávolítása\n    Set Current Instance as Default: A jelenlegi példány beállítása alapértelmezettként\n    Current instance will be randomized on startup: Véletlenszerű jelenlegi példány használata indításkor\n    No default instance has been set: Az alapértelmezett példány nincs beállítva\n    The currently set default instance is {instance}: A jelenleg beállított alapértelmezett példány {instance}\n    External Link Handling:\n      No Action: Nincs művelet\n      Ask Before Opening Link: Kérdés hivatkozás megnyitása előtt\n      Open Link: Hivatkozás megnyitása\n      External Link Handling: Külső hivatkozás kezelése\n    Auto Load Next Page:\n      Label: Következő oldal automatikus betöltése\n      Tooltip: További oldalak és a hozzászólások automatikus betöltése.\n    Open Deep Links In New Window: A FreeTube-nak átadott webcímek megnyitása új ablakban\n    Minimize to system tray: Kicsinyítés a tálcára\n  Theme Settings:\n    Theme Settings: 'Téma'\n    Match Top Bar with Main Color: 'A felső sáv színe egyezzen meg a fő színnel'\n    Base Theme:\n      Base Theme: 'Alap téma'\n      Black: 'Fekete'\n      Dark: 'Sötét'\n      Light: 'Világos'\n      Dracula: 'Drakula'\n      System Default: Rendszer alapértelmezett\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pasztell rózsaszín\n      Hot Pink: Forró rózsaszín\n      Nordic: Skandináv\n      Solarized Light: Szolarizált világos\n      Solarized Dark: Szolarizált sötét\n      Gruvbox Light: Gruvbox világos\n      Gruvbox Dark: Gruvbox sötét\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Medium: Everforest közepes sötét\n      Everforest Light Hard: Everforest erős világos\n      Everforest Light Medium: Everforest közepes világos\n      Everforest Light Low: Everforest gyenge világos\n      Everforest Dark Hard: Everforest erős sötét\n      Everforest Dark Low: Everforest gyenge sötét\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Fő színtéma'\n      Red: 'Vörös'\n      Pink: 'Rózsaszín'\n      Purple: 'Lila'\n      Deep Purple: 'Mély-bíbor'\n      Indigo: 'Indigókék'\n      Blue: 'Kék'\n      Light Blue: 'Világoskék'\n      Cyan: 'Ciánkék'\n      Teal: 'Pávakék'\n      Green: 'Zöld'\n      Light Green: 'Világoszöld'\n      Lime: 'Citrom-zöld'\n      Yellow: 'Sárga'\n      Amber: 'Borostyán-sárga'\n      Orange: 'Narancssárga'\n      Deep Orange: 'Sötét narancssárga'\n      Dracula Cyan: 'Drakula ciánkék'\n      Dracula Green: 'Drakula zöld'\n      Dracula Orange: 'Drakula narancssárga'\n      Dracula Pink: 'Drakula rózsaszín'\n      Dracula Purple: 'Drakula lila'\n      Dracula Red: 'Drakula vörös'\n      Dracula Yellow: 'Drakula sárga'\n      Catppuccin Mocha Flamingo: Catppuccin Mocha flamingó\n      Catppuccin Mocha Mauve: Catppuccin Mocha mályva\n      Catppuccin Mocha Red: Catppuccin Mocha vörös\n      Catppuccin Mocha Green: Catppuccin Mocha zöld\n      Catppuccin Mocha Teal: Catppuccin Mocha pávakék\n      Catppuccin Mocha Sky: Catppuccin Mocha égszínkék\n      Catppuccin Mocha Sapphire: Catppuccin Mocha zafír\n      Catppuccin Mocha Pink: Catppuccin Mocha rózsaszín\n      Catppuccin Mocha Blue: Catppuccin Mocha kék\n      Catppuccin Mocha Lavender: Catppuccin Mocha levendula\n      Catppuccin Mocha Maroon: Catppuccin Mocha gesztenyebarna\n      Catppuccin Mocha Rosewater: Catppuccin Mocha rózsavíz\n      Catppuccin Mocha Peach: Catppuccin Mocha barackvirág\n      Catppuccin Mocha Yellow: Catppuccin Mocha sárga\n      Solarized Yellow: Szolarizált sárga\n      Solarized Orange: Szolarizált narancssárga\n      Solarized Red: Szolarizált vörös\n      Solarized Blue: Szolarizált kék\n      Solarized Cyan: Szolarizált ciánkék\n      Solarized Green: Szolarizált zöld\n      Solarized Magenta: Szolarizált magenta\n      Solarized Violet: Szolarizált ibolya\n      Gruvbox Dark Yellow: Gruvbox sötét sárga\n      Gruvbox Dark Blue: Gruvbox sötét kék\n      Gruvbox Dark Aqua: Gruvbox sötét vízkék\n      Gruvbox Dark Orange: Gruvbox sötét narancssárga\n      Gruvbox Light Red: Gruvbox világos piros\n      Gruvbox Light Blue: Gruvbox világos kék\n      Gruvbox Dark Green: Gruvbox sötét zöld\n      Gruvbox Dark Purple: Gruvbox sötét lila\n      Gruvbox Light Orange: Gruvbox világos narancssárga\n      Gruvbox Light Purple: Gruvbox világos lila\n      Catppuccin Frappe Pink: Catppuccin Frappe rózsaszín\n      Catppuccin Frappe Mauve: Catppuccin Frappe mályva\n      Catppuccin Frappe Rosewater: Catppuccin Frappe rózsavíz\n      Catppuccin Frappe Flamingo: Catppuccin Frappe flamingó\n      Catppuccin Frappe Red: Catppuccin Frappe piros\n      Catppuccin Frappe Maroon: Catppuccin Frappe gesztenyebarna\n      Catppuccin Frappe Peach: Catppuccin Frappe barackvirág\n      Catppuccin Frappe Yellow: Catppuccin Frappe sárga\n      Catppuccin Frappe Green: Catppuccin Frappe zöld\n      Catppuccin Frappe Teal: Catppuccin Frappe pávakék\n      Catppuccin Frappe Sky: Catppuccin Frappe égszínkék\n      Catppuccin Frappe Blue: Catppuccin Frappe kék\n      Catppuccin Frappe Lavender: Catppuccin Frappe levendula\n      Catppuccin Frappe Sapphire: Catppuccin Frappe zafírkék\n      Everforest Dark Orange: Everforest sötét narancssárga\n      Everforest Dark Green: Everforest sötét zöld\n      Everforest Dark Aqua: Everforest sötét vízkék\n      Everforest Dark Blue: Everforest sötét kék\n      Everforest Light Red: Everforest világos vörös\n      Everforest Light Orange: Everforest világos narancssárga\n      Everforest Light Yellow: Everforest világos sárga\n      Everforest Light Green: Everforest világos zöld\n      Everforest Light Blue: Everforest világos kék\n      Everforest Dark Red: Everforest sötét vörös\n      Everforest Dark Yellow: Everforest sötét sárga\n      Everforest Light Purple: Everforest világos lila\n      Everforest Dark Purple: Everforest sötét lila\n      Everforest Light Aqua: Everforest világos vízkék\n      Catppuccin Latte Mauve: Catppuccin Latte mályva\n      Catppuccin Latte Red: Catppuccin Latte piros\n    Secondary Color Theme: 'Másodlagos színtéma'\n        #* Main Color Theme\n    UI Scale: Felhasználói felület méretezése\n    Expand Side Bar by Default: Alapértelmezés szerinti oldalsáv megjelenítés\n    Disable Smooth Scrolling: Finom görgetés letiltása\n    Hide Side Bar Labels: Gombfeliratok elrejtése az oldalsávról\n    Hide FreeTube Header Logo: FreeTube logo elrejtése a fejlécből\n  Player Settings:\n    Player Settings: 'Lejátszó'\n    Play Next Video: 'Ajánlott videók automatikus lejátszása'\n    Turn on Subtitles by Default: 'Feliratok engedélyezése alapértelmezetten'\n    Autoplay Videos: 'Videók automatikus elindítása'\n    Proxy Videos Through Invidious: 'Videók közvetítése az Invidiouson keresztül'\n    Autoplay Playlists: 'Lejátszási lista az automatikus videólejátszáshoz'\n    Enable Theatre Mode by Default: 'A mozimód bekapcsolása alapértelmezetten'\n    Default Volume: 'Alapértelmezett hangerő'\n    Default Playback Rate: 'Alapértelmezett lejátszási sebesség'\n    Default Video Format:\n      Default Video Format: 'Alapértelmezett videóformátum'\n      Dash Formats: 'DASH (Dinamikus adaptív sávszélességű folyamatos átvitel HTTP-n keresztül) formátumok'\n      Legacy Formats: 'Örökölt formátumok'\n      Audio Formats: 'Hangformátumok'\n    Default Quality:\n      Default Quality: 'Alapértelmezett minőség'\n      Auto: 'Automatikus'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4K'\n      8k: '8K'\n    Next Video Interval: Automatikus lejátszás időköze\n    Scroll Volume Over Video Player: A hangerő szintjének szabályozása a videolejátszó feletti görgetéssel\n    Display Play Button In Video Player: Lejátszás gomb megjelenítése a videolejátszóban\n    Fast-Forward / Rewind Interval: Gyors előre- és visszatekerési időköz\n    Screenshot:\n      Ask Path: Rákérdezés a Mentési mappára\n      File Name Label: Fájlnévminta\n      Folder Label: Képernyőképek mappa\n      Folder Button: Mappa kiválasztása\n      Enable: Képernyőkép készítésének engedélyezése\n      Format Label: Képernyőkép formátuma\n      Error:\n        Forbidden Characters: Tiltott karakterek\n        Empty File Name: Üres fájlnév\n      File Name Tooltip: Az alábbi változókat használhatja. %Y 4-számjegyű év. %M 2-számjegyű hónap. %D 2-számjegyű nap. %H 2-számjegyű óra. %N 2-számjegyű perc. %S 2-számjegyű másodperc. %T 3-számjegyű ezredmásodperc. %s Videó másodperc. %t Videó 3-számjegyű ezredmásodperc. %i videóazonosító.\n      Quality Label: Képernyőkép minősége\n    Scroll Playback Rate Over Video Player: A lejátszás sebességét a videolejátszó feletti kerékkel szabályozhatja\n    Max Video Playback Rate: Legnagyobb videólejátszási sebesség\n    Video Playback Rate Interval: Videó lejátszási sebesség léptetési köze\n    Enter Fullscreen on Display Rotate: Belépés a teljes képernyős módba a kijelző elforgatásakor\n    Skip by Scrolling Over Video Player: Kihagyás a Videolejátszó felett görgetve\n    Autoplay Interruption Timer: Automatikus lejátszás megszakításának időköze\n    Default Viewing Mode:\n      Full Screen: Teljes képernyő\n      Theater: Szélesvásznú\n      Picture in Picture: Kép a képben\n      External Player: Külső lejátszó ({externalPlayerName})\n      Default Viewing Mode: Alapértelmezett nézetmód\n  Privacy Settings:\n    Privacy Settings: 'Adatvédelem'\n    Remember History: 'Megtekintési előzmények megjegyzése'\n    Save Watched Progress: 'Megtekintési előrehaladás mentése'\n    Clear Search Cache: 'Keresési gyorsítótár törlése'\n    Are you sure you want to clear out your search cache?: 'Biztosan törli a keresési gyorsítótárat?'\n    Search cache has been cleared: 'A keresési gyorsítótár törölve lett'\n    Remove Watch History: 'Megtekintési előzmények eltávolítása'\n    Are you sure you want to remove your entire watch history?: 'Biztosan eltávolítja az összes megtekintési előzményt?'\n    Watch history has been cleared: 'A megtekintési előzmények törölve lettek'\n    Remove All Subscriptions / Profiles: 'Összes feliratkozás és profil eltávolítása'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Biztosan eltávolítja az összes feliratkozást és profilt? Ez a művelet nem vonható vissza.'\n    Save Watched Videos With Last Viewed Playlist: Megtekintett videók mentése az utoljára megtekintett lejátszási listával\n    All playlists have been removed: Összes lejátszási lista eltávolítva\n    Remove All Playlists: Összes lejátszási lista eltávolítása\n    Are you sure you want to remove all your playlists?: Biztosan el akarja távolítani az összes lejátszási listáját?\n    Remember Search History: Keresési előzmények megjegyzése\n    Clear Search History and Cache: A keresési előzmények és a gyorsítótár törlése\n    Are you sure you want to clear out your search history and cache?: Biztosan törölni szeretné a keresési előzményeket és a gyorsítótárat?\n    Search history and cache have been cleared: A keresési előzmények és a gyorsítótár törölve\n    Watched Progress Saving Mode:\n      Modes:\n        Semi-auto: Félautomatikus\n        Auto: Automatikus\n        Never: Soha\n      Tooltip: Automatikus = Mentés minden videóoldal elhagyásakor, a videó befejezésekor és hiba esetén (pl. a megtekintési korlátozás és videólejátszási munkamenet lejártakor). Félautomata = Hasonló az automatikushoz, kivéve a videóoldal elhagyásakor, továbbá a videolejátszó alatt található „Megtekintett videó folyamatának mentése” nevű gomb segítségével saját kezűleg is menthető.\n  Subscription Settings:\n    Subscription Settings: 'Feliratkozás'\n    Fetch Feeds from RSS: 'RSS-hírcsatornák beolvasása'\n    Fetch Automatically: Hírcsatorna automatikus lekérdezése\n    Confirm Before Unsubscribing: Megerősítés kérése leiratkozáskor\n    'Limit the number of videos displayed for each channel': Az egyes csatornákon megjelenített videók számának korlátozása\n    To: 'Ennyire'\n  Data Settings:\n    Data Settings: 'Adat'\n    Select Export Type: 'Exportálási típus kiválasztása'\n    Import Subscriptions: 'Feliratkozások importálása'\n    Export Subscriptions: 'Feliratkozások exportálása'\n    Export FreeTube: 'FreeTube exportálása'\n    Export YouTube: 'YouTube exportálása'\n    Export NewPipe: 'NewPipe exportálása'\n    Import History: 'Előzmények importálása'\n    Export History: 'Előzmények exportálása'\n    Profile object has insufficient data, skipping item: 'A profilobjektum nem rendelkezik elegendő adattal, az elem kihagyása'\n    All subscriptions and profiles have been successfully imported: 'Az összes feliratkozás és a profil sikeresen importálva'\n    All subscriptions have been successfully imported: 'Az összes feliratkozás sikeresen importálva'\n    Invalid subscriptions file: 'Érvénytelen feliratkozási fájl'\n    Invalid history file: 'Érvénytelen előzményfájl'\n    Subscriptions have been successfully exported: 'Feliratkozások sikeresen exportálva'\n    History object has insufficient data, skipping item: 'Az előzményobjektum nem rendelkezik elegendő adattal, az elem kihagyása'\n    All watched history has been successfully imported: 'Az összes megtekintett előzmény sikeresen importálva'\n    All watched history has been successfully exported: 'Az összes megtekintett előzmény sikeresen exportálva'\n    Unable to read file: 'Nem lehet olvasni a fájlt'\n    Unable to write file: 'Nem lehet írni a fájlt'\n    Unknown data key: 'Ismeretlen adatkulcs'\n    How do I import my subscriptions?: 'Hogyan importálhatja a feliratkozásait?'\n    Manage Subscriptions: Feliratkozások kezelése\n    Playlist insufficient data: Nincs elegendő adat a(z) „{playlist}” lejátszási listához, elem kihagyása\n    Export Playlists: Lejátszási listák exportálása\n    Import Playlists: Lejátszási listák importálása\n    All playlists has been successfully exported: Az összes lejátszási lista exportálása sikeresen megtörtént\n    All playlists has been successfully imported: Az összes lejátszási lista importálása sikeresen megtörtént\n    Subscription File: Feliratkozás-fájl\n    History File: Előzményfájl\n    Playlist File: Lejátszási lista fájl\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Ez az opció az összes lejátszási lista videóit egyetlen, „Kedvencek” nevű lejátszási listába exportálja.\\nHogyan exportálhat és importálhat videókat lejátszási listákba a FreeTube régebbi verziója esetében:\\n1. Exportálja a lejátszási listáit, ezzel az opcióval bekacsolva.\\n2. Törölje az összes meglévő lejátszási listáját az Adatvédelmi beállítások alatt található Összes lejátszási lista eltávolítása opcióval.\\n3. Indítsa el a FreeTube régebbi verzióját, és importálja az exportált lejátszási listákat.\"\n      Label: Lejátszási listák exportálása régebbi FreeTube verziókhoz\n\n    Search history file: Keresési előzmények fájl\n    Search history: Keresési előzmények\n    Import search history: Keresési előzmények importálása\n    Export search history: Keresési előzmények exportálása\n    All search history has been successfully imported: Az összes keresési előzmény sikeresen importálva\n    All search history has been successfully exported: Az összes keresési előzmény sikeresen exportálva\n  Distraction Free Settings:\n    Hide Live Chat: Élő csevegés elrejtése\n    Hide Popular Videos: Népszerű videók elrejtése\n    Hide Trending Videos: Felkapott videók elrejtése\n    Hide Recommended Videos: Ajánlott videók elrejtése\n    Hide Comment Likes: Hozzászólás-kedvelések elrejtése\n    Hide Channel Subscribers: Csatorna-feliratkozók elrejtése\n    Hide Video Likes And Dislikes: Kedvelések és nemtetszések elrejtése a videóknál\n    Hide Video Views: Videónézettség elrejtése\n    Distraction Free Settings: Ne zavarjanak\n    Hide Active Subscriptions: Elérhető feliratkozások elrejtése\n    Hide Playlists: Lejátszási listák elrejtése\n    Hide Video Description: Videóleírás elrejtése\n    Hide Comments: Hozzászólások elrejtése\n    Hide Live Streams: Élő közvetítések elrejtése\n    Hide Sharing Actions: Megosztási műveletek elrejtése\n    Hide Videos on Watch: 'Videók elrejtése megtekintés után'\n    Hide Chapters: Fejezetek elrejtése\n    Hide Upcoming Premieres: Közelgő bemutatók elrejtése\n    Hide Channels: Videók elrejtése a csatornákból\n    Hide Channels Placeholder: Csatornaazonosító\n    Display Titles Without Excessive Capitalisation: Címek túlzott nagybetűs írás és írásjelek nélkül való megjelenítése\n    Hide Featured Channels: Kiemelt csatornák elrejtése\n    Hide Channel Playlists: „Lejátszási listák” csatornalap elrejtése\n    Hide Channel Shorts: „Rövidek” csatornalap elrejtése\n    Sections:\n      Side Bar: Oldalsáv\n      Channel Page: Csatornalap\n      Watch Page: Megtekintési lap\n      General: Általános\n      Subscriptions Page: Feliratkozások oldal\n    Hide Channel Podcasts: „Podcastok” csatornalap elrejtése\n    Hide Channel Releases: „Kiadások” csatornalap elrejtése\n    Hide Subscriptions Shorts: Feliratkozások rövid videóinak elrejtése\n    Hide Subscriptions Videos: Feliratkozási videók elrejtése\n    Hide Subscriptions Live: Élő feliratkozások elrejtése\n    Hide Profile Pictures in Comments: Profilképek elrejtése a hozzászólásokban\n    Hide Channels Invalid: Érvénytelen a megadott csatornaazonosító\n    Hide Channels Disabled Message: Egyes csatornákat letiltottak az azonosító miatt, és nem dolgozták fel őket. A funkció le van tiltva, amíg ezek az azonosítók nem frissülnek\n    Hide Channels Already Exists: Már létezik a csatornaazonosító\n    Hide Channels API Error: Hiba történt a megadott azonosítóval rendelkező felhasználó lekérésekor. Ellenőrizze még egyszer, hogy helyes-e az azonosító.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Szó, szótöredék, vagy kifejezés\n    Hide Videos, Playlists and Channels Containing Text: Szöveget tartalmazó videók és lejátszási listák elrejtése\n    Hide Channel Home: „Főoldal” csatornalap elrejtése\n    Show Added Items: Hozzáadott elemek megjelenítése\n    Hide Channel Courses: „Tanfolyamok” csatornalap elrejtése\n    Hide Channel Posts: „Bejegyzések” csatornalap elrejtése\n    Hide Subscriptions Posts: Feliratkozási bejegyzések elrejtése\n  The app needs to restart for changes to take effect. Restart and apply change?: Az alkalmazásnak újra kell indulnia, hogy a változtatások életbe lépjenek. Induljon újra és alkalmazza a módosítást?\n  Proxy Settings:\n    City: Helység\n    Region: Körzet\n    Country: Ország\n    Ip: IP-cím\n    Your Info: Saját adatok\n    Clicking on Test Proxy will send a request to: 'A Proxy tesztelés gombra kattintva kérést küld a következő címre'\n    Test Proxy: Proxy tesztelés\n    Proxy Port Number: Proxy port száma\n    Proxy Host: Proxy-kiszolgáló\n    Proxy Protocol: Proxy protokoll\n    Enable Tor / Proxy: Tor/Proxy engedélyezése\n    Proxy Settings: Proxy\n    Error getting network information. Is your proxy configured properly?: Hiba a hálózati adatok lekérésekor. Megfelelő a proxy beállítása?\n    Proxy Warning: A FreeTube nem rendelkezik beépített proxyval, de képes csatlakozni egy külső proxyhoz, például egy olyanhoz, amely az Ön gépén fut, mint a Tor, vagy egy külső proxyhoz, például egy SOCKS5 proxyhoz, amelyet egyes VPN-ek biztosítanak. Ha engedélyezve van, győződjön meg róla, hogy a proxy/Tor megfelelően van beállítva, különben a FreeTube nem fog tudni adatokat lekérni.\n    Proxy Username: Proxy felhasználónév\n    Proxy Password: Proxy jelszó\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Értesítés a szponzorált szakasz kihagyásáról\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'SponsorBlock API webcíme (Alapértelmezett: https://sponsor.ajay.app)'\n    Enable SponsorBlock: SponsorBlock engedélyezése\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Beállítás kihagyása\n      Auto Skip: Automatikus kihagyás\n      Show In Seek Bar: Megjelenítés a keresősávban\n      Do Nothing: Nincs művelet\n      Prompt To Skip: Kérdés kihagyáskor\n    Category Color: Kategória színe\n    UseDeArrowTitles: DeArrow-videocímek használata\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'DeArrow előnézet-előállító API webcíme (alapértelmezett: https://dearrow-thumb.ajay.app)'\n    UseDeArrowThumbnails: DeArrow használata bélyegképekhez\n  External Player Settings:\n    Ignore Unsupported Action Warnings: Nem támogatott műveletek figyelmeztetéseinek mellőzése\n    Custom External Player Arguments: Egyéni külső lejátszó argumentumok\n    Custom External Player Executable: Egyéni külső lejátszó végrehajthatója\n    External Player: Külső lejátszó\n    External Player Settings: Külső lejátszó\n    Players:\n      None:\n        Name: Nincs\n    Ignore Default Arguments: Alapértelmezett argumentumok mellőzése\n  Parental Control Settings:\n    Parental Control Settings: Szülői felügyelet\n    Show Family Friendly Only: Csak a családbarát videók megjelenítése\n    Hide Search Bar: Keresősáv elrejtése\n    Hide Unsubscribe Button: Leiratkozás gomb elrejtése\n    Hide Uploader on Watch page: Feltöltő nevének elrejtése a megtekintési lapról\n  Experimental Settings:\n    Replace HTTP Cache: HTTP-gyorsítótár cseréje\n    Experimental Settings: Kísérleti\n    Warning: Ezek a beállítások kísérleti jellegűek, összeomlást okozhatnak, ha engedélyezve vannak. Erősen ajánlott biztonsági mentéseket készíteni. Csak saját felelősségre használja!\n  Password Dialog:\n    Enter Password To Unlock: Jelszó megadása a beállítások feloldásához\n    Password: Jelszó\n  Password Settings:\n    Password Settings: Jelszó\n    Set Password To Prevent Access: Jelszó megadása a beállításokhoz való hozzáférés megakadályozásához\n    Set Password: Jelszó megadása\n    Remove Password: Jelszó eltávolítása\n  Sort Settings Sections (A-Z): Beállítások rendezése (A-Z)\n  Return to Settings Menu: Vissza a „Beállítások” menübe\n  SABR:\n    Label: SABR engedélyezése mint DASH-háttérprogram\n    Tooltip: A SABR lesz az egyetlen DASH-háttérprogram a jövőbeli kiadásokban, és nem lehet majd letiltani. Ez a kapcsoló arra az esetre szolgál, ha a korai megvalósítása helyrehozhatatlan problémákat okozna.\nAbout:\n  #On About page\n  About: 'Névjegy'\n  #& About\n  these people and projects: az alábbi emberek és projektek\n  Donate: Adományozás\n  Credits: Készítők\n  Translate: Fordítás\n  room rules: szobaszabályok\n  Chat on Matrix: Csevegés a Matrixon\n  Mastodon: Mastodon\n  Blog: Blog\n  Email: E-mail\n  Website: Honlap\n  Please check for duplicates before posting: Beküldés előtt ellenőrizze, nincs-e már azonos\n  GitHub issues: GitHub hibajegyek\n  Help: Súgó\n  GitHub releases: GitHub kiadások\n  Downloads / Changelog: Letöltések / Változáslista\n  FreeTube Wiki: FreeTube Wiki\n  Source code: Forráskód\n  Beta: Béta\n  FAQ: GYIK\n  Report a problem: Probléma jelentése\n  Discussions: Vitalapok\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licencelve a(z) {licenseLink} alatt\n  Please read the {roomRulesLink}: 'Olvassa el a következőt: {roomRulesLink}'\n  FreeTube is made possible by {creditsPageLink}: A FreeTube a {creditsPageLink} jóvoltából jöhetett létre\nProfile:\n  Profile Select: 'Profil kiválasztása'\n  All Channels: 'Összes csatorna'\n  Profile Manager: 'Profilkezelő'\n  Create New Profile: 'Új profil létrehozása'\n  Edit Profile: 'Profil szerkesztése'\n  Color Picker: 'Színválasztó'\n  Custom Color: 'Egyéni szín'\n  Profile Preview: 'Profil előnézet'\n  Create Profile: 'Profil létrehozása'\n  Update Profile: 'Profil frissítése'\n  Make Default Profile: 'Legyen alapértelmezett profil'\n  Delete Profile: 'Profil törlése'\n  Are you sure you want to delete this profile?: 'Biztosan törli ezt a profilt?'\n  All subscriptions will also be deleted.: 'Az összes feliratkozás is törlődik.'\n  Your profile name cannot be empty: 'A profil neve nem lehet üres'\n  Profile has been created: 'Profil létrehozva'\n  Profile has been updated: 'A profil frissült'\n  Your default profile has been set to {profile}: 'Az alapértelmezett profil a következőre lett beállítva: {profile}'\n  Removed {profile} from your profiles: 'A(z) {profile} nevű profilja el lett távolítva a profiljaiból'\n  Your default profile has been changed to your primary profile: 'Az alapértelmezett profil az elsődleges profilra változott'\n  '{profile} is now the active profile': 'A(z) {profile} most az aktív profil'\n  Subscription List: 'Feliratkozási lista'\n  Other Channels: 'Egyéb csatornák'\n  '{number} selected': '{number} kiválasztva'\n  Select All: 'Összes kiválasztása'\n  Select None: 'Kiválasztások megszüntetése'\n  Delete Selected: 'Kiválasztottak törlése'\n  Add Selected To Profile: 'Kiválasztottak hozzáadása a profilhoz'\n  No channel(s) have been selected: 'Nincs kiválasztva csatorna'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Ez az elsődleges profilja.    Biztosan törli a kiválasztott csatornákat?   Ugyanezek a csatornák törlődnek minden olyan profilból, amelyben megtalálhatók.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Biztosan törli a kiválasztott csatornákat? Ez nem törli a csatornát más profilokból.'\n#On Channel Page\n  Profile Filter: Profilszűrő\n  Profile Settings: Profil\n  Toggle Profile List: Profillista be-/kikapcsolása\n  Profile Name: Profilnév\n  Edit Profile Name: Profilnév szerkesztése\n  Create Profile Name: Profilnév létrehozása\n  Open Profile Dropdown: Profil legördülő menü megnyitása\n  Close Profile Dropdown: Profil legördülő menü bezárása\nChannel:\n  Subscribe: 'Feliratkozás'\n  Unsubscribe: 'Leiratkozás'\n  Channel has been removed from your subscriptions: 'A csatorna el lett távolítva a feliratkozásokból'\n  Removed subscription from {count} other channel(s): 'A feliratkozás el lett távolítva {count} másik csatornából'\n  Added channel to your subscriptions: 'Csatorna hozzáadva a feliratkozásaihoz'\n  Search Channel: 'Csatorna keresése'\n  Your search results have returned 0 results: 'Keresési eredmény: 0 találat'\n  Videos:\n    Videos: 'Videók'\n    This channel does not currently have any videos: 'Ebben a csatornában jelenleg nincsenek videók'\n    Sort Types:\n      Newest: 'Legújabb'\n      Oldest: 'Legrégebbi'\n      Most Popular: 'Legnépszerűbb'\n  Playlists:\n    Playlists: 'Lejátszási listák'\n    This channel does not currently have any playlists: 'Ennek a csatornának jelenleg nincsenek lejátszási listái'\n    Sort Types:\n      Last Video Added: 'Utolsó videó hozzáadva'\n      Newest: 'Legújabb'\n      Oldest: 'Legrégebbi'\n  About:\n    About: 'Névjegy'\n    Channel Description: 'Csatorna leírása'\n    Featured Channels: 'Kiemelt csatornák'\n    Location: Hely\n    Details: Részletek\n    Joined: Csatlakozott\n    Tags:\n      Tags: Címkék\n      Search for: „{tag}” címke keresése\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Ez a csatorna korhatáros, és jelenleg nem tekinthető meg a FreeTube alkalmazásban.\n  Channel Tabs: Csatornalapok\n  Live:\n    This channel does not currently have any live streams: Jelenleg nincs élő közvetítés ezen a csatornán\n    Live: Élő\n  Posts:\n    This channel currently does not have any posts: Ezen a csatornán jelenleg nincsenek bejegyzések\n    Reveal Answers: Válaszok felfedése\n    Hide Answers: Válaszok elrejtése\n    votes: '{votes} szavazat'\n    Video hidden by FreeTube: FreeTube által rejtett videó\n    View Full Post: Teljes bejegyzés megtekintése\n    Viewing Posts Only Supported By Invidious: A hozzászólások megtekintését csak az Invidious támogatja. Az Invidious nélkül is megtekintheti a csatornák közösségi fülét.\n  Shorts:\n    This channel does not currently have any shorts: Ezen a csatornán jelenleg nincsenek rövidek\n  This channel does not exist: Nem létezik ez a csatorna\n  This channel does not allow searching: Keresés nem engedélyezett ezen a csatornán\n  Releases:\n    Releases: Kiadások\n    This channel does not currently have any releases: Ennek a csatornának jelenleg nincsenek kiadásai\n  Podcasts:\n    Podcasts: Podcastok\n    This channel does not currently have any podcasts: Ez a csatorna jelenleg nem rendelkezik podcastokkal\n  Home:\n    View Playlist: Lejátszási listák megtekintése\n    Home: Főoldal\n  Courses:\n    This channel does not currently have any courses: Ezen a csatornán jelenleg nincsenek tanfolyamok\n    Courses: Tanfolyamok\nVideo:\n  Mark As Watched: 'Megjelölés megtekintettként'\n  Remove From History: 'Eltávolítás az előzményekből'\n  Video has been marked as watched: 'A videó megtekintettnek lett jelölve'\n  Video has been removed from your history: 'A videó el lett távolítva az előzményekből'\n  Open in YouTube: 'Megnyitás a YouTube-ban'\n  Copy YouTube Link: 'YouTube-hivatkozás másolása'\n  Open YouTube Embedded Player: 'YouTube beágyazott lejátszó megnyitása'\n  Copy YouTube Embedded Player Link: 'YouTube beágyazott lejátszói hivatkozás másolása'\n  Open in Invidious: 'Invidious megnyitása'\n  Copy Invidious Link: 'Invidious hivatkozás másolása'\n  Views: 'Megtekintés'\n  Loop Playlist: 'Lejátszási lista folyamatos lejátszása'\n  Shuffle Playlist: 'Véletlen sorrendű lejátszás'\n  Reverse Playlist: 'Fordított lejátszási lista'\n  Previous: 'Előző'\n  Next: 'Következő'\n  Watched: 'Megtekintett'\n  Autoplay: 'Automatikus lejátszás'\n  Starting soon, please refresh the page to check again: 'Hamarosan kezdődik, frissítse a lapot az ellenőrzéshez'\n  # As in a Live Video\n  Live: 'Élő'\n  Live Now: 'Élő most'\n  Live Chat: 'Élő csevegés'\n  Enable Live Chat: 'Élő csevegés engedélyezése'\n  Live Chat is currently not supported in this build.: 'Az élő csevegés jelenleg nem támogatott ebben a összeállításban.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Élő csevegés engedélyezve. A csevegőüzenetek itt jelennek meg, miután elküldték.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Az élő csevegést jelenleg nem támogatja az Invidious API. Közvetlen kapcsolat szükséges a YouTube-hoz.'\n  Published:\n    In less than a minute: Kevesebb, mint egy perce\n  Published on: 'Megjelent'\n#& Videos\n  Copy Invidious Channel Link: Invidious csatorna hivatkozása másolása\n  Copy YouTube Channel Link: YouTube-csatorna hivatkozás másolása\n  Open Channel in YouTube: Csatorna megnyitása a YouTube-on\n  Open Channel in Invidious: Csatorna megnyitása az Invidious oldalán\n  Started streaming on: Folyamatos átvitel indult\n  Streamed on: 'Közvetítve'\n  Video has been removed from your saved list: A videó el lett távolíva a mentett listáról\n  Video has been saved: A videó mentve\n  Save Video: Videó mentése\n  Sponsor Block category:\n    music offtopic: Témán kívüli zene\n    interaction: Interakció\n    self-promotion: Önreklámozás\n    outro: Utójáték\n    intro: Bevezető\n    sponsor: Szponzor\n    filler: Kitöltő\n    recap: Összegzés\n  External Player:\n    Unsupported Actions:\n      looping playlists: lejátszási lista folyamatos lejátszása\n      shuffling playlists: véletlen sorrendű lejátszási listák\n      reversing playlists: lejátszási listák visszafelé\n      opening specific video in a playlist (falling back to opening the video): adott videó megnyitása a lejátszási listában (visszatérve a videó megnyitására)\n      opening playlists: lejátszási listák megnyitása\n      setting a playback rate: lejátszási sebesség beállítása\n      starting video at offset: videó kezdésének eltolása\n    UnsupportedActionTemplate: 'A(z) {externalPlayer} külső lejátszó nem támogatja a következőt: {action}'\n    OpeningTemplate: A(z) {videoOrPlaylist} videó megnyitása a(z) {externalPlayer} külső lejátszóban…\n    playlist: lejátszási lista\n    video: videó\n    OpenInTemplate: 'Megnyitás itt: {externalPlayer}'\n  Premieres: Első előadások\n  Show Super Chat Comment: Super Chat hozzászólás megjelenítése\n  Scroll to Bottom: Görgetés legalulra\n  Upcoming: Közelgő\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Az élő csevegés nem érhető el ehhez az adatfolyamhoz. Lehet, hogy a feltöltő letiltotta.\n  Unhide Channel: Csatorna megjelenítése\n  Hide Channel: Csatorna elrejtése\n  More Options: További beállítások\n  Player:\n    Audio Tracks: Hangsávok\n    Exit Theatre Mode: Kilépés a szélesvásznú módból\n    Theatre Mode: Szélesvásznú mód\n    Full Window: Teljes ablak\n    Exit Full Window: Kilépés a teljes ablakból\n    Take Screenshot: Képernyőkép készítése\n    Hide Stats: Statisztika elrejtése\n    Stats:\n      Stats: Statisztikák\n      Video ID: 'Videó azonosító: {videoId}'\n      Media Formats: 'Média formátum: {formats}'\n      Player Dimensions: 'Lejátszó mérete: {width}x{height}'\n      Bitrate: 'Bitsebesség: {bitrate} kbps'\n      Volume: 'Hangerő: {volumePercentage}%'\n      Bandwidth: 'Sávszélesség: {bandwidth} kbps'\n      Buffered: 'Pufferolt: {bufferedPercentage}%'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Kodekek: {videoCodec} / {audioCodec}'\n      Dropped Frames / Total Frames: 'Kihagyott képkockák: {droppedFrames} / Összes képkocka: {totalFrames}'\n      Resolution: 'Felbontás: {width}x{height}{''@''}{frameRate}'\n      CodecsVideoAudio: 'Kodekek: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n    You appear to be offline: Úgy tűnik, hogy jelenleg nem kapcsolódsz a hálózathoz.\n    Skipped segment: Kihagyott {segmentCategory} szakasz\n    TranslatedCaptionTemplate: '{language} (fordítva erről: „{originalLanguage}”)'\n    Show Stats: Statisztika megjelenítése\n    Playback will resume automatically when your connection comes back: A lejátszás automatikusan folytatódik, amikor a kapcsolat helyreáll.\n    Autoplay is off: Az automatikus lejátszás ki van kapcsolva\n    Autoplay is on: Az automatikus lejátszás be van kapcsolva\n  IP block: A YouTube letiltotta az IP-címét a videók megtekintéséhez. Próbáljon meg másik VPN-re vagy proxyra váltani.\n  Unlisted: Listázatlan\n  AgeRestricted: A FreeTube-on nem lehet korhatáros videókat megtekinteni, mivel ezekhez Google-bejelentkezés és korhatár-ellenőrzött YouTube-fiók használata szükséges.\n  MembersOnly: A csak tagoknak szóló videók nem tekinthetők meg a FreeTube-on, mivel ezekhez Google-bejelentkezés és fizetett tagság szükséges a feltöltő csatornájához.\n  DeArrow:\n    Show Modified Details: Módosított részletek megjelenítése\n    Show Original Details: Eredeti részletek megjelenítése\n  DRMProtected: A DRM-védelemmel ellátott videók nem játszhatók le a FreeTube-ban, mivel ezekhez zárt forráskódú, tulajdonosi komponensekre van szükség. Ha meg szeretné nézni ezt a videót, akkor tekintse meg a YouTube hivatalos weboldalán egy DRM-képes böngészőben.\n#& Playlists\n  Save Watched Progress: Megtekintett videó folyamatának mentése\n  Watched Progress Saved: Megtekintett videó folyamata elmentve\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Hátralévő előzetes hirdetési idő: {remindingTimeSeconds} mp'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Hátralévő várakozási idő a SABR-re: {remindingTimeSeconds} mp'\n  Popout Live Chat: Felugró csevegés\nPlaylist:\n  #& About\n  View Full Playlist: 'Teljes lejátszási lista megtekintése'\n  Last Updated On: 'Utoljára frissítve'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lejátszási lista\n  Sort By:\n    DateAddedOldest: Hozzáadás dátuma (legrégebbi)\n    DateAddedNewest: Hozzáadás dátuma (legújabb)\n    AuthorAscending: Szerző szerint (A-Z)\n    AuthorDescending: Szerző szerint (Z-A)\n    VideoTitleAscending: Cím szerint (A-Z)\n    VideoTitleDescending: Cím szerint (Z-A)\n    Custom: Egyéni rendezés\n    VideoDurationAscending: Időtartam (legrövidebb)\n    VideoDurationDescending: Időtartam (leghosszabb)\n    PublishedNewest: Közzététel dátuma (legújabb)\n    PublishedOldest: Közzététel dátuma (legrégebbi)\nChange Format:\n  Change Media Formats: 'Videoformátumok módosítása'\n  Use Dash Formats: 'DASH (Dinamikus adaptív sávszélességű folyamatos átvitel HTTP-n keresztül) formátumok használata'\n  Use Legacy Formats: 'Örökölt formátumok használata'\n  Use Audio Formats: 'Hangformátumok használata'\n  Dash formats are not available for this video: 'DASH (Dinamikus adaptív sávszélességű folyamatos átvitel HTTP-n keresztül) formátumok nem állnak rendelkezésre ehhez a videóhoz'\n  Audio formats are not available for this video: 'Hangformátumok nem érhetők el ehhez a videóhoz'\n  Legacy formats are not available for this video: A régebbi formátumok nem állnak rendelkezésre ehhez a videóhoz\nShare:\n  Share Video: 'Videó megosztása'\n  Share Playlist: 'Lejátszási lista megosztása'\n  Include Timestamp: 'Időbélyeg beágyazása'\n  Copy Link: 'Hivatkozás másolása'\n  Open Link: 'Hivatkozás megnyitása'\n  Copy Embed: 'Beágyazás másolása'\n  Open Embed: 'Beágyazás megnyitása'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious webcím a vágólapra másolva'\n  Invidious Embed URL copied to clipboard: 'Invidious beágyazott webcím a vágólapra másolva'\n  YouTube URL copied to clipboard: 'YouTube-webcím a vágólapra másolva'\n  YouTube Embed URL copied to clipboard: 'YouTube beágyazott webcím a vágólapra másolva'\n  YouTube Channel URL copied to clipboard: YouTube-csatorna webcíme a vágólapra másolva\n  Invidious Channel URL copied to clipboard: Invidious csatornawebcím a vágólapra másolva\n  Share Channel: Csatorna megosztása\n  Share Post: Bejegyzés megosztása\nMini Player: 'Minilejátszó'\nComments:\n  Comments: 'Hozzászólások'\n  Click to View Comments: 'Hozzászólások megtekintése'\n  Getting comment replies, please wait: 'Hozzászólásra adott válaszok beolvasása. Kis türelmet kérünk'\n  There are no more comments for this video: 'Ehhez a videóhoz nincsenek további hozzászólások'\n  Hide Comments: 'Hozzászólások elrejtése'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Ehhez a videóhoz még nincsenek hozzászólások'\n  Load More Comments: 'További hozzászólások betöltése'\n  Newest first: Legújabb elöl\n  Top comments: Legnépszerűbb hozzászólások\n  Show More Replies: További válaszok megjelenítése\n  Pinned by: 'Kitűzve'\n  Member: Tag\n  View {replyCount} replies: '1 válasz megtekintése | {replyCount} válasz megtekintése'\n  Hearted: Kedvenc\n  Subscribed: Feliratkozott\n  There are no comments available for this post: Nincsenek hozzászólások ehhez a bejegyzéshez\n  Hide {replyCount} replies: 1 válasz elrejtése | {replyCount} válasz elrejtése\n  View 1 reply from {channelName}: 1 válasz megtekintése a(z) {channelName} csatornában\n  View {replyCount} replies from {channelName} and others: '{replyCount} válasz megtekintése a(z) {channelName} és egyéb csatornákban'\nUp Next: 'Következő'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Helyi API hiba (kattintson a másoláshoz)'\nInvidious API Error (Click to copy): 'Invidious API hiba (Kattintson a másoláshoz)'\nFalling back to Invidious API: 'Invidious API-ra visszatérve'\nFalling back to Local API: 'Helyi API-ra visszatérve'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Ez a videó hiányzó formátumok miatt nem érhető el. Ez az ország nem elérhetősége miatt következhet be.'\nLoop is now disabled: 'Folyamatos lejátszás letiltva'\nLoop is now enabled: 'Folyamatos lejátszás engedélyezve'\nShuffle is now disabled: 'Véletlen sorrendű lejátszás letiltva'\nShuffle is now enabled: 'Véletlen sorrendű lejátszás engedélyezve'\nThe playlist has been reversed: 'Lejátszási lista megfordítva'\nPlaying Next Video: 'Következő videó lejátszása'\nPlaying Previous Video: 'Előző videó lejátszása'\nCanceled next video autoplay: 'A következő videó automatikus lejátszásának megszakítása'\n'The playlist has ended. Enable loop to continue playing': 'A lejátszási lista véget ért. Engedélyezze a folyamatos lejátszást a lejátszás folytatásához'\n\nYes: 'Igen'\nNo: 'Nem'\nTooltips:\n  General Settings:\n    Preferred API Backend: Válassza ki a háttéralkalmazást, amelyet a FreeTube használ az adatok megszerzéséhez. A helyi API egy beépített kinyerő. Az Invidious API használatához Invidious-kiszolgáló szükséges.\n    Region for Trending: A felkapottak régiója lehetővé teszi a választást, hogy melyik ország felkapott videóit szeretné megtekinteni.\n    Invidious Instance: Invidious példány, amelyhez a FreeTube csatlakozni fog az API-hívásokhoz.\n    Thumbnail Preference: A FreeTube-on minden bélyegkép le lesz cserélve a videó egy képkockájára, amely elmosódott vagy elrejtett lesz az alapértelmezett bélyegkép helyett.\n    Fallback to Non-Preferred Backend on Failure: Amikor az előnyben részesített API-jával hiba merül fel, a FreeTube automatikusan megpróbálja a nem előnyben részesített API-t tartalékként használni, amikor engedélyezve van.\n    External Link Handling: \"Válassza ki az alapértelmezett viselkedést, amikor egy hivatkozásra kattint, amely nem nyitható meg FreeTube-ban.\\nA FreeTube alapértelmezés szerint megnyitja a kattintott hivatkozást az alapértelmezett böngészőben.\\n\"\n    Open Deep Links In New Window: A FreeTube-nak átadott webcímek, például a böngészőbővítmények vagy parancssori argumentumok átirányításával, új ablakban nyílnak meg.\n  Subscription Settings:\n    Fetch Feeds from RSS: Amikor engedélyezve van, a FreeTube az RSS-t fogja használni az alapértelmezett módszer helyett a feliratkozási hírfolyam lekérdezéséhez. Az RSS gyorsabb és megakadályozza az IP-tiltást, de nem tartalmaz bizonyos információkat, például a videó időtartamát, az élő állapotot vagy a bejegyzéseket\n    Fetch Automatically: Amikor engedélyezve van, a FreeTube új ablak megnyitásakor és az alkalmazás elindításakor automatikusan lekérdezi az feliratkozási hírfolyamot.\n  Player Settings:\n    Default Video Format: A videóhoz használt formátumok beállítása. A DASH-formátumok magasabb minőségű lejátszást tesznek lehetővé. A régebbi formátumok legfeljebb 360p felbontásúak, de kevesebb sávszélességet igényelnek. A hangformátumok kizárólag hangadatfolyamokat tartalmaznak.\n    Proxy Videos Through Invidious: Csatlakozik az Invidious szolgáltatáshoz, hogy videókat szolgáltasson, ahelyett, hogy közvetlen kapcsolatot létesítene a YouTube szolgáltatással.\n    Scroll Playback Rate Over Video Player: Amíg a kurzor a videó felett van, nyomja meg és tartsa lenyomva a Control billentyűt (Mac gépen a Command billentyű), és görgesse az egér görgőjét előre vagy hátra a lejátszási sebesség szabályozásához. Tartsa lenyomva a Control billentyűt (Mac gépen a Command billentyű), majd kattintson az egér bal gombjával az alapértelmezett lejátszási sebesség gyors visszatéréséhez (1x, hacsak nem módosították a beállításokban).\n    Skip by Scrolling Over Video Player: MPV módban a görgetőkerék használatával kihagyhatja a videót.\n  External Player Settings:\n    Custom External Player Executable: Alapértelmezés szerint a FreeTube feltételezi, hogy a kiválasztott külső lejátszó megtalálható a PATH (ÚTVONAL) környezeti változón keresztül. Szükség esetén itt egyéni útvonal állítható be.\n    Ignore Warnings: A figyelmeztetések mellőzése, amikor a jelenlegi külső lejátszó nem támogatja a jelenlegi műveletet (pl. lejátszási listák megfordítása stb.).\n    Custom External Player Arguments: A külső lejátszónak átadni kívánt egyéni parancssori argumentumok.\n    External Player: Külső lejátszó kiválasztása esetén megjelenik egy ikon a videó (lejátszási lista, ha támogatott) megnyitásához a külső lejátszóban, a bélyegképen. Figyelem! Az Invidious beállításai nincsenek hatással a külső lejátszókra.\n    DefaultCustomArgumentsTemplate: '(Alapértelmezett: „{defaultCustomArguments}”)'\n    Ignore Default Arguments: Ne küldjön semmilyen alapértelmezett argumentumot a külső lejátszónak a videó webcímén kívül (pl. lejátszási sebesség, lejátszási lista webcíme stb.). Az egyéni argumentumok továbbra is átadásra kerülnek.\n  Experimental Settings:\n    Replace HTTP Cache: Letiltja az Electron lemezalapú HTTP-gyorsítótárát, és engedélyezi az egyéni memórián belüli képgyorsítótárat. Megnövekedett RAM-használathoz vezet.\n  Distraction Free Settings:\n    Hide Channels: Adjon meg egy csatornaazonosítót, hogy elrejtse az összes videót, lejátszási listát és magát a csatornát a keresési eredményekből, a felkapottak közül, a legnépszerűbbekből és az ajánlottak közül. A megadott csatornaazonosítónak pontosan egyeznie kell, valamint kis- és nagybetűérzékeny.\n    Hide Subscriptions Live: Ezt a beállítást felülírja az alkalmazásszintű „{appWideSetting}” beállítás a(z) „{settingsSection}” „{subsection}” szakaszában\n    Hide Videos, Playlists and Channels Containing Text: Adjon meg egy szót, szótöredéket vagy kifejezést (nem érzékeny a nagy- és kisbetűkre), hogy elrejtse az összes olyan videót és lejátszási listát, amelynek eredeti címe tartalmazza ezt a szót vagy kifejezést a FreeTube egész területén, kivéve az előzményeket, a lejátszási listákat és a lejátszási listákon belüli videókat.\n    Hide Videos on Watch: Elrejti a megtekintett videókat a videók-, rövidek- és élő lapokról a feliratkozás- és a csatornaoldalon. Ez nem érinti a kezdőoldalon található csatornalapokat\n  SponsorBlock Settings:\n    UseDeArrowTitles: Cserélje le a videocímeket a DeArrow-ból, felhasználó által beküldött címekre.\n    UseDeArrowThumbnails: Videóbélyegkép cseréje DeArrow bélyegképpel.\nPlaying Next Video Interval: A következő videó lejátszása folyamatban van. Kattintson a megszakításhoz. | A következő videó lejátszása {nextVideoInterval} másodperc múlva. Kattintson a megszakításhoz. | A következő videó lejátszása {nextVideoInterval} másodperc múlva. Kattintson a megszakításhoz.\nMore: Több\nUnknown YouTube url type, cannot be opened in app: Ismeretlen YouTube-webcím, nem nyitható meg az alkalmazásban\nOpen New Window: Új ablak megnyitása\nDefault Invidious instance has been cleared: Alapértelmezett Invidious példány eltávolítva\nDefault Invidious instance has been set to {instance}: 'Alapértelmezett Invidious példány {instance} beállítva'\nSearch Bar:\n  Clear Input: Bemenet törlése\n  Remove: Eltávolítás\nExternal link opening has been disabled in the general settings: A külső hivatkozás megnyitása le van tiltva az általános beállításokban\nAre you sure you want to open this link?: Biztosan megnyitja ezt a hivatkozást?\nNew Window: Új ablak\nChannels:\n  Channels: Csatornák\n  Title: Csatornalista\n  Search bar placeholder: Csatornák keresése\n  Count: '{number} csatorna találat.'\n  Empty: A csatornalistája jelenleg üres.\n  Unsubscribe Prompt: Biztosan le szeretne iratkozni a(z) „{channelName}” csatornáról?\nScreenshot Success: Képernyőkép elmentve\nChapters:\n  Chapters: Fejezetek\n  Key Moments: Fontos pillanatok\nClipboard:\n  Cannot access clipboard without a secure connection: Biztonságos kapcsolat nélkül nem lehet hozzáférni a vágólaphoz\n  Copy failed: A vágólapra másolás nem sikerült\nScreenshot Error: Nem sikerült képernyőképet készíteni. {error}\nPreferences: Beállítások\nOk: OK\nHashtag:\n  Hashtag: Kettős kereszt\n  This hashtag does not currently have any videos: Ez a kettős kereszt jelenleg nem rendelkezik videókkal\nChannel Hidden: '{channel} hozzáadva a csatornaszűrőhöz'\nGo to page: Ugrás a(z) {page} oldalra\nChannel Unhidden: 'A(z) {channel} el lett távolítva a csatornaszűrőből'\nTrimmed input must be at least N characters long: A vágott bemenetnek legalább 1 karakter hosszúnak kell lennie | A vágott bemenetnek legalább {length} karakter hosszúnak kell lennie\nTag already exists: '„{tagName}” címke már létezik'\nClose Banner: Banner bezárása\nAge Restricted:\n  This channel is age restricted: Ez a csatorna korhatáros\n  This video is age restricted: Ez a videó korhatáros\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nFeed:\n  Feed Last Updated: '{feedName} frissítve: {date}'\n  Refresh Feed: '{subscriptionName} frissítése'\nMoments Ago: épp most\nCancel: Mégse\nYes, Delete: Igen, törlés\nYes, Restart: Igen, újraindítás\nYes, Open Link: Igen, hivatkozás megnyitása\nSearch character limit: A keresési lekérdezés túllépte a {searchCharacterLimit} karakterhatárt\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Feliratok\n    Closed Captions: Feliratok (effektek is)\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Új\n    3D: 3D\nKeys:\n  arrowup: Felfele nyíl\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Lefele nyíl\n  arrowleft: Balra nyíl\n  arrowright: Jobbra nyíl\n  enter: Enter\n  plus: Plusz\n  shift: Shift\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: Kattintson a jobb gombbal vagy tartsa lenyomva az előzmények megtekintéséhez\nAutoplay Interruption Timer: Az automatikus lejátszás {autoplayInterruptionIntervalHours} óra inaktivitás miatt meg lett szakítva\nDescription:\n  Collapse Description: Kevesebb megjelenítése\n  Expand Description: …továbbiak\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Billentyűkombinációk\n  Sections:\n    Video:\n      Playback: 'Videó: Lejátszás'\n      General: 'Videó: Általános'\n    App:\n      Situational: 'Alkalmazás: Helyzetfüggő'\n      General: 'Alkalmazás: Általános'\n  Show Keyboard Shortcuts: Billentyű-kombinációk megjelenítése\n  Take Screenshot: Képernyőkép készítése\n  History Forward: A következő oldalra lépés\n  New Window: Új ablak létrehozása\n  Navigate to Settings: Ugrás a „Beállítások” oldalra\n  Navigate to History: Ugrás az „Előzmények” oldalra\n  Focus Secondary Search: A másodlagos keresősávra fókuszálás (ha van ilyen)\n  Fullscreen: Teljes képernyő be/ki\n  Picture in Picture: Kép a képben mód be/ki\n  Play: Lejátszás / Szüneteltetés be/ki\n  Mute: Némítás be/ki\n  Decrease Video Speed: A videó lejátszási sebességének csökkentése a lejátszási sebesség időköze alapján\n  Increase Video Speed: A videó lejátszási sebességének növelése a lejátszási sebesség időköze alapján\n  Toggle Developer Tools: Fejlesztői eszközök be/ki\n  Zoom In: Nagyítás\n  Full Window: Teljes ablakmód be/ki\n  Theatre Mode: Szélesvásznú mód be/ki\n  Minimize Window: Ablak minimalizálása\n  Last Frame: Előző képkocka megjelenítése (szüneteltetés alatt)\n  Next Frame: Következő képkocka megjelenítése (szüneteltetés alatt)\n  Volume Up: Hangerő növelése\n  Volume Down: Hangerő csökkentése\n  Small Rewind: X másodperc visszatekerés a visszatekerési időköz és a jelenlegi videólejátszási sebesség alapján\n  Last Chapter: Utolsó fejezet\n  Next Chapter: Következő fejezet\n  Skip by Tenths: A videó pörgetése százalékosan (3 pörgetés = a videó teljes időtartamának 30%-a)\n  Focus Search: Fókuszálás a keresési sávra\n  History Backward: Visszalépés az előző oldalra\n  Reset Zoom: Nagyítási szint / UI-skála visszaállítása\n  Zoom Out: Kicsinyítés\n  Search in New Window: Keresés új ablakban\n  Stats: Videóstatisztikák megjelenítése\n  Small Fast Forward: X másodperc előretekerés az előretekerési időköz és a jelenlegi videólejátszási sebesség alapján\n  Large Fast Forward: Előretekerés 10 másodperccel / Gyors előretekerés a jelenlegi videólejátszási sebesség alapján\n  Refresh: A hírcsatorna frissítése a legújabb tartalommal\n  Captions: Feliratok be/ki\n  Large Rewind: Visszatekerés 10 másodperccel / Visszatekerés a jelenlegi videólejátszási sebesség alapján\n  Close Window: Ablak bezárása\n  Home: Keressen a videó elejére\n  End: Keressen a videó végére\n  Skip to Next Video: Ugrás a lejátszási lista következő videójára vagy a következő ajánlott videóra\n  Skip to Previous Video: Ugrás a lejátszási lista előző videójára\nshortcutLabelSeparator: ｜\nCompact side navigation: Kompakt oldalsó navigáció\nExpand side navigation: Oldalsó navigáció kibontása\n"
  },
  {
    "path": "static/locales/id.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Bahasa Indonesia'\n\n# Webkit Menu Bar\nFile: 'Berkas'\nQuit: 'Keluar'\nEdit: 'Sunting'\nUndo: 'Urungkan'\nRedo: 'Majukan'\nCut: 'Potong'\nCopy: 'Salin'\nPaste: 'Tempel'\nDelete: 'Hapus'\nSelect all: 'Pilih semua'\nToggle Developer Tools: 'Alat Pengembang'\nActual size: 'Ukuran sebenarnya'\nZoom in: 'Perbesar'\nZoom out: 'Perkecil'\nToggle fullscreen: 'Layar penuh'\nWindow: 'Jendela'\nMinimize: 'Minimalkan'\nClose: 'Tutup'\nBack: 'Kembali'\nForward: 'Maju'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video'\n\n  Counts:\n    Video Count: 1 video | {count} video\n    Subscriber Count: 1 subscriber | {count} subscriber\n    Channel Count: 1 kanal | {count} kanal\n    View Count: 1 ditonton | {count} ditonton\n    Watching Count: 1 sedang menonton | {count} sedang menonton\n    Comment Count: 1 komentar | {count} komentar\n    Like Count: 1 suka | {count} suka\n  Posts: Postingan\n  Live: Siaran Langsung\n  Shorts: Video Singkat\n  Sort By: Urut Menurut\nVersion {versionNumber} is now available!  Click for more details: 'Versi {versionNumber} sekarang tersedia!  Klik untuk detail lebih lanjut'\nDownload From Site: 'Unduh dari Situs'\nA new blog is now available, {blogTitle}. Click to view more: 'Pos blog baru tersedia, {blogTitle}. Klik untuk lihat lebih lanjut'\n\n# Search Bar\nSearch / Go to URL: 'Cari / Pergi ke URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filter Pencarian'\n  Sort By:\n    Most Relevant: 'Paling Relevan'\n    Rating: 'Peringkat'\n    Upload Date: 'Tanggal Diunggah'\n    View Count: 'Jumlah Tontonan'\n  Time:\n    Time: 'Durasi'\n    Any Time: 'Kapan Saja'\n    Last Hour: 'Sejam Terakhir'\n    Today: 'Hari ini'\n    This Week: 'Minggu ini'\n    This Month: 'Bulan ini'\n    This Year: 'Tahun ini'\n  Type:\n    Type: 'Tipe'\n    All Types: 'Semua Tipe'\n    Videos: 'Video'\n    Channels: 'Kanal'\n    #& Playlists\n    Movies: Film\n  Duration:\n    Duration: 'Durasi'\n    All Durations: 'Semua Durasi'\n    Short (< 4 minutes): 'Pendek (< 4 menit)'\n    Long (> 20 minutes): 'Panjang (> 20 menit)'\n  # On Search Page\n    Medium (4 - 20 minutes): Sedang (4 - 20 menit)\n  Search Results: 'Hasil Pencarian'\n  Fetching results. Please wait: 'Mengambil hasil. Silakan tunggu'\n  Fetch more results: 'Ambil lebih banyak hasil'\n# Sidebar\n  There are no more results for this search: Tidak ada hasil lagi untuk pencarian ini\n  Features:\n    Features: Fitur\n    Live: Langsung\n    HDR: HDR\n    HD: HD\n    Subtitles: Subtitel\n    4K: 4K\n    3D: 3D\n    360 Video: Video 360\n    Location: Lokasi\n    VR180: VR180\n    Creative Commons: Hak Cipta Creative Commons\n  Clear Filters: Bersihkan Filter\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Langganan'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Daftar Langganan Anda saat ini kosong. Jika Anda ingin mengimpor langganan Anda, bukalah Pengaturan Data dan pilih Impor Langganan atau Anda dapat mencari saluran dan berlangganan saluran tersebut.'\n  Load More Videos: Muat Lebih Banyak Video\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Profil ini berlangganan ke banyak kanal. Beralih ke RSS untuk menghindari pembatasan akses\n  Load More Posts: Muat Lebih Banyak Pos\n  Subscriptions Tabs: Tab Langganan\n  Empty Channels: Kanal langganan Anda belum mempunyai video apa pun.\n  Empty Posts: Kanal langganan Anda belum mempunyai pos apa pun.\n  Disabled Automatic Fetching: Anda telah mematikan pengambilan langganan otomatis. Muat ulang langganan untuk melihat mereka.\n  Error Channels: Kanal dengan Galat\n  All Subscription Tabs Hidden: Semua tab langganan disembunyikan. Untuk melihat konten di sini, harap tampilkan beberapa tab di bagian \"{subsection}\" di \"{settingsSection}\".\nTrending:\n  Trending: 'Sedang Tren'\n  Gaming: Bermain game\n  Trending Tabs: Tab Trending\n  Sports: Olahraga\nMost Popular: 'Paling Populer'\nPlaylists: 'Daftar Putar'\nUser Playlists:\n  Your Playlists: 'Daftar Putar Anda'\n  Search bar placeholder: Cari Daftar Putar\n  Empty Search Message: Tidak ada video dalam daftar putar ini yang sesuai dengan pencarian Anda\n  Remove from Favorites: Hapus dari {playlistName}\n  Move Video Up: Pindah Video Ke Atas\n  Remove from Playlist: Hapus dari Daftar Putar\n  Are you sure you want to delete this playlist? This cannot be undone: Apakah Anda yakin ingin menghapus daftar putar ini? Ini tidak dapat dikembalikan kembali.\n  Sort By:\n    NameDescending: Z-A\n    NameAscending: A-Z\n    LatestUpdatedFirst: Tanggal Diperbarui (Terbaru)\n    EarliestCreatedFirst: Tanggal Dibuat (Terlama)\n    EarliestUpdatedFirst: Tanggal Diperbarui (Terlama)\n    LatestPlayedFirst: Tanggal Diputar (Terbaru)\n    LatestCreatedFirst: Tanggal Dibuat (Terbaru)\n    EarliestPlayedFirst: Tanggal Diputar (Terlama)\n  CreatePlaylistPrompt:\n    Create: Buat\n    New Playlist Name: Nama Daftar Putar yang Baru\n    Toast:\n      Playlist {playlistName} has been successfully created.: Daftar putar {playlistName} berhasil dibuat.\n      There is already a playlist with this name. Please pick a different name.: Sudah ada daftar putar dengan nama ini. Silakan pilih nama lain.\n      There was an issue with creating the playlist.: Terjadi masalah saat membuat daftar putar.\n  Create New Playlist: Buat Daftar Putar yang Baru\n  Add to Playlist: Tambahkan ke Daftar Putar\n  Move Video Down: Pindah Video Ke Bawah\n  Playlist Name: Nama Daftar Putar\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: Video telah dihapus\n      There was a problem with removing this video: Ada masalah ketika menghapus video ini\n      There was an issue with updating this playlist.: Ada masalah ketika memperbarui daftar putar ini.\n      \"{videoCount} video(s) have been removed\": 1 video telah dihapus | {videoCount} video telah dihapus\n      Playlist has been updated.: Daftar putar telah diperbarui.\n      There were no videos to remove.: Tidak ada video untuk dihapus.\n      Playlist {playlistName} has been deleted.: Daftar putar {playlistName} telah dihapus.\n      Playlist name cannot be empty. Please input a name.: Nama daftar putar tidak dapat kosong. Silakan masukkan sebuah nama.\n      This playlist does not exist: Daftar putar ini tidak ada\n      This video cannot be moved up.: Video ini tidak dapat dipindahkan ke atas.\n      Reverted to use {oldPlaylistName} for quick bookmark: Dikembalikan untuk menggunakan {oldPlaylistName} untuk penanda cepat\n      This playlist is now used for quick bookmark: Daftar putar ini sekarang digunakan untuk penanda cepat\n      This playlist is protected and cannot be removed.: Daftar putar ini dilindungi dan tidak dapat dihapus.\n      Video has been removed. Click here to undo.: Video telah dihapus. Klik di sini untuk membatalkannya.\n      This playlist is already being used for quick bookmark.: Daftar putar ini sudah digunakan untuk penanda cepat.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Daftar putar ini sekarang digunakan untuk penanda cepat, bukan {oldPlaylistName}. Klik di sini untuk membatalkannya\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Beberapa video dalam daftar putar belum dimuat. Klik di sini untuk tetap menyalin.\n      This playlist has a video with a duration error: Daftar putar ini berisi sedikitnya satu video yang tidak memiliki durasi. Daftar putar ini akan diurutkan seolah-olah durasinya nol.\n      This video cannot be moved down.: Video ini tidak dapat dipindahkan ke bawah.\n    Search for Videos: Cari Video\n  AddVideoPrompt:\n    Toast:\n      You haven't selected any playlist yet.: Anda belum memilih daftar putar apa pun.\n      \"Video(s) added to {playlistCount} playlists\": \"Video ditambahkan ke 1 daftar putar | Video ditambahkan ke daftar putar {playlistCount}\"\n    N playlists selected: '{playlistCount} Dipilih'\n    Search in Playlists: Cari di Daftar Putar\n    Save: Simpan\n    Allow Adding Duplicate Video(s): Izinkan Penambahan Video Duplikat\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Video Sudah Ditambahkan'\n    Select a playlist to add your N videos to: Pilih daftar putar untuk menambahkan video Anda | Pilih daftar putar untuk menambahkan {videoCount} video Anda\n    Added {count} Times: Sudah Ditambahkan | Ditambahkan {count} Kali\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Video Akan Ditambahkan'\n  Playlists with Matching Videos: Daftar Putar dengan Video yang Sama\n  Add to Favorites: Tambahkan ke {playlistName}\n  Cancel: Batal\n  Save Changes: Simpan Perubahan\n  Edit Playlist Info: Sunting Informasi Daftar Putar\n  Copy Playlist: Salin Daftar Putar\n  Remove Watched Videos: Hapus Video yang Sudah Ditonton\n  Delete Playlist: Hapus Daftar Putar\n  Playlist Description: Deskripsi Daftar Putar\n  This playlist currently has no videos.: Daftar putar ini belum mempunyai video apa pun.\n  Export Playlist: Ekspor Daftar Putar Ini\n  The playlist has been successfully exported: Daftar putar berhasil diekspor\n  You have no playlists. Click on the create new playlist button to create a new one.: Anda tidak memiliki daftar putar. Klik tombol buat daftar putar baru untuk membuat daftar putar baru.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Apakah Anda yakin ingin menghapus 1 video duplikat dari daftar putar ini? Tindakan ini tidak dapat dibatalkan. | Apakah Anda yakin ingin menghapus {playlistItemCount} video duplikat dari daftar putar ini? Tindakan ini tidak dapat dibatalkan.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Apakah Anda yakin ingin menghapus 1 video yang telah ditonton dari daftar putar ini? Tindakan ini tidak dapat dibatalkan. | Apakah Anda yakin ingin menghapus {playlistItemCount} video yang telah ditonton dari daftar putar ini? Tindakan ini tidak dapat dibatalkan.\n  Cannot delete the quick bookmark target playlist.: Tidak dapat menghapus daftar putar target penanda cepat.\n  Quick Bookmark Enabled: Penanda Cepat Diaktifkan\n  Remove Duplicate Videos: Hapus Video Duplikat\n  Enable Quick Bookmark With This Playlist: Aktifkan Bookmark Cepat Dengan Daftar Putar Ini\n  TotalTimePlaylist: Total Waktu :{duration}\n  Export list of URLs: Ekspor daftar URL\nHistory:\n  # On History Page\n  History: 'Riwayat'\n  Watch History: 'Riwayat Tontonan'\n  Your history list is currently empty.: 'Daftar riwayat Anda kosong.'\n  Search bar placeholder: Cari di Riwayat\n  Empty Search Message: Tidak ada video dalam riwayat Anda yang cocok dengan pencarian Anda\n  Case Sensitive Search: Pencarian Peka Huruf Besar/Kecil\n  DateOldestHistory: Tanggal Ditonton (Terlama)\n  DateNewestHistory: Tanggal Ditonton (Terbaru)\nSettings:\n  # On Settings Page\n  Settings: 'Pengaturan'\n  General Settings:\n    General Settings: 'Umum'\n    Check for Updates: 'Cek Pembaruan'\n    Check for Latest Blog Posts: 'Cek Kiriman Blog Terbaru'\n    Fallback to Non-Preferred Backend on Failure: 'Beralih ke Layanan Cadangan saat terjadi Kegagalan'\n    Enable Search Suggestions: 'Aktifkan Saran Pencarian'\n    Default Landing Page: 'Halaman Awal Baku'\n    Locale Preference: 'Bahasa'\n    Preferred API Backend:\n      Preferred API Backend: 'Dukungan API yang Dipilih'\n      Local API: 'API Lokal'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Tipe Tampilan Video'\n      Grid: 'Kotak²'\n      List: 'Daftar'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferensi Thumbnail'\n      Default: 'Default'\n      Beginning: 'Awal'\n      Middle: 'Tengah'\n      End: 'Akhir'\n      Hidden: Tersembunyi\n      Blur: Buramkan\n    Region for Trending: 'Wilayah untuk Sedang Tren'\n        #! List countries\n    View all Invidious instance information: Tampilkan informasi semua peladen Invidious\n    System Default: Sistem standar\n    Current instance will be randomized on startup: Situs akan diacak saat aplikasi dijalankan\n    Current Invidious Instance: Situs Invidious Saat Ini\n    External Link Handling:\n      External Link Handling: Penanganan Tautan Eksternal\n      Open Link: Buka Tautan\n      Ask Before Opening Link: Tanya Sebelum Membuka Tautan\n      No Action: Tidak ada\n    The currently set default instance is {instance}: Instans default yang saat ini disetel adalah {instance}\n    No default instance has been set: Tidak ada instans default yang disetel\n    Set Current Instance as Default: Tetapkan Instans Saat Ini sebagai Default\n    Clear Default Instance: Hapus Peladen Baku\n    Auto Load Next Page:\n      Label: Otomatis Memuat Halaman Selanjutnya\n      Tooltip: Muat halaman dan komentar tambahan secara otomatis.\n    Open Deep Links In New Window: Buka URL yang Diteruskan ke FreeTube di Jendela Baru\n    Minimize to system tray: Minimalkan ke System Tray\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Samakan Bilah Atas dengan Warna Utama'\n    Base Theme:\n      Base Theme: 'Tema Dasar'\n      Black: 'Hitam'\n      Dark: 'Gelap'\n      Light: 'Terang'\n      Dracula: 'Drakula'\n      System Default: Bawaan sistem\n      Gruvbox Light: Gruvbox terang\n      Catppuccin Mocha: Catpucin Mocha\n      Gruvbox Dark: Gruvbox gelap\n      Pastel Pink: Pink Pastel\n      Nordic: Nordik\n      Solarized Dark: Solari Gelap\n      Catppuccin Frappe: Frappe Kue Kucing\n      Hot Pink: Pink Terang\n      Solarized Light: Solari Terang\n      Everforest Dark Hard: Everforest Gelap Keras\n      Everforest Dark Medium: Everforest Gelap Sedang\n      Everforest Dark Low: Everforest Gelap rendah\n      Everforest Light Hard: Everforest Ringan Keras\n      Everforest Light Medium: Everforest Ringan Sedang\n      Everforest Light Low: Everforest Cahaya rendah\n      Catppuccin Latte: Kopi Susu Latte\n    Main Color Theme:\n      Main Color Theme: 'Tema Warna Utama'\n      Red: 'Merah'\n      Pink: 'Merah Muda'\n      Purple: 'Ungu'\n      Deep Purple: 'Ungu Tua'\n      Indigo: 'Nila'\n      Blue: 'Biru'\n      Light Blue: 'Biru Muda'\n      Cyan: 'Sian'\n      Teal: 'biru kehijauan'\n      Green: 'Hijau'\n      Light Green: 'Hijau Muda'\n      Lime: 'Lime'\n      Yellow: 'Kuning'\n      Amber: 'Ambar'\n      Orange: 'Jingga'\n      Deep Orange: 'Jingga Tua'\n      Dracula Cyan: 'Dracula Sian'\n      Dracula Green: 'Dracula Hijau'\n      Dracula Orange: 'Dracula Jingga'\n      Dracula Pink: 'Dracula Merah Muda'\n      Dracula Purple: 'Dracula Ungu'\n      Dracula Red: 'Dracula Merah'\n      Dracula Yellow: 'Dracula Kuning'\n      Gruvbox Light Red: Gruvbox merah terang\n      Catppuccin Mocha Blue: Catppuccin Mocha Biru\n      Catppuccin Mocha Mauve: Catpucin Mocha Mauve\n      Gruvbox Light Blue: Gruvbox biru terang\n      Solarized Orange: Solari orange\n      Gruvbox Dark Blue: Gruvbox biru tua\n      Catppuccin Mocha Maroon: Catpucin Mocha Maroon\n      Catppuccin Mocha Flamingo: Catpuccin Mocha Flamingo\n      Catppuccin Mocha Pink: Catpucin Mocha Pink\n      Gruvbox Dark Orange: Gruvbox orange tua\n      Catppuccin Frappe Flamingo: Flamingo Cappuccin Frappe\n      Catppuccin Frappe Lavender: Catpucin Frappe Lavender\n      Gruvbox Dark Aqua: Gruvbox ungu tua\n      Catppuccin Mocha Sky: Catpucin Mocha Sky\n      Solarized Green: Solari hijau\n      Solarized Cyan: Solari Biru kehijauan\n      Catppuccin Mocha Peach: Catpuccin Mocha Peach\n      Catppuccin Mocha Yellow: Catpucin Mocha Kuning\n      Catppuccin Mocha Rosewater: Catpuccin Mocha Rosewater\n      Gruvbox Dark Yellow: Gruvbox Kuning Tua\n      Gruvbox Light Purple: Gruvbox ungu terang\n      Gruvbox Light Orange: Gruvbox orange terang\n      Solarized Magenta: Solari ungu\n      Solarized Yellow: Solari kuning\n      Catppuccin Mocha Lavender: Catpucin Mocha Lavender\n      Catppuccin Mocha Red: Catpucin Mocha Merah\n      Catppuccin Frappe Rosewater: Catpucin Frappe Air Mawar\n      Catppuccin Frappe Pink: Catpucin Frappe Merah Muda\n      Catppuccin Frappe Mauve: Frappe Kucing Ungu\n      Catppuccin Frappe Red: Catpucin Frappe Merah\n      Catppuccin Frappe Maroon: Catpucin Frappe Maroon\n      Catppuccin Frappe Peach: Catpucin Frappe Persik\n      Catppuccin Frappe Yellow: Catpuccin Frappe Kuning\n      Catppuccin Frappe Green: Catppuccin Frappe Hijau\n      Catppuccin Frappe Teal: Catpucin Frappe Teal\n      Catppuccin Frappe Sky: Catppuccin Frappe Langit\n      Catppuccin Frappe Sapphire: Catpucin Frappe Safir\n      Catppuccin Frappe Blue: Catpucin Frappe Biru\n      Catppuccin Mocha Green: Catpucin Mocha Hijau\n      Catppuccin Mocha Teal: Catpucin Mocha Teal\n      Gruvbox Dark Green: Gruvbox Hijau Gelap\n      Gruvbox Dark Purple: Gruvbox Ungu Tua\n      Solarized Red: Solari merah\n      Solarized Violet: Solari violet\n      Solarized Blue: Solari Biru\n      Catppuccin Mocha Sapphire: Catpucin Mocha Sapphire\n      Everforest Light Green: Everforest Hijau Muda\n      Everforest Dark Red: Everforest Merah Tua\n      Everforest Dark Orange: Everforest Jingga Tua\n      Everforest Dark Yellow: Everforest Kuning Tua\n      Everforest Dark Green: Everforest Hijau Tua\n      Everforest Dark Aqua: Everforest Aqua Gelap\n      Everforest Dark Blue: Everforest Biru tua\n      Everforest Dark Purple: Ungu Tua Everforest\n      Everforest Light Red: Everforest Merah Muda\n      Everforest Light Orange: Everforest Oranye Muda\n      Everforest Light Yellow: Everforest Kuning Muda\n      Everforest Light Aqua: Cahaya Everforest Aqua\n      Everforest Light Blue: Everforest Biru muda\n      Everforest Light Purple: Everforest Ungu Muda\n      Catppuccin Latte Mauve: Kopi Susu Latte Ungu Muda\n      Catppuccin Latte Red: Kopi Susu Latte Merah\n    Secondary Color Theme: 'Warna Tema Sekunder'\n        #* Main Color Theme\n    Expand Side Bar by Default: Perluas Bilah Samping\n    UI Scale: Skala UI\n    Disable Smooth Scrolling: Nonaktifkan Gulir Halus\n    Hide Side Bar Labels: Sembunyikan Label Bilah Samping\n    Hide FreeTube Header Logo: Sembunyikan Logo Header FreeTube\n  Player Settings:\n    Player Settings: 'Pemutar'\n    Play Next Video: 'Putar Otomatis Video Rekomendasi'\n    Turn on Subtitles by Default: 'Aktifkan Subtitel Secara Default'\n    Autoplay Videos: 'Mulai Video Secara Otomatis'\n    Proxy Videos Through Invidious: 'Proksi Video Lewat Invidious'\n    Autoplay Playlists: 'Putar Otomatis Daftar Video'\n    Enable Theatre Mode by Default: 'Aktifkan Mode Teater'\n    Default Volume: 'Volume Bawaan'\n    Default Playback Rate: 'Laju Pemutaran Bawaan'\n    Default Video Format:\n      Default Video Format: 'Format Video Bawaan'\n      Dash Formats: 'Format DASH'\n      Legacy Formats: 'Format Lama'\n      Audio Formats: 'Format Audio'\n    Default Quality:\n      Default Quality: 'Kualitas Bawaan'\n      Auto: 'Otomatis'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Penghitung Waktu Mundur Putar Otomatis\n    Display Play Button In Video Player: Tampilkan Tombol Putar di Dalam Pemutar Video\n    Scroll Volume Over Video Player: Gulir Volume di Atas Pemutar Video\n    Fast-Forward / Rewind Interval: Interval Fast-Forward / Rewind\n    Scroll Playback Rate Over Video Player: Scroll Tingkat Pemutaran Di Atas Pemutar Video\n    Max Video Playback Rate: Maks Laju Pemutaran Video\n    Video Playback Rate Interval: Interval Laju Pemutaran Video\n    Screenshot:\n      Folder Label: Folder Tangkapan Layar\n      Error:\n        Empty File Name: Nama Berkas Kosong\n        Forbidden Characters: Karakter Terlarang\n      Folder Button: Pilih Folder\n      Format Label: Format Tangkapan Layar\n      Enable: Aktifkan Tangkapan Layar\n      Ask Path: Tanya Lokasi Penyimpanan\n      Quality Label: Kualitas Tangkapan Layar\n      File Name Label: Pola Nama Berkas\n      File Name Tooltip: Anda dapat menggunakan variabel di bawah ini. %Y Tahun 4 digit. %M Bulan 2 digit. %D Hari 2 digit. %H Jam 2 digit. %N Menit 2 digit. %S Detik 2 digit. %T Milidetik 3 digit. %s Detik Video. %t Milidetik Video 3 digit. %i ID Video.\n    Enter Fullscreen on Display Rotate: Masuk ke Layar Penuh ketika Perangkat Diputar\n    Skip by Scrolling Over Video Player: Lewati dengan Menggulir Di Atas Pemutar Video\n    Default Viewing Mode:\n      Theater: Teater\n      Default Viewing Mode: Mode Tampilan Default\n      Full Screen: Layar Penuh\n      Picture in Picture: Gambar dalam Gambar\n      External Player: Pemain Eksternal ({externalPlayerName})\n    Autoplay Interruption Timer: Pengatur Waktu Interupsi Putar Otomatis\n  Privacy Settings:\n    Privacy Settings: 'Privasi'\n    Remember History: 'Ingat Riwayat Tontonan'\n    Save Watched Progress: 'Simpan Progres Tontonan'\n    Clear Search Cache: 'Hapus Cache Pencarian'\n    Are you sure you want to clear out your search cache?: 'Apakah Anda yakin ingin menghapus cache pencarian Anda?'\n    Search cache has been cleared: 'Cache pencarian telah dihapus'\n    Remove Watch History: 'Hapus Riwayat Tontonan'\n    Are you sure you want to remove your entire watch history?: 'Apakah Anda yakin ingin menghapus seluruh riwayat tontonan Anda?'\n    Watch history has been cleared: 'Riwayat tontonan telah dihapus'\n    Remove All Subscriptions / Profiles: 'Hapus Semua Langganan / Profil'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Apakah Anda yakin ingin menghapus semua langganan dan profil? Tindakan ini tidak bisa diurungkan.'\n    All playlists have been removed: Semua daftar putar telah dihapus\n    Remove All Playlists: Hapus Semua Daftar Putar\n    Are you sure you want to remove all your playlists?: Apakah Anda yakin ingin menghapus semua daftar putar Anda?\n    Remember Search History: Ingat Riwayat pencarian\n    Save Watched Videos With Last Viewed Playlist: Simpan Video yang Ditonton Dengan Daftar Putar Terakhir Ditonton\n    Clear Search History and Cache: Hapus Riwayat Pencarian dan Cache\n    Are you sure you want to clear out your search history and cache?: Apakah Anda yakin ingin menghapus riwayat pencarian dan cache?\n    Search history and cache have been cleared: Riwayat pencarian dan cache telah dihapus\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Otomatis\n        Semi-auto: Semi Otomatis\n        Never: Tidak Pernah\n      Tooltip: Otomatis = Simpan pada setiap kali keluar dari laman video, selesai menonton video dan saat terjadi error (e.g. rate-limit dan watch session expired). Semi otomatis = Seperti mode Otomatis, kecuali hanya pada saat keluar dari laman video dan dapat menyimpan progres secara manual dengan mengklik tombol Simpan Progres Tontonan, terletak di bawah pemutar video.\n  Subscription Settings:\n    Subscription Settings: 'Langganan'\n    Fetch Feeds from RSS: 'Ambil Umpan dari RSS'\n    Fetch Automatically: Ambil Umpan Secara Otomatis\n    'Limit the number of videos displayed for each channel': Batasi jumlah video yang ditampilkan untuk setiap saluran\n    To: Untuk\n    Confirm Before Unsubscribing: Konfirmasi Sebelum Berhenti Berlangganan\n  Data Settings:\n    Data Settings: 'data'\n    Select Export Type: 'Pilih Tipe Ekspor'\n    Import Subscriptions: 'Impor Langganan'\n    Export Subscriptions: 'Ekspor Langganan'\n    Export FreeTube: 'Ekspor FreeTube'\n    Export YouTube: 'Ekspor YouTube'\n    Export NewPipe: 'Ekspor NewPipe'\n    Import History: 'Impor Riwayat'\n    Export History: 'Ekspor Riwayat'\n    Profile object has insufficient data, skipping item: 'Obyek profil tidak memiliki cukup data, melewati item'\n    All subscriptions and profiles have been successfully imported: 'Semua langganan dan profil telah berhasil diimpor'\n    All subscriptions have been successfully imported: 'Semua langganan telah berhasil diimpor'\n    Invalid subscriptions file: 'Berkas langganan tidak valid'\n    Invalid history file: 'Berkas riwayat tidak valid'\n    Subscriptions have been successfully exported: 'Langganan telah berhasil diekspor'\n    History object has insufficient data, skipping item: 'Obyek riwayat tidak memiliki cukup data, melewati item'\n    All watched history has been successfully imported: 'Semua riwayat tontonan telah berhasil diimpor'\n    All watched history has been successfully exported: 'Semua riwayat tontonan telah berhasil diekspor'\n    Unable to read file: 'Tidak dapat membaca berkas'\n    Unable to write file: 'Tidak dapat menulis berkas'\n    Unknown data key: 'Kunci data tidak diketahui'\n    How do I import my subscriptions?: 'Bagaimana saya mengimpor langganan saya?'\n    Manage Subscriptions: Kelola Langganan\n    Import Playlists: Impor Playlist\n    Export Playlists: Ekspor Playlist\n    Playlist insufficient data: Data tidak mencukupi untuk \"{playlist}\" playlist, melewatkan item\n    All playlists has been successfully imported: Semua daftar putar berhasil diimpor\n    All playlists has been successfully exported: Semua daftar putar berhasil diekspor\n    Subscription File: Berkas Langganan\n    History File: Berkas Riwayat\n    Playlist File: Berkas Daftar Putar\n    Export Playlists For Older FreeTube Versions:\n      Label: Ekspor Daftar Putar untuk Versi FreeTube yang Lebih Tua\n\n      Tooltip: \"Opsi ini mengekspor video dari semua daftar putar ke dalam satu daftar putar bernama 'Favorit'.\\nCara mengekspor & mengimpor video dalam daftar putar untuk FreeTube versi lama:\\n1. Ekspor daftar putar Anda dengan mengaktifkan opsi ini.\\n2. Hapus semua daftar putar Anda yang ada menggunakan opsi Hapus Semua Daftar Putar di bawah Pengaturan Privasi.\\n3. Luncurkan FreeTube versi lama dan impor daftar putar yang diekspor.\\\"\"\n    Search history file: Berkas riwayat pencarian\n    Search history: Riwayat pencarian\n    Import search history: Impor riwayat pencarian\n    Export search history: Ekspor riwayat pencarian\n    All search history has been successfully imported: Semua riwayat pencarian telah berhasil diimpor\n    All search history has been successfully exported: Semua riwayat pencarian telah berhasil diekspor\n  Distraction Free Settings:\n    Hide Comment Likes: Sembunyikan Jumlah Suka pada Komentar\n    Hide Channel Subscribers: Sembunyikan Jumlah Pelanggan Kanal\n    Hide Recommended Videos: Sembunyikan Video yang Direkomendasikan\n    Hide Trending Videos: Sembunyikan Video yang Sedang Tren\n    Hide Live Chat: Sembunyikan Obrolan Langsung\n    Hide Popular Videos: Sembunyikan Video Populer\n    Distraction Free Settings: Bebas Gangguan\n    Hide Video Likes And Dislikes: Sembunyikan Suka dan Tidak Suka Video\n    Hide Video Views: Sembunyikan Tinjauan Video\n    Hide Active Subscriptions: Sembunyikan Langganan Aktif\n    Hide Playlists: Sembunyikan Daftar Putar\n    Sections:\n      Side Bar: Bilah Samping\n      Subscriptions Page: Halaman Langganan\n      Channel Page: Halaman Kanal\n      Watch Page: Halaman Tontonan\n      General: Umum\n    Hide Channels Already Exists: ID Kanal sudah ada\n    Hide Channel Podcasts: Sembunyikan Tab \"Podcast\" Saluran\n    Display Titles Without Excessive Capitalisation: Tampilkan Judul Tanpa Huruf Kapital dan Tanda Baca yang Berlebihan\n    Hide Upcoming Premieres: Sembunyikan Siaran Langsung yang Akan Datang\n    Hide Live Streams: Sembunyikan Siaran Langsung\n    Hide Channel Playlists: Sembunyikan Tab \"Daftar Putar\" Saluran\n    Hide Sharing Actions: Sembunyikan Tindakan Bagikan Video\n    Hide Videos on Watch: 'Sembunyikan Video saat Menonton'\n    Hide Featured Channels: Sembunyikan Kanal Unggulan\n    Hide Channels: Sembunyikan Video dari Kanal\n    Hide Channels Placeholder: ID Kanal\n    Hide Channels API Error: Galat menemukan pengguna dengan ID yang diberikan. Mohon periksa kembali apakah ID-nya benar.\n    Hide Channel Releases: Sembunyikan Tab \"Rilis\" Saluran\n    Hide Videos, Playlists and Channels Containing Text: Sembunyikan Video dan Daftar yang Mengandung Teks\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Kata, Kata-Kata, atau Frasa\n    Hide Subscriptions Videos: Sembunyikan Video dalam Langganan\n    Hide Subscriptions Live: Sembunyikan Siaran Langsung dalam Langganan\n    Hide Video Description: Sembunyikan Deskripsi Video\n    Hide Comments: Sembunyikan Komentar\n    Hide Profile Pictures in Comments: Sembunyikan Gambar Profil di Komentar\n    Hide Channels Disabled Message: Beberapa kanal diblokir menggunakan ID dan belum diproses. Fitur kanal tersebut diblokir selagi ID tersebut diperbarui\n    Hide Channels Invalid: ID Kanal yang diberikan tidak valid\n    Hide Chapters: Sembunyikan Bab\n    Hide Subscriptions Shorts: Sembunyikan Langganan Shorts\n    Show Added Items: Tampilkan Item yang Ditambahkan\n    Hide Channel Home: Sembunyikan Tab \"Beranda\" Saluran\n    Hide Channel Shorts: Sembunyikan Tab \"Shorts\" Saluran\n    Hide Channel Courses: Sembunyikan Tab \"Kursus\" Saluran\n    Hide Channel Posts: Sembunyikan Tab \"Postingan\" Saluran\n    Hide Subscriptions Posts: Sembunyikan Postingan dalam Langganan\n  The app needs to restart for changes to take effect. Restart and apply change?: Aplikasi butuh dimulai ulang agar perbubahan diterapkan. Mulai ulang dan terapkan perubahan?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Galat mendapatkan informasi jaringan. Apakah proksi Anda dikonfigurasi dengan benar?\n    City: Kota\n    Region: Wilayah\n    Country: Negara\n    Ip: IP\n    Your Info: Info Anda\n    Test Proxy: Tes Proksi\n    Clicking on Test Proxy will send a request to: Klik pada Tes Proksi akan mengirim permintaan ke\n    Proxy Port Number: Porta Proksi\n    Proxy Host: Hos Proksi\n    Proxy Protocol: Protokol Proksi\n    Enable Tor / Proxy: Aktifkan Tor / Proksi\n    Proxy Settings: Proksi\n    Proxy Warning: FreeTube tidak memiliki proxy bawaan tetapi dapat terhubung ke proxy eksternal, seperti proxy yang berjalan di komputer Anda seperti Tor atau proxy eksternal seperti proxy SOCKS5 yang disediakan oleh beberapa VPN. Jika diaktifkan, pastikan proxy/Tor Anda dikonfigurasi dengan benar, atau FreeTube tidak akan dapat mengambil data apa pun.\n    Proxy Username: Nama pengguna proksi\n    Proxy Password: Kata sandi proksi\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Beri tahu saat segmen sponsor dilewati\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Url SponsorBlock API (Default is https://sponsor.ajay.app)\n    Enable SponsorBlock: Aktifkan SponsorBlock\n    SponsorBlock Settings: SponsorBlok\n    UseDeArrowTitles: Gunakan Judul Video dari DeArrow\n    Skip Options:\n      Skip Option: Pilihan Melewati\n      Auto Skip: Otomatis Lewati\n      Show In Seek Bar: Tampilkan Di Seek Bar\n      Do Nothing: Jangan Lakukan Apa Pun\n      Prompt To Skip: Perintah untuk Melewati\n    UseDeArrowThumbnails: Gunakan Keluku dari DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL API DeArrow Thumbnail Generator\n    Category Color: Warna Kategori\n  External Player Settings:\n    Custom External Player Arguments: Argumen Pemutar Eksternal\n    Custom External Player Executable: Aplikasi Pemutar Eksternal\n    Ignore Unsupported Action Warnings: Abaikan Peringatan Tindakan yang Tidak Didukung\n    External Player: Pemutar Eksternal\n    External Player Settings: Pemutar Eksternal\n    Players:\n      None:\n        Name: Nihil\n    Ignore Default Arguments: Abaikan Argumen Default\n  Experimental Settings:\n    Experimental Settings: Eksperimental\n    Replace HTTP Cache: Ganti Tembolok HTTP\n    Warning: Pengaturan ini masih bersifat eksperimental, dan dapat menyebabkan crash saat diaktifkan. Sangat disarankan untuk membuat cadangan. Gunakan dengan risiko Anda sendiri!\n  Password Settings:\n    Set Password To Prevent Access: Tetapkan sandi untuk mencegah akses ke pengaturan\n    Password Settings: Sandi\n    Remove Password: Hapus Kata Sandi\n    Set Password: Atur Kata Sandi\n  Password Dialog:\n    Enter Password To Unlock: Masukkan sandi untuk membuka kunci pengaturan\n    Password: Kata Sandi\n  Parental Control Settings:\n    Parental Control Settings: Kontrol Orang Tua\n    Hide Unsubscribe Button: Sembunyikan Tombol Berhenti Berlangganan\n    Show Family Friendly Only: Tampilkan Hanya yang Ramah Keluarga\n    Hide Search Bar: Sembunyikan Kotak Pencarian\n    Hide Uploader on Watch page: Sembunyikan Pengunggah pada Halaman Tontonan\n  Return to Settings Menu: Kembali ke Menu Pengaturan\n  Sort Settings Sections (A-Z): Urutkan Bagian Pengaturan (A-Z)\nAbout:\n  #On About page\n  About: 'Tentang'\n  #& About\n  Donate: Donasi\n  these people and projects: pengembang dan proyek berikut\n  Credits: Kredit\n  Translate: Terjemahkan\n  room rules: aturan kamar\n  Chat on Matrix: Mengobrol di Matrix\n  Mastodon: mastodon\n  Email: Surel\n  Blog: Blog\n  Website: Situs web\n  Please check for duplicates before posting: Silakan periksa duplikat sebelum melaporkan\n  GitHub issues: Isu GitHub\n  Report a problem: Laporkan masalah\n  FAQ: PYSD\n  FreeTube Wiki: Wiki FreeTube\n  Help: Bantuan\n  GitHub releases: Rilis GitHub\n  Downloads / Changelog: Unduhan / Catatan Perubahan\n  Source code: Kode sumber\n  Beta: Beta\n  Discussions: Diskusi\n  AGPLv3: Agplv3\n  Licensed under the {licenseLink}: Dilisensikan di bawah {licenseLink}\n  Please read the {roomRulesLink}: Silahkan baca {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube dapat dibuat atas dukungan dari {creditsPageLink}\nProfile:\n  Profile Select: 'Pilih Profil'\n  All Channels: 'Semua Kanal'\n  Profile Manager: 'Pengelola Profil'\n  Create New Profile: 'Buat Profil Baru'\n  Edit Profile: 'Sunting Profil'\n  Color Picker: 'Pemilih Warna'\n  Custom Color: 'Warna Khusus'\n  Profile Preview: 'Pratinjau Profil'\n  Create Profile: 'Buat Profil'\n  Update Profile: 'Perbarui Profil'\n  Make Default Profile: 'Jadikan Profil Baku'\n  Delete Profile: 'Hapus Profil'\n  Are you sure you want to delete this profile?: 'Apakah Anda yakin ingin menghapus profil ini?'\n  All subscriptions will also be deleted.: 'Semua langganan juga akan dihapus.'\n  Your profile name cannot be empty: 'Nama profil Anda tidak boleh kosong'\n  Profile has been created: 'Profil telah dibuat'\n  Profile has been updated: 'Profil telah diperbarui'\n  Your default profile has been set to {profile}: 'Profil baku Anda telah diatur ke {profile}'\n  Removed {profile} from your profiles: '{profile} dihapus dari profil Anda'\n  Your default profile has been changed to your primary profile: 'Profil baku Anda telah diubah ke profil utama Anda'\n  '{profile} is now the active profile': '{profile} adalah profil aktif sekarang'\n  Subscription List: 'Daftar Langganan'\n  Other Channels: 'Kanal Lain'\n  '{number} selected': '{number} terpilih'\n  Select All: 'Pilih Semua'\n  Select None: 'Tidak Pilih Apa Pun'\n  Delete Selected: 'Hapus yang Terpilih'\n  Add Selected To Profile: 'Tambahkan Kanal yang Terpilih ke Profil'\n  No channel(s) have been selected: 'Tidak ada kanal yang terpilih'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Ini adalah profil utama Anda. Apakah Anda yakin ingin menghapus kanal yang terpilih? Kanal yang sama juga akan dihapus dari semua profil.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Apakah Anda yakin ingin menghapus kanal yang terpilih? Tindakan ini tidak akan menghapus kanal tersebut dari profil yang lain.'\n#On Channel Page\n  Profile Filter: Filter Profil\n  Profile Settings: Profil\n  Profile Name: Nama Profil\n  Edit Profile Name: Sunting Nama Profil\n  Create Profile Name: Buat Nama Profil\n  Close Profile Dropdown: Tutup Profil Dropdown\n  Open Profile Dropdown: Buka Menu Dropdown Profil\n  Toggle Profile List: Beralih Daftar Profil\nChannel:\n  Subscribe: 'Langganan'\n  Unsubscribe: 'Berhenti Berlangganan'\n  Channel has been removed from your subscriptions: 'Kanal telah dihapus dari langganan Anda'\n  Removed subscription from {count} other channel(s): 'Langganan terhapus dari {count} kanal lainnya'\n  Added channel to your subscriptions: 'Kanal ditambahkan ke langganan Anda'\n  Search Channel: 'Cari Kanal'\n  Your search results have returned 0 results: 'Hasil pencarian Anda memberikan 0 hasil'\n  Videos:\n    Videos: 'Video'\n    This channel does not currently have any videos: 'Kanal ini belum memiliki video apa pun'\n    Sort Types:\n      Newest: 'Terbaru'\n      Oldest: 'Terlawas'\n      Most Popular: 'Paling Populer'\n  Playlists:\n    Playlists: 'Daftar Putar'\n    This channel does not currently have any playlists: 'Kanal ini belum memiliki daftar putar apa pun'\n    Sort Types:\n      Last Video Added: 'Video Terakhir Ditambahkan'\n      Newest: 'Terbaru'\n      Oldest: 'Terlawas'\n  About:\n    About: 'Tentang'\n    Channel Description: 'Deskripsi Kanal'\n    Featured Channels: 'Kanal Unggulan'\n    Details: Detail\n    Location: Lokasi\n    Tags:\n      Search for: Pencarian untuk \"{tag}\"\n      Tags: Tag\n    Joined: Bergabung\n  Live:\n    Live: Siaran Langsung\n    This channel does not currently have any live streams: Kanal ini belum memiliki siaran langsung apa pun\n  Posts:\n    Hide Answers: Sembunyikan jawaban\n    Reveal Answers: Tampilkan jawaban\n    Video hidden by FreeTube: Video disembunyikan oleh FreeTube\n    This channel currently does not have any posts: Kanal ini belum memiliki pos apa pun\n    votes: '{votes} memilih'\n    View Full Post: Lihat Postingan Lengkap\n    Viewing Posts Only Supported By Invidious: Melihat Postingan hanya didukung oleh Invidious. Buka tab komunitas saluran untuk melihat konten di sana tanpa Invidious.\n  Releases:\n    Releases: Rilis\n    This channel does not currently have any releases: Kanal ini belum memiliki rilis apa pun\n  Podcasts:\n    Podcasts: Sinaran\n    This channel does not currently have any podcasts: Kanal ini belum memiliki sinaran apa pun\n  This channel does not exist: Kanal ini tidak ada\n  Home:\n    View Playlist: Lihat Daftar Putar\n    Home: Beranda\n  Shorts:\n    This channel does not currently have any shorts: Saluran ini saat ini tidak memiliki shorts\n  This channel does not allow searching: Saluran ini tidak mengizinkan pencarian\n  Channel Tabs: Tab Saluran\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Saluran ini dibatasi usia dan saat ini tidak dapat ditonton di FreeTube.\n  Courses:\n    This channel does not currently have any courses: Saluran ini saat ini tidak memiliki kursus apa pun\n    Courses: kursus\nVideo:\n  Mark As Watched: 'Tandai Sudah Ditonton'\n  Remove From History: 'Hapus dari Riwayat'\n  Video has been marked as watched: 'Video telah ditandai sudah ditonton'\n  Video has been removed from your history: 'Video telah dihapus dari riwayat Anda'\n  Open in YouTube: 'Buka di YouTube'\n  Copy YouTube Link: 'Salin Tautan YouTube'\n  Open YouTube Embedded Player: 'Buka di Pemutar Tersemat YouTube'\n  Copy YouTube Embedded Player Link: 'Salin Tautan Pemutar Tersemat YouTube'\n  Open in Invidious: 'Buka di Invidious'\n  Copy Invidious Link: 'Salin Tautan Invidious'\n  Views: 'Ditonton'\n  Loop Playlist: 'Ulangi Daftar Putar'\n  Shuffle Playlist: 'Acak Daftar Putar'\n  Reverse Playlist: 'Putar-Balik Daftar Putar'\n  Previous: 'Sebelumnya'\n  Next: 'Berikutnya'\n  Watched: 'Sudah Ditonton'\n  Autoplay: 'Putar-Otomatis'\n  # As in a Live Video\n  Live: 'Siaran Langsung'\n  Live Now: 'Sedang Siaran Langsung'\n  Live Chat: 'Obrolan Langsung'\n  Enable Live Chat: 'Aktifkan Obrolan Langsung'\n  Live Chat is currently not supported in this build.: 'Obrolan Langsung belum didukung dalam versi ini.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Obrolan langsung diaktifkan. Pesan akan muncul di sini saat terkirim.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Obrolan Langsung belum didukung dengan API Invidious. Koneksi langsung dengan YouTube dibutuhkan.'\n  Published on: 'Dipublikasi pada'\n#& Videos\n  Starting soon, please refresh the page to check again: Segera dimulai, silakan muat ulang halaman untuk mengeceknya kembali\n  Copy Invidious Channel Link: Salin Tautan Kanal Invidious\n  Open Channel in Invidious: Buka Kanal di Invidious\n  Copy YouTube Channel Link: Salin Tautan Kanal YouTube\n  Open Channel in YouTube: Buka Kanal di YouTube\n  Started streaming on: Siaran langsung dimulai pada\n  Streamed on: Siaran langsung pada\n  Video has been removed from your saved list: Video telah dihapus dari daftar simpan Anda\n  Video has been saved: Video telah disimpan\n  Save Video: Simpan Video\n  Sponsor Block category:\n    interaction: Interaksi\n    music offtopic: Musik Non-Topik\n    self-promotion: Promosi Diri Sendiri\n    outro: outro\n    intro: Intro\n    sponsor: Sponsor\n    recap: Rekap\n    filler: Pengisi\n  External Player:\n    Unsupported Actions:\n      starting video at offset: memulai video pada offset\n      looping playlists: memutar berulang-ulang daftar putar\n      shuffling playlists: mengacak daftar putar\n      reversing playlists: membalik urutan daftar putar\n      opening specific video in a playlist (falling back to opening the video): membuka video yang spesifik di dalam daftar putar (dengan cadangan untuk membuka langsung video)\n      opening playlists: membuka daftar putar\n      setting a playback rate: menetapkan laju pemutaran\n    UnsupportedActionTemplate: '{externalPlayer} tidak mendukung: {action}'\n    OpeningTemplate: Membuka {videoOrPlaylist} dalam {externalPlayer}...\n    playlist: daftar putar\n    video: video\n    OpenInTemplate: Buka di {externalPlayer}\n  Hide Channel: Sembunyikan Kanal\n  Upcoming: Akan Datang\n#& Playlists\n  IP block: YouTube telah memblokir alamat IP Anda agar tidak dapat menonton video. Coba beralih ke VPN atau proxy lain.\n  DRMProtected: Video yang dilindungi DRM tidak dapat diputar di FreeTube, karena memerlukan komponen sumber tertutup dan berpemilik. Jika Anda ingin menonton video ini, silakan tonton di situs web YouTube resmi di peramban web yang mendukung DRM.\n  Published:\n    In less than a minute: Dalam waktu kurang dari satu menit\n  DeArrow:\n    Show Original Details: Tampilkan Detail Asli\n    Show Modified Details: Tampilkan Detail yang Dimodifikasi\n  Player:\n    TranslatedCaptionTemplate: '{language} (diterjemahkan dari \"{originalLanguage}\")'\n    Audio Tracks: Trek Audio\n    Autoplay is off: Putar otomatis mati\n    Autoplay is on: Putar otomatis hidup\n    Exit Full Window: Keluar dari Jendela Penuh\n    Stats:\n      Video ID: 'ID Video: {videoId}'\n      Bitrate: 'Kecepatan bit: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      Buffered: 'Di-buffer: {bufferedPercentage}%'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Frame yang Dihilangkan: {droppedFrames} / Jumlah Frame: {totalFrames}'\n      Media Formats: 'Format Media: {formats}'\n      CodecsVideoAudio: 'Kodek: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Resolution: 'Resolusi: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensi Pemain: {width}x{height}'\n      Stats: Statistik\n      Bandwidth: 'bandwidth: {bandwidth} kbps'\n      CodecsVideoAudioNoItags: 'Kodek: {videoCodec} / {audioCodec}'\n    Show Stats: Tampilkan Statistik\n    Full Window: Jendela Penuh\n    Hide Stats: Sembunyikan Statistik\n    Theatre Mode: Mode Teater\n    Exit Theatre Mode: Keluar dari Mode Teater\n    Take Screenshot: Ambil Tangkapan Layar\n    You appear to be offline: Anda tampaknya sedang offline.\n    Playback will resume automatically when your connection comes back: Pemutaran ulang akan dilanjutkan secara otomatis ketika koneksi Anda kembali.\n    Skipped segment: Melewati segmen {segmentCategory}\n  More Options: Lebih Banyak Pilihan\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Obrolan Langsung tidak tersedia untuk streaming ini. Mungkin telah dinonaktifkan oleh pengunggah.\n  Show Super Chat Comment: Tampilkan Komentar Super Chat\n  MembersOnly: Video khusus anggota tidak dapat ditonton dengan FreeTube karena memerlukan login Google dan keanggotaan berbayar ke saluran pengunggah.\n  Unlisted: Tidak terdaftar\n  Unhide Channel: Tampilkan Saluran\n  Scroll to Bottom: Gulir ke Bawah\n  Premieres: Penayangan perdana\n  AgeRestricted: Video yang dibatasi usia tidak dapat ditonton dengan FreeTube karena memerlukan login Google dan menggunakan akun YouTube yang diverifikasi usianya.\n  Save Watched Progress: Simpan Progress Tontonan\n  Watched Progress Saved: Progress Tontonan yang telah Disimpan\n  Popout Live Chat: Obrolan Popout\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Waktu iklan pra-putar yang tersisa: {remindingTimeSeconds}detik'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Waktu tunggu SABR yang tersisa: {remindingTimeSeconds}detik'\nPlaylist:\n  #& About\n  View Full Playlist: 'Tampilkan Daftar Putar Penuh'\n  Last Updated On: 'Terakhir Diperbarui Pada'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Daftar Putar\n  Sort By:\n    PublishedNewest: Tanggal dipublikasikan (Terbaru)\n    PublishedOldest: Tanggal dipublikasikan (Terlama)\n    AuthorAscending: Penulis (A-Z)\n    Custom: Aturan sendiri\n    VideoTitleAscending: Judul (A-Z)\n    DateAddedOldest: Tanggal ditambahkan (Terlama)\n    DateAddedNewest: Tanggal ditambahkan (Terbaru)\n    VideoDurationAscending: Durasi (Terpendek)\n    VideoDurationDescending: Durasi (Terpanjang)\n    VideoTitleDescending: Judul (Z-A)\n    AuthorDescending: Penulis (Z-A)\nChange Format:\n  Change Media Formats: 'Ubah Format Video'\n  Use Dash Formats: 'Gunakan Format DASH'\n  Use Legacy Formats: 'Gunakan Format Lawas'\n  Use Audio Formats: 'Gunakan Format Audio'\n  Dash formats are not available for this video: 'Format DASH tidak tersedia untuk video ini'\n  Audio formats are not available for this video: 'Format audio tidak tersedia untuk video ini'\n  Legacy formats are not available for this video: Format lama tidak tersedia untuk video ini\nShare:\n  Share Video: 'Bagikan Video'\n  Share Playlist: 'Bagikan Daftar Putar'\n  Include Timestamp: 'Sertakan Waktu-Terkini'\n  Copy Link: 'Salin Tautan'\n  Open Link: 'Buka Tautan'\n  Copy Embed: 'Salin Tersemat'\n  Open Embed: 'Buka Tersemat'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious tersalin ke papan klip'\n  Invidious Embed URL copied to clipboard: 'URL Tersemat Invidious tersalin ke papan klip'\n  YouTube URL copied to clipboard: 'URL YouTube tersalin ke papan clip'\n  YouTube Embed URL copied to clipboard: 'URL Tersemat YouTube tersalin ke papan klip'\n  YouTube Channel URL copied to clipboard: URL Kanal YouTube disalin ke papan klip\n  Invidious Channel URL copied to clipboard: URL Kanal Invidious disalin ke papan klip\n  Share Channel: Bagikan Kanal\n  Share Post: Bagikan Postingan\nMini Player: 'Pemutar Kecil'\nComments:\n  Comments: 'Komentar'\n  Click to View Comments: 'Klik untuk Melihat Komentar'\n  Getting comment replies, please wait: 'Memuat balasan komentar, harap tunggu'\n  Hide Comments: 'Sembunyikan Komentar'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Tidak ada komentar tersedia untuk video ini'\n  Load More Comments: 'Muat Lebih Banyak Komentar'\n  Newest first: Terbaru\n  Top comments: Komentar teratas\n  There are no more comments for this video: Tidak ada komentar lagi untuk video ini\n  Show More Replies: Tampilkan Lebih Banyak Balasan\n  Pinned by: Disematkan oleh\n  Member: Anggota\n  View {replyCount} replies: Lihat 1 balasan | Lihat {replyCount} balasan\n  Subscribed: Berlangganan\n  Hearted: Disukai\n  There are no comments available for this post: Tidak ada komentar yang tersedia untuk posting ini\n  Hide {replyCount} replies: Sembunyikan 1 balasan | Sembunyikan {replyCount} balasan\n  View 1 reply from {channelName}: Lihat 1 balasan dari {channelName}\n  View {replyCount} replies from {channelName} and others: Lihat {replyCount} balasan dari {channelName} dan lainnya\nUp Next: 'Akan Datang'\n\n# Toast Messages\nLocal API Error (Click to copy): 'API Lokal Galat (Klik untuk menyalin)'\nInvidious API Error (Click to copy): 'API Invidious Galat (Klik untuk menyalin)'\nFalling back to Invidious API: 'Kembali ke API Invidious'\nFalling back to Local API: 'Kembali ke API lokal'\nLoop is now disabled: 'Putar-Ulang sekarang dimatikan'\nLoop is now enabled: 'Putar-Ulang sekarang diaktifkan'\nShuffle is now disabled: 'Acak sekarang dimatikan'\nShuffle is now enabled: 'Acak sekarang diaktifkan'\nThe playlist has been reversed: 'Daftar Putar telah dibalik'\nPlaying Next Video: 'Memutar Video Berikutnya'\nPlaying Previous Video: 'Memutar Video Sebelumnya'\nCanceled next video autoplay: 'Putar-otomatis video berikutnya dibatalkan'\n'The playlist has ended. Enable loop to continue playing': 'Daftar putar telah berakhir. Aktifkan Putar-Ulang untuk melanjutkan pemutaran'\n\nYes: 'Ya'\nNo: 'Tidak'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Video ini tidak tersedia karena format hilang. Ini bisa terjadi karena dibatasi berdasarkan wilayah.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Saat diaktifkan, FreeTube akan menggunakan RSS, bukan metode default untuk mengambil umpan langganan Anda. RSS lebih cepat dan mencegah pemblokiran IP, tetapi tidak memberikan informasi tertentu seperti durasi video, status langsung, atau postingan komunitas\n    Fetch Automatically: Ketika dinyalakan, FreeTube akan mengambil secara otomatis umpan langganan Anda saat memulai ketika jendala baru dibuka.\n  Player Settings:\n    Default Video Format: Atur format ketika video dimainkan. Format DASH dapat memutar kualitas yang lebih tinggi. Format lama terbatas ke maksimum 720p tetapi dengan bandwidth yang lebih rendah. Format audio hanya berisi aliran audio.\n    Proxy Videos Through Invidious: Akan menyambung ke Invidious daripada YouTube.\n    Scroll Playback Rate Over Video Player: Ketika kursor berada di atas video, tekan dan tahan tombol Control (tombol Command di Mac) dan scroll roda mouse ke depan atau ke belakang untuk mengontrol laju pemutaran. Tekan dan tahan tombol Control (tombol Command di Mac) dan klik kiri mouse untuk dengan cepat kembali ke laju pemutaran default (1x kecuali telah diubah dalam pengaturan).\n    Allow DASH AV1 formats: Format DASH AV1 mungkin terlihat lebih baik daripada format DASH H.264. Format DASH AV1 memerlukan lebih banyak energi untuk pemutaran! Format itu juga tidak tersedia di semua video, yang mana pemutar akan menggunakan format DASH H.264.\n    Skip by Scrolling Over Video Player: Gunakan guliran tetikus untuk melewati lewat video, seperti MPV.\n  General Settings:\n    Region for Trending: Wilayah tren memungkinkan Anda memilih video yang sedang ngetren dari negara tersebut untuk ditampilkan.\n    Invidious Instance: Situs Invidious yang akan tersambung dengan FreeTube untuk panggilan API.\n    Thumbnail Preference: Semua gambar mini di dalam aplikasi FreeTube akan diganti dengan frame dari video, diburamkan atau disembunyikan alih-alih menggunakan gambar mini bawaan.\n    Fallback to Non-Preferred Backend on Failure: Ketika API yang Anda pilih memiliki masalah, FreeTube akan secara otomatis menggunakan layanan API lainnya sebagai cadangan jika diaktifkan.\n    Preferred API Backend: Pilih layanan yang digunakan oleh FreeTube untuk mengambil data. API lokal adalah ekstraktor bawaan. API Invidious membutuhkan sambungan ke server Invidious.\n    External Link Handling: \"Pilih perilaku default ketika tautan, yang tidak dapat dibuka di FreeTube, diklik.\\nSecara default FreeTube akan membuka tautan yang diklik dengan browser default Anda.\\n\"\n    Open Deep Links In New Window: URL yang diteruskan ke FreeTube, seperti melalui ekstensi browser pengalihan atau argumen baris perintah, dibuka di jendela baru.\n  External Player Settings:\n    Custom External Player Arguments: Semua argumen perintah khusus, yang Anda ingin gunakan dengan pemutar eksternal.\n    Ignore Warnings: Jangan tampilkan peringatan saat pemutar eksternal saat ini tidak mendukung tindakan yang ada (mis. membalik urutan daftar putar, dsb.).\n    Custom External Player Executable: Secara bawaan, FreeTube akan berasumsi bahwa pemutar eksternal yang dipilih bisa diitemukan via variabel lingkungan PATH. Jika diperlukan, bisa menggunakan jalur khusus di sini.\n    External Player: Memilih pemutar eksternal akan menampilkan ikon khusus, untuk membuka video (daftar putar jika didukung) di dalam pemutar eksternal, pada thumbnail. Peringatan, pengaturan Invidious tidak berdampak pada pemutar eksternal.\n    DefaultCustomArgumentsTemplate: \"(Default: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Jangan kirim argumen default apa pun ke pemutar eksternal selain URL video (misalnya kecepatan pemutaran, URL daftar putar, dll.). Argumen khusus akan tetap diteruskan.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Gunakan judul video dari judul yang disarankan oleh pengguna dari DeArrow.\n    UseDeArrowThumbnails: Gunakan keluku video dari yang disediakan oleh DeArrow.\n  Distraction Free Settings:\n    Hide Channels: Masukkan ID Kanal untuk menyembunyikan semua video, daftar putar, dan kanal itu sendiri dari pencarian, halaman tren, halaman video popular, dan bagian rekomendasi. ID Kanal yang dimasukkan harus sesuai.\n    Hide Subscriptions Live: Pengaturan ini digantikan oleh pengaturan \"{appWideSetting}\" di seluruh aplikasi, di bagian \"{subsection}\" dari \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Masukkan kata, pecahan kata, atau frasa (tanpa memperhatikan huruf besar/kecil) untuk menyembunyikan semua video & daftar putar yang judul aslinya memuatnya di seluruh FreeTube, kecuali hanya Riwayat, Daftar Putar Anda, dan video di dalam daftar putar.\n    Hide Videos on Watch: Menyembunyikan video yang telah ditonton dari Tab Video, Video Pendek, dan Langsung pada Halaman Langganan dan Kanal. Hal tersebut tidak mempengaruhi Tab Beranda pada Halaman Kanal\n  Experimental Settings:\n    Replace HTTP Cache: Menonaktifkan cache HTTP berbasis disk Electron dan mengaktifkan cache gambar dalam memori khusus. Akan menyebabkan peningkatan penggunaan RAM.\nPlaying Next Video Interval: Langsung putar video berikutnya. Klik untuk membatalkan. | Putar video berikutnya dalam {nextVideoInterval} detik. Klik untuk membatalkan. | Putar video berikutnya dalam {nextVideoInterval} detik. Klik untuk membatalkan.\nMore: Lebih banyak\nUnknown YouTube url type, cannot be opened in app: Tipe URL YouTube tidak dikenal, tidak bisa dibuka di aplikasi\nOpen New Window: Buka Jendela Baru\nSearch Bar:\n  Clear Input: Hapus Masukan\n  Remove: Buang\nExternal link opening has been disabled in the general settings: Pembukaan tautan eksternal telah dimatikan pada pengaturan umum\nAre you sure you want to open this link?: Yakin ingin membuka tautan ini?\nDefault Invidious instance has been set to {instance}: 'Situs Invidious baku telah di atur ke {instance}'\nDefault Invidious instance has been cleared: Peladen Invidious yang baku telah disetel ulang\nNew Window: Jendela Baru\nChannels:\n  Channels: Kanal\n  Title: Daftar Kanal\n  Search bar placeholder: Cari Kanal\n  Count: '{number} kanal ditemukan.'\n  Unsubscribe Prompt: Apakah Anda yakin ingin berhenti berlangganan \"{channelName}\"?\n  Empty: Daftar kanal Anda kosong.\nPreferences: Pengaturan\nClipboard:\n  Copy failed: Gagal menyalin ke papan klip\n  Cannot access clipboard without a secure connection: Tidak dapat mengakses papan klip tanpa koneksi yang aman\nScreenshot Error: Tangkap layar gagal. {error}\nFeed:\n  Refresh Feed: Muat Ulang {subscriptionName}\n  Feed Last Updated: 'Umpan {feedName} terakhir diperbarui: {date}'\nScreenshot Success: Tangkapan layar disimpan\nMoments Ago: beberapa saat yang lalu\nYes, Delete: Ya, Hapus\nYes, Restart: Ya, Mulai Ulang\nCancel: Batal\nGo to page: Pergi ke {page}\nOk: Oke\nYes, Open Link: Ya, Buka Tautan\ncheckmark: ✓\nClose Banner: Tutup Banner\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Subtitel\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Baru\n    3D: 3D\n    Closed Captions: Tutup Caption\nSearch character limit: Kata pencarian melebihi batas {searchCharacterLimit} karakter\nRight-click or hold to see history: Klik kanan atau tahan untuk melihat riwayat\nKeyboardShortcutPrompt:\n  Sections:\n    App:\n      General: 'Aplikasi: Umum'\n      Situational: 'Aplikasi: Situasional'\n    Video:\n      General: 'Video: Umum'\n      Playback: 'Video: Pemutaran ulang'\n  Show Keyboard Shortcuts: Tampilkan pintasan keyboard\n  Captions: Aktifkan/Nonaktifkan teks\n  Stats: Tampilkan statistik video\n  Fullscreen: Beralih ke layar penuh\n  Picture in Picture: Beralih ke mode Gambar-dalam-Gambar\n  Decrease Video Speed: Kurangi kecepatan video berdasarkan Interval Kecepatan Pemutaran Video\n  Increase Video Speed: Meningkatkan kecepatan video berdasarkan Interval Kecepatan Pemutaran Video\n  Full Window: Alihkan jendela penuh\n  Theatre Mode: Beralih ke mode teater\n  Zoom Out: Perkecil\n  Focus Search: Fokus pada bilah pencarian\n  Next Frame: Bingkai berikutnya (saat dijeda)\n  Volume Up: Meningkatkan volume\n  Volume Down: Kurangi volume\n  Small Rewind: Putar ulang X detik berdasarkan Interval Putar Ulang dan Kecepatan Pemutaran Video saat ini\n  Small Fast Forward: Percepatan X detik berdasarkan Interval Percepatan dan Kecepatan Pemutaran Video saat ini\n  Next Chapter: Bab Berikutnya\n  Skip by Tenths: Lewati video berdasarkan persentase (3 kali lompatan untuk 30% durasi)\n  Keyboard Shortcuts: Pintasan keyboard\n  History Backward: Kembali satu halaman\n  History Forward: Maju satu halaman\n  New Window: Buat jendela baru\n  Navigate to Settings: Navigasi ke halaman Pengaturan\n  Navigate to History: Navigasi ke halaman Riwayat\n  Refresh: Segarkan umpan dengan konten terbaru\n  Focus Secondary Search: Fokus pada bilah pencarian sekunder (jika ada)\n  Take Screenshot: Ambil tangkapan layar\n  Minimize Window: Minimalkan jendela\n  Close Window: Tutup jendela\n  Search in New Window: Cari di jendela baru\n  Large Fast Forward: Maju 10 detik / Percepat video berdasarkan Kecepatan Pemutaran Video saat ini\n  Last Chapter: Bab Terakhir\n  Large Rewind: Putar ulang 10 detik / Putar ulang video berdasarkan Kecepatan Pemutaran Video saat ini\n  Play: Beralih putar/jeda\n  Mute: Alihkan bisu\n  Toggle Developer Tools: Beralih alat pengembang\n  Reset Zoom: Setel ulang tingkat zoom / skala UI\n  Zoom In: Perbesar\n  Last Frame: Bingkai sebelumnya (saat dijeda)\n  Home: Lihat ke awal video\n  End: Lihat ke akhir video\n  Skip to Next Video: Lewati ke video berikutnya dalam daftar putar atau video yang direkomendasikan berikutnya\n  Skip to Previous Video: Lewati ke video sebelumnya dalam daftar putar\nTag already exists: Tag \"{tagName}\" sudah ada\nChannel Unhidden: '{channel} dihapus dari filter saluran'\nKeys:\n  ctrl: Ctrl\n  plus: Plus\n  shift: Shift\n  arrowup: Panah atas\n  arrowdown: Panah Bawah\n  alt: Alt\n  arrowright: Panah kanan\n  arrowleft: Panah Kiri\n  enter: Enter\nAutoplay Interruption Timer: Putar otomatis dibatalkan karena {autoplayInterruptionIntervalHours} jam tidak aktif\nHashtag:\n  This hashtag does not currently have any videos: Tagar ini saat ini tidak memiliki video apa pun\n  Hashtag: Hastage\nDisplay Label: '{label}: {value}'\nChannel Hidden: '{channel} ditambahkan ke filter saluran'\nAge Restricted:\n  This video is age restricted: Video ini dibatasi usia\n  This channel is age restricted: Saluran ini dibatasi usia\nTrimmed input must be at least N characters long: Input yang dipangkas harus memiliki panjang minimal 1 karakter | Input yang dipangkas harus memiliki panjang minimal {length} karakter\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nChapters:\n  Key Moments: Momen-momen penting\n  Chapters: Bab-bab\nshortcutLabelSeparator: ' '\nDescription:\n  Collapse Description: Tampilkan lebih sedikit\n  Expand Description: '...lanjutan'\nCompact side navigation: Navigasi samping ringkas\nExpand side navigation: Perluas navigasi samping\n"
  },
  {
    "path": "static/locales/is.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Íslenska'\n\n# Webkit Menu Bar\nFile: 'Skrá'\nQuit: 'Hætta'\nEdit: 'Breyta'\nUndo: 'Afturkalla'\nRedo: 'Endurtaka'\nCut: 'Klippa'\nCopy: 'Afrita'\nPaste: 'Líma'\nDelete: 'Eyða'\nSelect all: 'Velja allt'\nToggle Developer Tools: 'Víxla forritaratólum af/á'\nActual size: 'Raunstærð'\nZoom in: 'Renna að'\nZoom out: 'Renna frá'\nToggle fullscreen: 'Víxla skjáfylli af/á'\nWindow: 'Gluggi'\nMinimize: 'Lágmarka'\nClose: 'Loka'\nBack: 'Til baka'\nForward: 'Áfram'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Myndskeið'\n  Shorts: Símamyndir\n  Live: Í beinni\n  Posts: Færslur\n  Sort By: Raða eftir\n\n  Counts:\n    Video Count: 1 myndskeið | {count} myndskeið\n    Channel Count: 1 rás | {count} rásir\n    Subscriber Count: 1 áskrifandi | {count} áskrifendur\n    View Count: 1 áhorf | {count} áhorf\n    Watching Count: 1 að horfa | {count} að horfa\n    Like Count: 1 líkaði | {count} líkaði\n    Comment Count: 1 athugasemd | {count} athugasemdir\nVersion {versionNumber} is now available!  Click for more details: 'Útgáfa {versionNumber} er tiltæk!  Smelltu til að skoða nánar'\nDownload From Site: 'Sækja af vefsvæði'\nA new blog is now available, {blogTitle}. Click to view more: 'Ný bloggfærsla er núna er tiltæk, {blogTitle}. Smelltu til að skoða nánar'\n\n# Search Bar\nSearch / Go to URL: 'Leita / Fara á slóð'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Leitarsíur'\n  Sort By:\n    Most Relevant: 'Mest viðeigandi'\n    Rating: 'Einkunn'\n    Upload Date: 'Dags. innsendingar'\n    View Count: 'Fjöldi áhorfa'\n  Time:\n    Time: 'Tími'\n    Any Time: 'Hvenær sem er'\n    Last Hour: 'Síðustu klukkustund'\n    Today: 'Í dag'\n    This Week: 'Í þessari viku'\n    This Month: 'Í þessum mánuði'\n    This Year: 'Á þessu ári'\n  Type:\n    Type: 'Tegund'\n    All Types: 'Allar tegundir'\n    Videos: 'Myndskeið'\n    Channels: 'Rásir'\n    #& Playlists\n    Movies: Kvikmyndir\n  Duration:\n    Duration: 'Tímalengd'\n    All Durations: 'Allar tímalengdir'\n    Short (< 4 minutes): 'Stutt (< 4 mínútur)'\n    Long (> 20 minutes): 'Langt (> 20 mínútur)'\n  # On Search Page\n    Medium (4 - 20 minutes): Miðlungs (4 - 20 mínútur)\n  Search Results: 'Leitarniðurstöður'\n  Fetching results. Please wait: 'Sæki niðurstöður. Hinkraðu aðeins'\n  Fetch more results: 'Sækja fleiri niðurstöður'\n  There are no more results for this search: 'Engar fleiri niðurstöður samsvara leitinni þinni'\n# Sidebar\n  Features:\n    HD: HD\n    Subtitles: Skjátextar\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Í beinni\n    4K: 4K\n    360 Video: 360-myndskeið\n    Location: Staðsetning\n    HDR: HDR\n    VR180: VR180\n    Features: Eiginleikar\n  Clear Filters: Hreinsa síur\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Áskriftir'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Þetta notkunarsnið er með mikinn fjölda áskrifta. Þvinga notkun á RSS til að forðast takmarkanir á magni'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Listi með áskriftum er tómur í augnablikinu. Ef þú vilt flytja inn áskriftirnar þínar, geturðu farið í stillingar gagna og valið ''Flytja inn áskriftir'' eða leitað að rás og gerst áskrifandi að henni.'\n  Load More Videos: 'Hlaða inn fleiri myndskeiðum'\n  Error Channels: Hugbúnaðarrásir með villum\n  Disabled Automatic Fetching: Þú hefur gert sjálfvirkt niðurhal áskrifta óvirkt. Endurlestu áskriftirnar og þær munu birtast hér.\n  Empty Channels: Rásirnar sem þú ert með í áskrift eru er ekki með nein myndskeið.\n  Subscriptions Tabs: Áskriftaflipar\n  All Subscription Tabs Hidden: Allir áskriftaflipar eru faldir. Til að sjá efni hér, skaltu gera einhverja flipa sýnilega í \"{subsection}\" hlutanum í \"{settingsSection}\".\n  Load More Posts: Hlaða inn fleiri færslum\n  Empty Posts: Rásirnar sem þú ert áskrifandi að eru ekki með neinar færslur.\nMore: 'Meira'\nTrending:\n  Trending: 'Í umræðunni'\n  Trending Tabs: Vinsælir flipar\n  Gaming: Leikir\n  Sports: Íþróttir\nMost Popular: 'Vinsælast'\nPlaylists: 'Spilunarlistar'\nUser Playlists:\n  Your Playlists: 'Spilunarlistarnir þínir'\n  Search bar placeholder: Leita að spilunarlistum\n  Empty Search Message: Það eru engin myndskeið í þessum spilunarlista sem samsvara leitinni þinni\n  You have no playlists. Click on the create new playlist button to create a new one.: Þú ert ekki með neina spilunarlista. Smelltu á hnappinn til að búa til nýjan spilunarlista.\n  Move Video Up: Færa myndskeið upp\n  Remove from Playlist: Fjarlægja af spilunarlista\n  Playlist Name: Heiti spilunarlista\n  Playlist Description: Lýsing spilunarlista\n  Save Changes: Vista breytingar\n  Cancel: Hætta við\n  Edit Playlist Info: Breyta upplýsingum spilunarlista\n  Sort By:\n    NameDescending: Ö-A\n    LatestCreatedFirst: Dags. útbúið (nýjast)\n    EarliestCreatedFirst: Dags. útbúið (elst)\n    LatestUpdatedFirst: Dags. uppfært (nýjast)\n    EarliestPlayedFirst: Dags. spilað (elst)\n    NameAscending: A-Ö\n    EarliestUpdatedFirst: Dags. uppfært (elst)\n    LatestPlayedFirst: Dags. spilað (nýjast)\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: Ekki er hægt að færa þetta myndskeið upp.\n      Video has been removed: Myndskeið hefur verið fjarlægt\n      There was a problem with removing this video: Það kom upp vandamál með að fjarlægja þetta myndskeið\n      Playlist has been updated.: Spilunarlisti hefur verið uppfærður.\n      There was an issue with updating this playlist.: Vandamál kom upp við að uppfæra þennan spilunarlista.\n      This playlist is protected and cannot be removed.: Þetta er varinn spilunarlisti sem ekki er hægt að fjarlægja.\n      Playlist {playlistName} has been deleted.: Spilunarlistanum {playlistName} hefur verið eytt.\n      This video cannot be moved down.: Ekki er hægt að færa þetta myndskeið niður.\n      Playlist name cannot be empty. Please input a name.: Heiti spilunarlista getur ekki verið tómt. Settu inn heiti á listann.\n      \"{videoCount} video(s) have been removed\": 1 myndskeið hefur verið fjarlægt | {videoCount} myndskeið hafa verið fjarlægð\n      There were no videos to remove.: Það eru engin myndskeið til að fjarlægja.\n      This playlist does not exist: Þessi spilunarlisti er ekki til\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Sum myndskeið í spilunarlistanum hafa ekki enn hlaðist inn. Smelltu hér til að afrita samt.\n      This playlist is now used for quick bookmark: Þessi spilunarlisti er núna notaður undir flýtibókamerki\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Þessi spilunarlisti er núna notaður undir flýtibókamerki í stað {oldPlaylistName}. Smelltu hér til að afturkalla\n      Reverted to use {oldPlaylistName} for quick bookmark: Snéri aftur í að nota {oldPlaylistName} undir flýtibókamerki\n      This playlist is already being used for quick bookmark.: Þessi spilunarlisti er nú þegar notaður undir flýtibókamerki.\n      This playlist has a video with a duration error: Spilunarlistinn inniheldur a.m.k. eitt myndskeið sem er ekki með neina tímalengd; það verður flokkað eins og tímalengdin sé núll.\n      Video has been removed. Click here to undo.: Myndskeiðið hefur verið fjarlægt. Smelltu hér til að afturkalla.\n    Search for Videos: Leita að myndskeiðum\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} valin'\n    Search in Playlists: Leita í spilunarlistum\n    Save: Vista\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Myndskeið(um) bætt við 1 spilunarlista | Myndskeið(um) bætt við {playlistCount} spilunarlista\"\n      You haven't selected any playlist yet.: Þú hefur enn ekki valið neina spilunarlista.\n    Select a playlist to add your N videos to: Veldu spilunarlista til að bæta myndskeiðinu þínu á | Veldu spilunarlista til að bæta {videoCount}̣ myndskeiðunum þínum á\n    Added {count} Times: Þegar bætt við | Bætt við {count} sinnum\n    Allow Adding Duplicate Video(s): Leyfa að tvíteknum myndskeiðum sé bætt við\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} myndskeiðum verður bætt við'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} myndskeiðum hefur þegar verið bætt við'\n  CreatePlaylistPrompt:\n    Create: Búa til\n    New Playlist Name: Heiti á nýjum spilunarlista\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Spilunarlisti með þessu heiti er þegar í notkun, veldu eitthvað annað nafn.\n      Playlist {playlistName} has been successfully created.: Tókst að útbúa spilunarlistann {playlistName}.\n      There was an issue with creating the playlist.: Vandamál kom upp við að útbúa þennan spilunarlista.\n  This playlist currently has no videos.: Þessi spilunarlisti er ekki með nein myndskeið.\n  Create New Playlist: Búa til nýjan spilunarlista\n  Add to Playlist: Bæta við spilunarlista\n  Move Video Down: Færa myndskeið niður\n  Copy Playlist: Afrita spilunarlista\n  Remove Watched Videos: Fjarlægja áhorfð myndskeið\n  Delete Playlist: Eyða spilunarlista\n  Are you sure you want to delete this playlist? This cannot be undone: Ertu viss um að þú viljir eyða þessum spilunarlista? Aðgerðin er ekki afturkallanleg.\n  Add to Favorites: Bæta í {playlistName}\n  Remove from Favorites: Fjarlægja úr {playlistName}\n  Enable Quick Bookmark With This Playlist: Virkja flýtibókamerki með þessum spilunarlista\n  Playlists with Matching Videos: Spilunarlistar með samsvarandi myndskeiðum\n  Quick Bookmark Enabled: Flýtibókamerki virkjuð\n  Remove Duplicate Videos: Fjarlægja tvítekin Myndskeið\n  Cannot delete the quick bookmark target playlist.: Tekst ekki að eyða þessum spilunarlista flýtibókamerkja.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Ertu viss um að þú viljir fjarlægja 1 tvítekið myndskeið af þessum spilunarlista? Þetta er ekki hægt að afturkalla. | Ertu viss um að þú viljir fjarlægja {playlistItemCount} tvítekin myndskeið af þessum spilunarlista? Þetta er ekki hægt að afturkalla.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Ertu viss um að þú viljir fjarlægja 1 áhorft myndskeið af þessum spilunarlista? Þetta er ekki hægt að afturkalla. | Ertu viss um að þú viljir fjarlægja {playlistItemCount} áhorfð myndskeið af þessum spilunarlista? Þetta er ekki hægt að afturkalla.\n  Export Playlist: Flytja út þennan spilunarlista\n  The playlist has been successfully exported: Það tókst að flytja út þennan spilunarlista\n  TotalTimePlaylist: 'Heildartími: {duration}'\n  Export list of URLs: Flytja út lista með vefslóðum\nHistory:\n  # On History Page\n  History: 'Áhorf'\n  Watch History: 'Áhorfsferill'\n  Your history list is currently empty.: 'Listi með áhorfsferli er tómur í augnablikinu.'\n  Search bar placeholder: Leita í áhorfsferli\n  Empty Search Message: Það eru engin myndskeið í ferlinum þínum sem samsvara leitinni þinni\n  Case Sensitive Search: Leit háð há-/lágstöfum\n  DateOldestHistory: Dags. horft á (elst)\n  DateNewestHistory: Dags. horft á (nýjast)\nSettings:\n  # On Settings Page\n  Settings: 'Stillingar'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Þú þarft að endurræsa forritið svo breytingarnar taki gildi. á að endurræsa og virkja breytingar?'\n  General Settings:\n    General Settings: 'Almennt'\n    Check for Updates: 'Athuga með uppfærslur'\n    Check for Latest Blog Posts: 'Athuga með nýjustu bloggfærslur'\n    Fallback to Non-Preferred Backend on Failure: 'Nota varaleið um ekki-forgangsbakenda þegar villa kemur upp'\n    Enable Search Suggestions: 'Virkja tillögur í leit'\n    Default Landing Page: 'Sjálfgefin upphafssíða'\n    Locale Preference: 'Umbeðin staðfærsla'\n    Preferred API Backend:\n      Preferred API Backend: 'Forgangsbakendi API-kerfisviðmóts'\n      Local API: 'Staðvært API-kerfisviðmót'\n      Invidious API: 'Invidious API-kerfisviðmót'\n    Video View Type:\n      Video View Type: 'Tegund myndskeiðsskoðunar'\n      Grid: 'Reitir'\n      List: 'Listi'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Kjörstillingar smámynda'\n      Default: 'Sjálfgefið'\n      Beginning: 'Upphaf'\n      Middle: 'Miðja'\n      End: 'Endir'\n      Hidden: Falið\n      Blur: Móska\n    View all Invidious instance information: 'Skoða allar upplýsingar um Invidious-tilvik'\n    Region for Trending: 'Landssvæði sem skal miða vinsældir við'\n        #! List countries\n    System Default: Sjálfgefið í kerfinu\n    Clear Default Instance: Hreinsa út sjálfgefið tilvik\n    Set Current Instance as Default: Stilla fyrirliggjandi tilvik sem sjálfgefið\n    Current instance will be randomized on startup: Fyrirliggjandi tilvik verður tilgreint af handahófi í ræsingu\n    No default instance has been set: Ekkert sjálfgefið tilvik hefur verið stillt\n    The currently set default instance is {instance}: 'Fyrirliggjandi sjálfgefna tilvikið er {instance}'\n    Current Invidious Instance: Fyrirliggjandi Invidious-tilvik\n    External Link Handling:\n      No Action: Ekkert gert\n      Ask Before Opening Link: Spyrja áður en tengill er opnaður\n      Open Link: Opna tengil\n      External Link Handling: Meðhöndlun ytri tengla\n    Auto Load Next Page:\n      Label: Hlaða næstu síðu sjálfvirkt\n      Tooltip: Hlaða viðbótarsíðum og athugasemdum sjálfkrafa inn.\n    Open Deep Links In New Window: Opna slóðir sem beint er til FreeTube í nýjum glugga\n    Minimize to system tray: Lágmarka í kerfisbakka\n  Theme Settings:\n    Theme Settings: 'Þema'\n    Match Top Bar with Main Color: 'Láta toppstiku samsvara aðallit'\n    Expand Side Bar by Default: 'Fletta sjálfgefið út hliðarstiku'\n    Disable Smooth Scrolling: 'Gera mjúkt skrun óvirkt'\n    UI Scale: 'Kvörðun viðmóts'\n    Base Theme:\n      Base Theme: 'Grunnþema'\n      Black: 'Svart'\n      Dark: 'Dökkt'\n      Light: 'Ljóst'\n      Dracula: 'Drakúla'\n      System Default: Sjálfgefið í kerfinu\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastelbleikt\n      Hot Pink: Dimmbleikt\n      Nordic: Norrænt\n      Solarized Dark: Sólaríserað dökkt\n      Solarized Light: Sólaríserað ljóst\n      Gruvbox Dark: Gruvbox dökkt\n      Gruvbox Light: Gruvbox ljóst\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Light Low: Everforest Ljóst-lítið\n      Everforest Dark Hard: Everforest Dökkt-skarpt\n      Everforest Dark Medium: Everforest Dökkt-miðlungs\n      Everforest Dark Low: Everforest Dökkt-lítið\n      Everforest Light Hard: Everforest Ljóst-skarpt\n      Everforest Light Medium: Everforest Ljóst-miðlungs\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Aðallitur þema'\n      Red: 'Rautt'\n      Pink: 'Bleikt'\n      Purple: 'Purpurablátt'\n      Deep Purple: 'Dökkpurpurablátt'\n      Indigo: 'Djúpfjólublátt'\n      Blue: 'Blátt'\n      Light Blue: 'Ljósblátt'\n      Cyan: 'Blágrænt'\n      Teal: 'Djúpblágrænt'\n      Green: 'Grænt'\n      Light Green: 'Ljósgrænt'\n      Lime: 'Límónugrænt'\n      Yellow: 'Gult'\n      Amber: 'Raflitt'\n      Orange: 'Appelsínugult'\n      Deep Orange: 'Dimmappelsínugult'\n      Dracula Cyan: 'Drakúla Blágrænt'\n      Dracula Green: 'Drakúla Grænt'\n      Dracula Orange: 'Drakúla Appelsínugult'\n      Dracula Pink: 'Drakúla Bleikt'\n      Dracula Purple: 'Drakúla Purpurablátt'\n      Dracula Red: 'Drakúla Rautt'\n      Dracula Yellow: 'Drakúla Gult'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha rósavatn\n      Catppuccin Mocha Flamingo: Catppuccin Mocha flamingó\n      Catppuccin Mocha Mauve: Catppuccin Mocha lillablátt\n      Catppuccin Mocha Red: Catppuccin Mocha rautt\n      Catppuccin Mocha Maroon: Catppuccin Mocha kastaníubrúnt\n      Catppuccin Mocha Green: Catppuccin Mocha grænt\n      Catppuccin Mocha Teal: Catppuccin Mocha sægrænt\n      Catppuccin Mocha Sky: Catppuccin Mocha himinblátt\n      Catppuccin Mocha Blue: Catppuccin Mocha blátt\n      Catppuccin Mocha Lavender: Catppuccin Mocha lavander\n      Catppuccin Mocha Pink: Catppuccin Mocha bleikt\n      Catppuccin Mocha Peach: Catppuccin Mocha ferskju\n      Catppuccin Mocha Yellow: Catppuccin Mocha gult\n      Catppuccin Mocha Sapphire: Catppuccin Mocha safír\n      Solarized Violet: Sólaríserað fjólublátt\n      Solarized Blue: Sólaríserað blátt\n      Solarized Cyan: Sólaríserað blágrænt\n      Solarized Yellow: Sólaríserað gult\n      Solarized Orange: Sólaríserað appelsínugult\n      Solarized Magenta: Sólaríserað blárautt\n      Solarized Red: Sólaríserað rautt\n      Solarized Green: Sólaríserað grænt\n      Gruvbox Dark Green: Gruvbox dökkgrænt\n      Gruvbox Dark Yellow: Gruvbox dökkgult\n      Gruvbox Dark Aqua: Gruvbox dökksægrænt\n      Gruvbox Light Red: Gruvbox ljósrautt\n      Gruvbox Light Blue: Gruvbox ljósblátt\n      Gruvbox Light Purple: Gruvbox ljósfjólublátt\n      Gruvbox Light Orange: Gruvbox ljósappelsínugult\n      Gruvbox Dark Orange: Gruvbox dökkappelsínugult\n      Gruvbox Dark Blue: Gruvbox dökkblátt\n      Gruvbox Dark Purple: Gruvbox dökkfjólublátt\n      Catppuccin Frappe Lavender: Catppuccin Frappe lavander\n      Catppuccin Frappe Rosewater: Catppuccin Frappe rósavatn\n      Catppuccin Frappe Flamingo: Catppuccin Frappe flamingó\n      Catppuccin Frappe Pink: Catppuccin Frappe bleikt\n      Catppuccin Frappe Mauve: Catppuccin Frappe lillablátt\n      Catppuccin Frappe Red: Catppuccin Frappe rautt\n      Catppuccin Frappe Maroon: Catppuccin Frappe kastaníubrúnt\n      Catppuccin Frappe Peach: Catppuccin Frappe ferskju\n      Catppuccin Frappe Yellow: Catppuccin Frappe gult\n      Catppuccin Frappe Green: Catppuccin Frappe grænt\n      Catppuccin Frappe Teal: Catppuccin Frappe sægrænt\n      Catppuccin Frappe Sky: Catppuccin Frappe himinblátt\n      Catppuccin Frappe Sapphire: Catppuccin Frappe safír\n      Catppuccin Frappe Blue: Catppuccin Frappe blátt\n      Everforest Dark Red: Everforest Dökkrautt\n      Everforest Dark Orange: Everforest Dökkappelsínugult\n      Everforest Dark Yellow: Everforest Dökkgult\n      Everforest Dark Green: Everforest Dökkgrænt\n      Everforest Dark Aqua: Everforest Dökksægrænt\n      Everforest Dark Purple: Everforest Dökkpurpuralitað\n      Everforest Dark Blue: Everforest Dökkblátt\n      Everforest Light Red: Everforest Ljósrautt\n      Everforest Light Orange: Everforest Ljósappelsínugult\n      Everforest Light Yellow: Everforest Ljósgult\n      Everforest Light Green: Everforest Ljósgrænt\n      Everforest Light Aqua: Everforest Ljóssægrænt\n      Everforest Light Blue: Everforest Ljósblátt\n      Everforest Light Purple: Everforest Ljóspurpuralitað\n      Catppuccin Latte Mauve: Catppuccin Latte fjólublár\n      Catppuccin Latte Red: Catppuccin Latte rautt\n    Secondary Color Theme: 'Aukalitur þema'\n        #* Main Color Theme\n    Hide Side Bar Labels: Fela skýringar á hliðarstiku\n    Hide FreeTube Header Logo: Fela táknmynd FreeTube í haus\n  Player Settings:\n    Player Settings: 'Spilari'\n    Play Next Video: 'Spila sjálfkrafa myndskeið sem mælt er með'\n    Turn on Subtitles by Default: 'Sjálfgefið virkja skjátexta'\n    Autoplay Videos: 'Ræsa myndskeið sjálfkrafa'\n    Proxy Videos Through Invidious: 'Beina myndskeiðum í gegnum Invidious-milliþjón'\n    Autoplay Playlists: 'Spila sjálfkrafa myndskeið í spilunarlista'\n    Enable Theatre Mode by Default: 'Sjálfgefið virkja bíóham (theater mode)'\n    Default Volume: 'Sjálfgefinn hljóðstyrkur'\n    Default Playback Rate: 'Sjálfgefinn afspilunarhraði'\n    Default Video Format:\n      Default Video Format: 'Sjálfgefið skráasnið myndskeiða'\n      Dash Formats: 'DASH-skráasnið'\n      Legacy Formats: 'Eldri skráasnið'\n      Audio Formats: 'Hljóðskráasnið'\n    Default Quality:\n      Default Quality: 'Sjálfgefin gæði'\n      Auto: 'Sjálfvirkt'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Niðurtalning í sjálfvirka spilun\n    Display Play Button In Video Player: Birta afspilunarhnapp í myndspilara\n    Scroll Volume Over Video Player: Skruna hljóðstyrk ofan á myndspilara\n    Fast-Forward / Rewind Interval: Millibil hraðspólunar / spóla til baka\n    Scroll Playback Rate Over Video Player: Skruna afspilunarhraða ofan á myndspilara\n    Video Playback Rate Interval: Hámarksbil milli afspilunar myndskeiða\n    Max Video Playback Rate: Hámarkshraði afspilunar myndskeiða\n    Screenshot:\n      Enable: Virkja skjámyndatöku\n      Format Label: Snið skjámynda\n      Quality Label: Gæði skjámynda\n      Error:\n        Forbidden Characters: Bannaðir stafir\n        Empty File Name: Autt skráaheiti\n      File Name Tooltip: Þú getur notað breyturnar hér fyrir neðan. %Y ár 4-stafa. %M mánuður 2-stafa. %D dagur 2-stafa. %H klukkustundir 2-stafa. %N mínútur 2-stafa. %S sekúndur 2-stafa. %T millísekúndur 3-stafa. %s sekúndur í myndskeiði. %t millísekúndur í myndskeiði 3-stafa. %i auðkenni myndskeiðs.\n      Ask Path: Spyrja um möppu til að vista í\n      Folder Label: Mappa undir skjámyndir\n      Folder Button: Veldu möppu\n      File Name Label: Mynstur skráaheita\n    Enter Fullscreen on Display Rotate: Fara í skjáfylli við snúning á skjá\n    Skip by Scrolling Over Video Player: Sleppa með því að skruna ofan á myndspilara\n    Autoplay Interruption Timer: Niðurtalning í stöðvun á sjálfvirkri spilun\n    Default Viewing Mode:\n      Theater: Bíóhamur\n      Default Viewing Mode: Sjálfgefinn skoðunarhamur\n      Full Screen: Skjáfylli\n      Picture in Picture: Mynd-í-mynd\n      External Player: Utanaðkomandi spilari ({externalPlayerName})\n  Privacy Settings:\n    Privacy Settings: 'Gagnaleynd'\n    Remember History: 'Muna áhorfsferil'\n    Save Watched Progress: 'Vista framvindu áhorfs'\n    Clear Search Cache: 'Hreinsa skyndiminni leitar'\n    Are you sure you want to clear out your search cache?: 'Ertu viss um að þú viljir eyða skyndiminni leitar?'\n    Search cache has been cleared: 'Skyndiminni leitar var hreinsað'\n    Remove Watch History: 'Fjarlægja áhorfsferil'\n    Are you sure you want to remove your entire watch history?: 'Ertu viss um að þú viljir fjarlægja allan áhorfsferilinn þinn?'\n    Watch history has been cleared: 'Áhorfsferill var hreinsaður'\n    Remove All Subscriptions / Profiles: 'Fjarlægja allar áskriftir / notkunarsnið'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Ertu viss um að þú viljir fjarlægja allar áskriftir og notkunarsnið? Ekki er hægt að afturkalla þetta.'\n    Save Watched Videos With Last Viewed Playlist: Vista myndskeið sem horft var á með síðast notaða spilunarlista\n    Remove All Playlists: Fjarlægja alla spilunarlista\n    Are you sure you want to remove all your playlists?: Ertu viss um að þú viljir fjarlægja alla spilunarlistana þína?\n    All playlists have been removed: Allir spilunarlistar hafa verið fjarlægðir\n    Clear Search History and Cache: Hreinsa leitarferil og biðminni\n    Are you sure you want to clear out your search history and cache?: Ertu viss um að þú viljir hreinsa leitarferilinn þinn og biðminnið?\n    Search history and cache have been cleared: Leitarferill og biðminni hafa verið hreinsuð\n    Remember Search History: Muna leitarferil\n    Watched Progress Saving Mode:\n      Tooltip: Sjálfvirkt = Vista alltaf þegar farið er af síðu myndskeiðs, þegar myndskeiði lýkur og rekist er á villu (t.d. magntakmörk og áhorfsseta er útrunnin). Hálfsjálfvirkt = Eins og 'Sjálfvirkt' nema aðeins þegar farið er af síðu myndskeiðs en hægt að vista áhorf handvirkt með hnappi sem kallast 'Vista áhorfsferil', sem staðsettur er neðan við spilarann.\n      Modes:\n        Auto: Sjálfvirkt\n        Semi-auto: Hálfsjálfvirkt\n        Never: Aldrei\n  Subscription Settings:\n    Subscription Settings: 'Áskrift'\n    Fetch Feeds from RSS: 'Ná í streymi úr RSS'\n    Fetch Automatically: Sækja streymi sjálfvirkt\n    Confirm Before Unsubscribing: Staðfesta uppsögn áskriftar\n    To: Við\n    'Limit the number of videos displayed for each channel': Takmarka fjölda myndskeiða sem birt eru fyrir hverja rás\n  Distraction Free Settings:\n    Distraction Free Settings: 'Truflanaminnkandi'\n    Hide Video Views: 'Fela fjölda áhorfa á myndskeið'\n    Hide Video Likes And Dislikes: 'Fela hve mörgum líkar eða mislíkar myndskeið'\n    Hide Channel Subscribers: 'Fela fjölda áskrifenda myndskeiða'\n    Hide Comment Likes: 'Fela hve mörgum líkar athugasemdir'\n    Hide Recommended Videos: 'Fela myndskeið sem mælt er með'\n    Hide Trending Videos: 'Fela myndskeið í umræðunni'\n    Hide Popular Videos: 'Fela vinsæl myndskeið'\n    Hide Playlists: 'Fela spilunarlista'\n    Hide Live Chat: 'Fela spjall í beinni'\n    Hide Active Subscriptions: 'Fela virkar áskriftir'\n    Hide Live Streams: Fela streymi í beinni\n    Hide Sharing Actions: Fela deiliaðgerðir\n    Hide Videos on Watch: 'Fela myndskeið eftir áhorf'\n    Hide Video Description: Fela lýsingu á myndskeiði\n    Hide Comments: Fela athugasemdir\n    Hide Chapters: Fela kafla\n    Hide Upcoming Premieres: Fela væntanlegar frumsýningar\n    Hide Channels: Fela myndskeið úr rásum\n    Hide Channels Placeholder: Auðkenni rásar\n    Display Titles Without Excessive Capitalisation: Birta titla án umfram-hástafa og greinarmerkja\n    Sections:\n      Side Bar: Hliðarspjald\n      Channel Page: Rásasíða\n      Watch Page: Áhorfssíða\n      General: Almennt\n      Subscriptions Page: Áskriftasíða\n    Hide Channel Shorts: Fela símamyndaflipa rása\n    Hide Channel Playlists: Fela spilunarlistaflipa rása\n    Hide Featured Channels: Fela rásir í deiglunni\n    Hide Channel Podcasts: Fela hlaðvarpsflipa rása\n    Hide Channel Releases: Fela útgáfuflipa rása\n    Hide Subscriptions Shorts: Fela símamyndir áskrifta\n    Hide Subscriptions Live: Fela bein streymi áskrifta\n    Hide Subscriptions Videos: Fela myndskeið áskrifta\n    Hide Profile Pictures in Comments: Fela auðkennismyndir í athugasemdum\n    Hide Channels Invalid: Uppgefið auðkenni rásar er ógilt\n    Hide Channels Disabled Message: Sumar rásir voru útilokaðar út frá auðkenni og voru ekki meðhöndlaðar. Lokað er á eiginleikann á meðan verið er að uppfæra þessi auðkenni\n    Hide Channels Already Exists: Auðkenni rásar er þegar til\n    Hide Channels API Error: Villa við að ná í notanda með uppgefið auðkenni. Athugaðu aftur hvort auðkennið ré rétt.\n    Hide Videos, Playlists and Channels Containing Text: Fela myndskeið og spilunarlista sem innihalda texta\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Orð, orðhluti eða setning\n    Hide Channel Home: Fela \"Heim\"-flipa rása\n    Show Added Items: Sýna atriði sem bætt hefur verið við\n    Hide Channel Courses: Fela flipann með rásinni \"Kennsluefni\"\n    Hide Channel Posts: Fela \"Færslur\"-flipa rása\n    Hide Subscriptions Posts: Fela áskriftarfærslur\n  Data Settings:\n    Data Settings: 'Gögn'\n    Select Export Type: 'Veldu tegund útflutnings'\n    Import Subscriptions: 'Flytja inn áskriftir'\n    Export Subscriptions: 'Flytja út áskriftir'\n    Export FreeTube: 'Flytja út FreeTube'\n    Export YouTube: 'Flytja út YouTube'\n    Export NewPipe: 'Flytja út NewPipe'\n    Import History: 'Flytja inn áhorfsferil'\n    Export History: 'Flytja út áhorfsferil'\n    Profile object has insufficient data, skipping item: 'Atriði notkunarsniðs er ekki með næg gögn, sleppi þessu'\n    All subscriptions and profiles have been successfully imported: 'Innflutningur á öllum áskriftum og notkunarsniðum tókst'\n    All subscriptions have been successfully imported: 'Innflutningur á öllum áskriftum tókst'\n    Invalid subscriptions file: 'Ógild áskriftaskrá'\n    Invalid history file: 'Ógild áhorfsferilskrá'\n    Subscriptions have been successfully exported: 'Úflutningur á áskriftum tókst'\n    History object has insufficient data, skipping item: 'Atriði áhorfsferils er ekki með næg gögn, sleppi þessu'\n    All watched history has been successfully imported: 'Allur áhorfsferillinn var fluttur inn'\n    All watched history has been successfully exported: 'Allur áhorfsferillinn var fluttur út'\n    Unable to read file: 'Gat ekki lesið skrá'\n    Unable to write file: 'Gat ekki skrifað skrá'\n    Unknown data key: 'Óþekktur gagnalykill'\n    How do I import my subscriptions?: 'Hvernig flyt ég inn áskriftirnar mínar?'\n    Manage Subscriptions: 'Sýsla með áskriftir'\n    Import Playlists: Flytja inn spilunarlista\n    Export Playlists: Flytja út spilunarlista\n    Playlist insufficient data: Ónóg gögn fyrir \"{playlist}\" spilunarlista, sleppi atriðinu\n    All playlists has been successfully imported: Tekist hefur að flytja inn alla spilunarlista\n    All playlists has been successfully exported: Tekist hefur að flytja út alla spilunarlista\n    Subscription File: Skrá með áskriftum\n    History File: Skrá með atvikaferli\n    Playlist File: Spilunarlistaskrá\n    Export Playlists For Older FreeTube Versions:\n      Label: Flytja út spilunarlista fyrir eldri útgáfur FreeTube\n      Tooltip: \"Þessi valkostur flytur út myndskeið úr öllum spilunarlistum inn í einn spilunarlista sem kallast 'Eftirlæti'.\\nHér er skýrt hvernig eigi að flytja út eða inn myndskeið í spilunarlistum fyrir eldri útgáfur FreeTube:\\n 1. Flyttu út spilunarlistana þína með þennan valkost virkann.\\n2. Eyddu út öllum fyrirliggjandi spilunarlistum hjá þér með valkostinum 'Fjarlægja alla spilunarlista' í stillingum gagnaleyndar.\\n3. Ræstu eldri útgáfu FreeTube og flyttu inn spilunarlistana sem þú fluttir út.\\\"\"\n    Search history file: Leita í ferilskrá\n    Search history: Leitarferill\n    Import search history: Flytja inn leitarferil\n    Export search history: Flytja út leitarferil\n    All search history has been successfully imported: Allur leitarferill hefur verið fluttur inn\n    All search history has been successfully exported: Allur leitarferill hefur verið fluttur út\n  Proxy Settings:\n    Proxy Settings: 'Milliþjónn (proxy)'\n    Enable Tor / Proxy: 'Virkja Tor / milliþjón'\n    Proxy Protocol: 'Samskiptamáti milliþjóns'\n    Proxy Host: 'Hýsilvél milliþjóns'\n    Proxy Port Number: 'Númer á gátt milliþjóns'\n    Clicking on Test Proxy will send a request to: 'Ef smellt er á ''Prófa milliþjón'' verður send beiðni á'\n    Test Proxy: 'Prófa milliþjón'\n    Your Info: 'Upplýsingar um þig'\n    Ip: 'IP-vistfang'\n    Country: 'Land'\n    Region: 'Hérað'\n    City: 'Borg/Sveitarfélag'\n    Error getting network information. Is your proxy configured properly?: 'Það tókst ekki að sækja upplýsingar um netkerfið. Er milliþjónninn rétt uppsettur?'\n    Proxy Warning: FreeTube er ekki með innbyggðan milliþjón en getur tengst við utanaðkomandi milliþjóna, til dæmis einhvern sem keyrir á vélinni þinni eins og Tor eða fjartengdan milliþjón á borð við SOCKS5-milliþjóna sem sumar VPN-þjónustur bjóða. Ef þetta er virkt skaltu ganga úr skugga um að milliþjónninn/Tor sé rétt stillt, annars mun FreeTube ekki geta sótt nein gögn.\n    Proxy Username: Notandanafn á milliþjóni\n    Proxy Password: Lykilorð á milliþjóni\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Láta vita þegar kostaður hluti er hunsaður\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API-slóð (sjálfgefið er https://sponsor.ajay.app)\n    Enable SponsorBlock: Virkja SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Valkostir við hunsun\n      Auto Skip: Hunsa sjálfvirkt\n      Show In Seek Bar: Sýna í leitarstiku\n      Prompt To Skip: Spyrja hvort eigi að sleppa\n      Do Nothing: Gera ekkert\n    Category Color: Litur flokks\n    UseDeArrowTitles: Nota DeArrow myndskeiðatitla\n    UseDeArrowThumbnails: Nota DeArrow fyrir smámyndir\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': Slóð á API-kerfisviðmót DeArrow Thumbnail Generator smámyndagerðar (sjálfgefið er https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Sérsniðin viðföng fyrir utanaðkomandi spilara\n    Custom External Player Executable: Sérsniðin skipun fyrir utanaðkomandi spilara\n    Ignore Unsupported Action Warnings: Hunsa aðvarinir vegna óstuddra aðgerða\n    External Player: Utanaðkomandi spilari\n    External Player Settings: Utanaðkomandi spilari\n    Players:\n      None:\n        Name: Ekkert\n    Ignore Default Arguments: Hunsa sjálfgefnar breytur\n  Parental Control Settings:\n    Hide Unsubscribe Button: Fela hnapp til að segja upp áskrift\n    Show Family Friendly Only: Aðeins sýna fjölskylduvænt efni\n    Hide Search Bar: Fela leitarstiku\n    Parental Control Settings: Foreldrastýringar\n    Hide Uploader on Watch page: Fela innsendingarsvæði á vöktunarsíðu\n  Experimental Settings:\n    Experimental Settings: Á tilraunastigi\n    Warning: Þessar stillingar eru á tilraunastigi, þær geta valdið hruni þegar þær eru virkjaðar. Mælt er með því að öryggisafrit séu tekin. Notist á eigin ábyrgð!\n    Replace HTTP Cache: Skipta út HTTP-skyndiminni\n  Password Dialog:\n    Password: Lykilorð\n    Enter Password To Unlock: Settu inn lykilorð til að aflæsa stillingum\n  Password Settings:\n    Set Password To Prevent Access: Settu lykilorð til að hindra aðgang að stillingum\n    Set Password: Setja lykilorð\n    Remove Password: Fjarlægja lykilorð\n    Password Settings: Lykilorð\n  Sort Settings Sections (A-Z): Röðun stillingahluta (A-Ö)\n  Return to Settings Menu: Fara aftur í stillingavalmynd\nAbout:\n  #On About page\n  About: 'Um hugbúnaðinn'\n  Beta: 'Beta-prófunarútgáfa'\n  Source code: 'Grunnkóði'\n  Downloads / Changelog: 'Sóttar skrár / Breytingaskrá'\n  GitHub releases: 'Útgáfur af GitHub'\n  Help: 'Hjálp'\n  FreeTube Wiki: 'FreeTube wikivefur'\n  FAQ: 'FAQ / Algengar spurningar'\n  Report a problem: 'Tilkynna vandamál'\n  GitHub issues: 'GitHub verkbeiðnir'\n  Please check for duplicates before posting: 'Athugaðu hvort fyrir séu eins fyrirspurnir áður en þú sendir nýja'\n  Website: 'Vefsvæði'\n  Blog: 'Blogg'\n  Email: 'Tölvupóstur'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Spjall á Matrix'\n  room rules: 'reglur spjallsins'\n  Translate: 'Þýða'\n  Credits: 'Framlög'\n  these people and projects: 'þessu fólki og verkefnum'\n  Donate: 'Styrkja'\n\n  Discussions: Umræður\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Notkunarleyfi samkvæmt {licenseLink}\n  Please read the {roomRulesLink}: Þú ættir endilega að lesa {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube er gert mögulegt af {creditsPageLink}\nProfile:\n  Profile Select: 'Val á notkunarsniði'\n  Profile Filter: 'Sía notkunarsnið'\n  All Channels: 'Allar rásir'\n  Profile Manager: 'Sýsla með notkunarsnið'\n  Create New Profile: 'Búa til nýtt notkunarsnið'\n  Edit Profile: 'Breyta notkunarsniði'\n  Color Picker: 'Litaplokkari'\n  Custom Color: 'Sérsniðinn litur'\n  Profile Preview: 'Forskoðun notkunarsniðs'\n  Create Profile: 'Búa til notkunarsnið'\n  Update Profile: 'Uppfæra notkunarsnið'\n  Make Default Profile: 'Gera að sjálfgefnu notkunarsniði'\n  Delete Profile: 'Eyða notkunarsniði'\n  Are you sure you want to delete this profile?: 'Ertu viss um að þú viljir eyða þessu notkunarsniði?'\n  All subscriptions will also be deleted.: 'Öllum áskriftum verður einnig eytt.'\n  Your profile name cannot be empty: 'Nafn notkunarsniðsins má ekki vera tómt'\n  Profile has been created: 'Notkunarsnið hefur verið útbúið'\n  Profile has been updated: 'Notkunarsnið hefur verið uppfært'\n  Your default profile has been set to {profile}: 'Sjálfgefið notandasnið þitt hefur stillt sem {profile}'\n  Removed {profile} from your profiles: 'Fjarlægði {profile} úr notkunarsniðunum þínum'\n  Your default profile has been changed to your primary profile: 'Sjálfgefið notandasnið þitt hefur stillt á aðalnotkunarsniðið þitt'\n  '{profile} is now the active profile': '{profile} er núna virka notkunarsniðið'\n  Subscription List: 'Áskriftalisti'\n  Other Channels: 'Aðrar rásir'\n  '{number} selected': '{number} valið'\n  Select All: 'Velja allt'\n  Select None: 'Velja ekkert'\n  Delete Selected: 'Eyða völdu'\n  Add Selected To Profile: 'Breyta völdu við notkunarsnið'\n  No channel(s) have been selected: 'Engin rás hefur verið valin'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Þetta er aðalnotkunarsnið þitt. Ertu viss um að þú viljir eyða völdu rásunum? Þessum sömu rásum verður eytt úr öllum þeim notkunarsniðum þar sem þær finnast.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ertu viss um að þú viljir eyða völdu rásunum? Þetta mun ekki eyða rásunum úr öðrum notkunarsniðum.'\n#On Channel Page\n  Profile Settings: Notkunarsnið\n  Toggle Profile List: Víxla lista með notkunarsniðum af/á\n  Profile Name: Heiti notkunarsniðs\n  Edit Profile Name: Breyta heiti notkunarsniðs\n  Create Profile Name: Útbúa heiti á notkunarsnið\n  Open Profile Dropdown: Opna fellivalmynd notkunarsniðs\n  Close Profile Dropdown: Loka fellivalmynd notkunarsniðs\nChannel:\n  Subscribe: 'Gerast áskrifandi'\n  Unsubscribe: 'Segja upp áskrift'\n  Channel has been removed from your subscriptions: 'Rás var fjarlægð úr áskriftunum þínum'\n  Removed subscription from {count} other channel(s): 'Fjarlægði áskrift úr {count} rás(um) til viðbótar'\n  Added channel to your subscriptions: 'Bætti rás í áskriftirnar þínar'\n  Search Channel: 'Leita á rás'\n  Your search results have returned 0 results: 'Leitin skilaði 0 niðurstöðum'\n  Videos:\n    Videos: 'Myndskeið'\n    This channel does not currently have any videos: 'Þessi rás er ekki með nein myndskeið'\n    Sort Types:\n      Newest: 'Nýjast'\n      Oldest: 'Elst'\n      Most Popular: 'Vinsælast'\n  Playlists:\n    Playlists: 'Spilunarlistar'\n    This channel does not currently have any playlists: 'Þessi rás er ekki með neina spilunarlista'\n    Sort Types:\n      Last Video Added: 'Síðast viðbætta myndskeið'\n      Newest: 'Nýjast'\n      Oldest: 'Elst'\n  About:\n    About: 'Um rásina'\n    Channel Description: 'Lýsing á rás'\n    Featured Channels: 'Rásir í deiglunni'\n    Tags:\n      Tags: Merki\n      Search for: Leita að „{tag}“\n    Details: Nánar\n    Joined: Skráði sig\n    Location: Staðsetning\n  This channel does not exist: Þessi rás er ekki til\n  This channel does not allow searching: Þessi rás gefur ekki kost á að leita\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Þessi rás er með aldurstakmark og er í augnablikinu ekki hægt að skoða í FreeTube.\n  Channel Tabs: Rásaflipar\n  Live:\n    Live: Í beinni\n    This channel does not currently have any live streams: Þessi rás er í augnablikinu ekki með nein bein streymi\n  Posts:\n    This channel currently does not have any posts: Þessi rás er ekki með neinar færslur\n    Reveal Answers: Birta svör\n    Hide Answers: Fela svör\n    votes: '{votes} atkvæði'\n    Video hidden by FreeTube: Myndskeið falið af FreeTube\n    View Full Post: Skoða alla færsluna\n    Viewing Posts Only Supported By Invidious: Einungis er hægt að skoða innsendar færslur á Invidious. Farðu á samfélagsflipa rásar til að skoða efni þar án Invidious.\n  Shorts:\n    This channel does not currently have any shorts: Þessi rás er í augnablikinu ekki með neinar símamyndir\n  Releases:\n    Releases: Útgáfur\n    This channel does not currently have any releases: Þessi rás er ekki með neinar útgáfur í augnablikinu\n  Podcasts:\n    Podcasts: Hlaðvörp\n    This channel does not currently have any podcasts: Þessi rás er ekki með nein hlaðvörp í augnablikinu\n  Home:\n    Home: Heim\n    View Playlist: Skoða spilunarlista\n  Courses:\n    Courses: Kennsluefni\n    This channel does not currently have any courses: Þessi rás er ekki með neitt kennsluefni\nVideo:\n  Mark As Watched: 'Merkja sem búið að horfa á'\n  Remove From History: 'Fjarlægja úr áhorfsferli'\n  Video has been marked as watched: 'Myndskeið hefur verið merkt sem skoðað'\n  Video has been removed from your history: 'Myndskeið hefur verið fjarlægt úr áhorfsferlinum þínum'\n  Save Video: 'Vista myndskeið'\n  Video has been saved: 'Myndskeið hefur verið vistað'\n  Video has been removed from your saved list: 'Myndskeið hefur verið fjarlægt úr listanum yfir vistað'\n  Open in YouTube: 'Opna í YouTube'\n  Copy YouTube Link: 'Afrita YouTube-tengil'\n  Open YouTube Embedded Player: 'Opna ívafinn YouTube-spilara'\n  Copy YouTube Embedded Player Link: 'Afrita tengil á ívafinn YouTube-spilara'\n  Open in Invidious: 'Opna í Invidious'\n  Copy Invidious Link: 'Afrita Invidious-tengil'\n  Open Channel in YouTube: 'Opna rás í YouTube'\n  Copy YouTube Channel Link: 'Afrita tengil YouTube-rásar'\n  Open Channel in Invidious: 'Opna rás í Invidious'\n  Copy Invidious Channel Link: 'Afrita tengil Invidious-rásar'\n  Views: 'Áhorf'\n  Loop Playlist: 'Endurtaka spilunarlista endalaust'\n  Shuffle Playlist: 'Stokka spilunarlista'\n  Reverse Playlist: 'Snúa við spilunarlista'\n  Previous: 'Spila aftur'\n  Next: 'Næsta'\n  Watched: 'Búið að horfa'\n  Autoplay: 'Spila sjálfkrafa'\n  Starting soon, please refresh the page to check again: 'Byrjar bráðum, endurlestu síðuna til að fylgjast með'\n  # As in a Live Video\n  Live: 'Beint'\n  Live Now: 'Í beinni útsendingu núna'\n  Live Chat: 'Spjall í beinni'\n  Enable Live Chat: 'Virkja spjall í beinni'\n  Live Chat is currently not supported in this build.: 'Spjall í beinni er ekki stutt í þessari byggingarútgáfu.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Beint spjall er virkt. Skilaboð spjallsins munu birtast hér.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Spjall í beinni er ekki stutt í Invidious API-kerfisviðmótinu. Nauðsynlegt er að vera með beina tengingu við YouTube.'\n  Published:\n    In less than a minute: eftir minna en mínútu\n  Published on: 'Gefið út'\n  Streamed on: 'Streymt'\n  Started streaming on: 'Byrjaði streymi'\n#& Videos\n  Sponsor Block category:\n    music offtopic: Tónlist óskyld efni\n    interaction: Gagnvirkni\n    self-promotion: Sjálfskynning\n    intro: Kynning\n    sponsor: Kostunaraðili\n    outro: Afkynning\n    recap: Upprifjun\n    filler: Uppfylling\n  External Player:\n    Unsupported Actions:\n      looping playlists: endurtaka spilunarlista\n      shuffling playlists: stokka spilunarlista\n      reversing playlists: snúa við spilunarlistum\n      opening playlists: opna spilunarlista\n      setting a playback rate: stilla hraða afspilunar\n      starting video at offset: byrja myndskeið á hliðrun\n      opening specific video in a playlist (falling back to opening the video): opna tiltekið myndskeið í spilunarlista (til vara að opna myndskeiðið)\n    UnsupportedActionTemplate: '{externalPlayer} styður ekki: {action}'\n    OpeningTemplate: Opna {videoOrPlaylist} eftir {externalPlayer}...\n    playlist: spilunarlisti\n    video: myndskeið\n    OpenInTemplate: Opna í {externalPlayer}\n  Premieres: Frumsýnt\n  Show Super Chat Comment: Birta athugasemd Super Chat\n  Scroll to Bottom: Skruna neðst\n  Upcoming: Á næstunni\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Spjall í beinni er ekki tiltækt fyrir þetta streymi. Sá sem sendi þetta inn gæti hafa gert það óvirkt.\n  Unhide Channel: Birta rás\n  Hide Channel: Fela rás\n  More Options: Fleiri valkostir\n  Player:\n    Stats:\n      Player Dimensions: 'Stærðir spilara: {width}x{height}'\n      Bitrate: 'Bitahraði: {bitrate} kbps'\n      Resolution: 'Upplausn: {width}x{height}{''@''}{frameRate}'\n      Volume: 'Hljóðstyrkur: {volumePercentage}%'\n      Stats: Tölfræði\n      Bandwidth: 'Bandbreidd: {bandwidth} kbps'\n      Buffered: 'Biðminni: {bufferedPercentage}%'\n      CodecsVideoAudio: 'Kóðunarlyklar: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Kóðunarlyklar: {videoCodec} / {audioCodec}'\n      Video ID: 'Auðkenni myndskeiðs: {videoId}'\n      Media Formats: 'Snið efnis: {formats}'\n      CodecAudio: 'Kóðunarlykill: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Römmum sleppt: {droppedFrames} / Rammar alls: {totalFrames}'\n    TranslatedCaptionTemplate: '{language} (þýtt úr \"{originalLanguage}\")'\n    Take Screenshot: Taka skjámynd\n    Hide Stats: Fela tölfræði\n    Show Stats: Birta tölfræði\n    Audio Tracks: Hljóðrásir\n    Full Window: Skjáfylli\n    You appear to be offline: Þú virðist ekki vera með tengingu við netið.\n    Skipped segment: Sleppti {segmentCategory} bút\n    Exit Full Window: Hætta í skjáfylli\n    Playback will resume automatically when your connection comes back: Afspilun heldur sjálfkrafa áfram þegar tenging næst aftur.\n    Exit Theatre Mode: Fara út úr bíóham\n    Theatre Mode: Bíóhamur\n    Autoplay is off: Slökkt er á sjálfvirkri afspilun\n    Autoplay is on: Kveikt er á sjálfvirkri afspilun\n  Unlisted: Óskráð\n  MembersOnly: Ekki er hægt að horfa á myndskeið einungis fyrir meðlimi með FreeTube þar sem þau krefjast innskráningar á Google og greiddu þátttökugjaldi á rás innsendandans.\n  AgeRestricted: Ekki er hægt að horfa á aldurstakmörkuð myndskeið með FreeTube þar sem þau krefjast innskráningar á Google og notkunar á aldursvottuðum YouTube-reikningi.\n  IP block: YouTube hefur útilokað IP-vistfang þitt frá því að horfa á myndskeið. Prófaðu að skipta yfir á annan VPN eða milliþjón.\n  DeArrow:\n    Show Original Details: Birta upprunalegar nánari upplýsingar\n    Show Modified Details: Birta breyttar nánari upplýsingar\n  DRMProtected: Ekki er hægt að spila DRM-varin myndskeið í FreeTube, þar sem þau krefjast notkunar lokaðs séreignarhugbúnaðar. Ef þú vilt endilega horfa á þetta myndskeið, skaltu gera það á opinbera YouTube-vefsvæðinu í vafra með uppsettum DRM-hugbúnaði.\n#& Playlists\n  Save Watched Progress: Vista áhorfsferil\n  Watched Progress Saved: Áhorfsferill vistaður\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Tími sem eftir er af forkeyrslu auglýsingar: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Tími sem eftir er af bakkeyrslu SABR: {remindingTimeSeconds}s'\n  Popout Live Chat: Spjall í sprettglugga\nPlaylist:\n  #& About\n  View Full Playlist: 'Sjá allan spilunarlistann'\n  Last Updated On: 'Síðast uppfært'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Spilunarlisti\n  Sort By:\n    AuthorAscending: Höfundur (A-Ö)\n    DateAddedNewest: Dags. bætt við (nýjast)\n    AuthorDescending: Höfundur (Ö-A)\n    VideoTitleAscending: Titill (A-Ö)\n    VideoTitleDescending: Titill (Ö-A)\n    Custom: Sérsniðið\n    DateAddedOldest: Dags. bætt við (elst)\n    VideoDurationAscending: Tímalengd (styst)\n    VideoDurationDescending: Tímalengd (lengst)\n    PublishedOldest: Dags. gefið út (elst)\n    PublishedNewest: Dags. gefið út (nýjast)\nChange Format:\n  Change Media Formats: 'Skipta um myndskeiðasnið'\n  Use Dash Formats: 'Nota DASH-skráasnið'\n  Use Legacy Formats: 'Nota eldri skráasnið'\n  Use Audio Formats: 'Nota hljóðskráasnið'\n  Dash formats are not available for this video: 'DASH-skráasnið eru ekki tiltæk fyrir þetta myndskeið'\n  Audio formats are not available for this video: 'Hljóðskráasnið eru ekki tiltæk fyrir þetta myndskeið'\n  Legacy formats are not available for this video: Eldri snið eru ekki tiltæk fyrir þetta myndskeið\nShare:\n  Share Video: 'Deila myndskeiði'\n  Share Playlist: 'Deila spilunarlista'\n  Include Timestamp: 'Hafa með tímamerki'\n  Copy Link: 'Afrita tengil'\n  Open Link: 'Opna tengil'\n  Copy Embed: 'Afrita ívafið'\n  Open Embed: 'Opna ívafið'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-slóð afrituð á klippispjaldið'\n  Invidious Embed URL copied to clipboard: 'Ívafin Invidious-slóð afrituð á klippispjaldið'\n  Invidious Channel URL copied to clipboard: 'Slóð Invidious-rásar afrituð á klippispjaldið'\n  YouTube URL copied to clipboard: 'YouTube-slóð afrituð á klippispjaldið'\n  YouTube Embed URL copied to clipboard: 'Ívafin YouTube-slóð afrituð á klippispjaldið'\n  YouTube Channel URL copied to clipboard: 'Slóð YouTube-rásar afrituð á klippispjaldið'\n\n  Share Channel: Deila rás\n  Share Post: Deila færslu\nMini Player: 'Smáspilari'\nComments:\n  Comments: 'Athugasemdir'\n  Click to View Comments: 'Smelltu til að skoða athugasemdir'\n  Getting comment replies, please wait: 'Sæki svör við athugasemdum, bíddu aðeins'\n  There are no more comments for this video: 'Það eru engar fleiri athugasemdir við þetta myndskeið'\n  Hide Comments: 'Fela athugasemdir'\n  Top comments: 'Efstu athugasemdir'\n  Newest first: 'Nýjasta fyrst'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Engar athugasemdir eru tiltækar fyrir þetta myndskeið'\n  Load More Comments: 'Hlaða inn fleiri athugasemdum'\n  Show More Replies: Birta fleiri svör\n  Pinned by: Fest af\n  Member: Meðlimur\n  View {replyCount} replies: Skoða 1 svar | Skoða {replyCount} svör\n  Hearted: Líkað\n  Subscribed: Áskrifandi\n  There are no comments available for this post: Engar athugasemdir finnast fyrir þessa færslu\n  Hide {replyCount} replies: Fela 1 svar | Fela {replyCount} svör\n  View 1 reply from {channelName}: Skoða 1 svar frá {channelName}\n  View {replyCount} replies from {channelName} and others: Skoða {replyCount} svör frá {channelName} og fleirum\nUp Next: 'Næst í spilun'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Veldu bakendann sem FreeTube notar til að ná í gögn. Staðværa API-kerfisviðmótið er innbyggður skrapari. Invidious API-kerfisviðmótið krefst tengingar við Invidious-netþjón.'\n    Fallback to Non-Preferred Backend on Failure: 'Þegar forgangsbakendi API-kerfisviðmóts á í vandræðum, mun FreeTube reyna sjálfkrafa að nota ekki-forgangsbakenda API-kerfisviðmóts sem varaleið, þegar þetta er virkjað.'\n    Thumbnail Preference: 'Öllum smámyndum í FreeTube verður skipt út fyrir ramma með myndskeiðinu, móskaðan eða falinn, í stað sjálfgefinnar smámyndar.'\n    Invidious Instance: 'Tilvik Invidious-netþjóns sem FreeTube mun tengjast fyrir beiðnir í API-kerfisviðmót.'\n    Region for Trending: 'Landssvæði sem skal miða vinsældir við gerir þér kleift að velja í hvaða landi aukning á vinsældum í umræðunni skal miða við.'\n    External Link Handling: \"Veldu sjálfgefna hegðun þegar smellt er á tengil sem ekki er hægt að opna í FreeTube.\\nSjálfgefið mun FreeTube opna viðkomandi tengil í sjálfgefna vafranum þínum.\\n\"\n    Open Deep Links In New Window: Slóðir sem beint er til FreeTube, til dæmis með endurbeiningum vafraviðbóta eða skipanalínuviðföngum, verða opnaðar í nýjum glugga.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Mun tengjast við Invidious til að miðla myndskeiðum í stað þess að tengjast beint við YouTube.'\n    Default Video Format: 'Stillu skráasniðin sem notuð eru við afspilun myndskeiða. DASH-snið (Dynamic Adaptive Streaming over HTTP) er hægt að spila í meiri gæðum. Eldri snið takmarkast við 360p en nota minni bandbreidd. Hljóðsnið eru streymi einungis með hljóði.'\n    Scroll Playback Rate Over Video Player: Á meðan bendillinn er yfir myndspilaranum, ýttu og haltu niðri Ctrl-lyklinum ('Command' slaufulykill á Mac) og skrunaðu með músarhjólinu áfram eða afturábak til að stýra hraða afspilunar. Ýttu og haltu niðri Ctrl-lyklinum ('Command' slaufulykill á Mac) og smelltu með vinstri músarhnappnum til að snúa aftur í sjálfgefinn hraða (1x nema ef því hefur verið breytt í stillingunum).\n    Skip by Scrolling Over Video Player: Nota skrunhjólið til að fletta í gegnum myndskeið, svipað og í MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Þegar þetta er virkt, mun FreeTube nota RSS í stað sjálfgefinnar aðferðar við að safna streymi áskriftarinnar þinnar. RSS er hraðvirkara og kemur í veg fyrir útilokun IP-vistfanga, en nær ekki að birta ákveðnar upplýsingar á borð við tímalengd myndskeiða, stöðu í beinni útsendingu eða færslur'\n\n# Toast Messages\n    Fetch Automatically: Þegar þetta er virkt, mun FreeTube sækja sjálfkrafa áskriftarstreymin þín í ræsingu og þegar nýr gluggi er opnaður.\n  External Player Settings:\n    Custom External Player Arguments: Öll sérsniðin skipanaviðföng og rofar, sem beina á til utanaðkomandi spilarans.\n    Ignore Warnings: Hunsa aðvarinir þegar valinn utanaðkomandi spilari styður ekki viðkomandi aðgerð (t.d. að snúa við spilunarlista, o.s.frv.).\n    Custom External Player Executable: Sjálfgefið gengur FreeTube út frá því að valinn utanaðkomandi spilari finnist í gegnum PATH umhverfisbreytuna. Ef þess þarf, má setja sérsniðna slóð hér.\n    External Player: Sé valinn utanaðkomandi spilari, birtist táknmynd á smámyndinni til að opna myndskeiðið (í spilunarlista ef stuðningur er við slíkt) í þessum utanaðkomandi spilara. Aðvörun, stillingar Invidious hafa ekki áhrif á utanaðkomandi spilara.\n    DefaultCustomArgumentsTemplate: \"(Sjálfgefið: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Ekki senda nein sjálfgefin viðföng til utanaðkomandi spilarans önnur en URL-slóð myndskeiðs (t.d. afspilunarhraða, slóð spilunarlista, o.s.frv.). Sérsniðin viðföng verða send eftir sem áður.\n  Experimental Settings:\n    Replace HTTP Cache: Gerir HTTP-skyndiminni Electron óvirkt og virkjar sérsniðna minnislæga skyndiminnis-diskmynd. Veldur aukinni notkun á vinnsluminni.\n  Distraction Free Settings:\n    Hide Channels: Settu inn auðkenni rásar til að fela öll myndskeið, spilunarlista og sjálfa rásina við leit eða því sem er vinsælast, mest skoðað og mælt með. Auðkenni rásarinnar sem sett er inn þarf að vera nákvæmlega stafrétt og tekur tillit til hástafa/lágstafa.\n    Hide Subscriptions Live: Þessa stillingu er hægt að taka yfir með \"{appWideSetting}\" stillingunni fyrir allt forritið, í \"{subsection}\" hlutanum í \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Settu inn orð, orðhluta eða setningu (óháð stafstöðu) til að fela öll myndskeið og spilunarlista þar sem titillinn inniheldur þetta, hvar sem er í FreeTube, með undantekningum innan áhorfsferils, spilunarlistanna þinna og myndskeiða innan spilunarlista.\n    Hide Videos on Watch: Felur myndskeið sem búið er að horfa á, úr flipunum Myndskeið, Símamyndir og Í beinni, á áskriftar- og rásasíðunum. Þetta hefur ekki áhrif á heimaflipann á rásasíðunum\n  SponsorBlock Settings:\n    UseDeArrowTitles: Skipta út titlum myndskeiða fyrir titla sem notendur hafa sent inn á DeArrow.\n    UseDeArrowThumbnails: Skipta út smámyndum myndskeiða fyrir smámyndir frá DeArrow.\nLocal API Error (Click to copy): 'Villa í staðværu API-kerfisviðmóti (smella til að afrita)'\nInvidious API Error (Click to copy): 'Villa í Invidious API-kerfisviðmóti (smella til að afrita)'\nFalling back to Invidious API: 'Nota til vara Invidious API-kerfisviðmót'\nFalling back to Local API: 'Nota til vara staðvært API-kerfisviðmót'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Þetta myndskeiðer ekki tiltækt vegna þess að það vantar skráasnið. Þetta getur gest ef þau eru ekki tiltæk í viðkomandi landi.'\nLoop is now disabled: 'Endurtekning er núna óvirk'\nLoop is now enabled: 'Endurtekning er núna virk'\nShuffle is now disabled: 'Stokkun er núna óvirk'\nShuffle is now enabled: 'Stokkun er núna virk'\nThe playlist has been reversed: 'Spilunarlistanum hefur verið snúið'\nPlaying Next Video: 'Spila næsta myndskeið'\nPlaying Previous Video: 'Spila fyrra myndskeið'\nPlaying Next Video Interval: 'Spila næsta myndskeið strax. Smelltu til að hætta við. | Spila næsta myndskeið eftir {nextVideoInterval} sekúndu. Smelltu til að hætta við. | Spila næsta myndskeið eftir {nextVideoInterval} sekúndur. Smelltu til að hætta við.'\nCanceled next video autoplay: 'Hætti við sjálfvirka afspilun næsta myndskeiðs'\n'The playlist has ended. Enable loop to continue playing': 'Spilunarlistinn er kominn út á enda. Virkjaðu óendanlega endurtekningu til að halda afspilun áfram'\n\nYes: 'Já'\nNo: 'Nei'\nUnknown YouTube url type, cannot be opened in app: Óþekkt gerð YouTube-slóðar, er ekki hægt að opna í forritinu\nOpen New Window: Opna í nýjum glugga\nDefault Invidious instance has been cleared: Sjálfgefið Invidious-tilvik hefur verið hreinsað út\nDefault Invidious instance has been set to {instance}: Sjálfgefið Invidious-tilvik hefur verið stillt sem {instance}\nSearch Bar:\n  Clear Input: Hreinsa reit\n  Remove: Fjarlægja\nExternal link opening has been disabled in the general settings: Opnun ytri tengla hefur verið gerð óvirk í almennum stillingum\nAre you sure you want to open this link?: Ertu viss um að þú viljir opna þennan tengil?\nScreenshot Error: Skjámyndataka mistókst. {error}\nScreenshot Success: Vistaði skjámynd\nNew Window: Nýr gluggi\nChannels:\n  Search bar placeholder: Leita í rásum\n  Count: '{number} rás/rásir fundust.'\n  Empty: Rásalistinn þinn er tómur.\n  Unsubscribe Prompt: Ertu viss um að þú viljir hætta áskrift að \"{channelName}\"?\n  Channels: Rásir\n  Title: Rásalisti\nClipboard:\n  Copy failed: Afritun á klippispjald mistókst\n  Cannot access clipboard without a secure connection: Get ekki tengst klippispjaldi án öruggrar tengingar\nChapters:\n  Chapters: Kaflar\n  Key Moments: Helstu augnablik\nPreferences: Kjörstillingar\nOk: Í lagi\nHashtag:\n  Hashtag: Myllumerki\n  This hashtag does not currently have any videos: Þetta myllumerki er í augnablikinu ekki með nein myndskeið\nGo to page: Fara á {page}\nChannel Hidden: '{channel} bætt við rásasíu'\nChannel Unhidden: '{channel} fjarlægt úr rásasíu'\nClose Banner: Loka borða\nAge Restricted:\n  This video is age restricted: Þetta myndskeið er með aldurstakmörkunum\n  This channel is age restricted: Þessi rás er með aldurstakmörkunum\nTag already exists: '\"{tagName}\" merkið er þegar til staðar'\nDisplay Label: '{label}: {value}'\nFeed:\n  Refresh Feed: Endurlesa {subscriptionName}\n  Feed Last Updated: '{feedName}-streymi síðast uppfært: {date}'\nSearch character limit: Leitarstrengurinn er kominn yfir hámarksfjöldann {searchCharacterLimit} stafi\nYes, Restart: Já, endurræsa\nYes, Open Link: Já, opna tengil\nCancel: Hætta við\nYes, Delete: Já, eyða\ncheckmark: ✓\nTrimmed input must be at least N characters long: Stytt úttak verður að minnsta kosti að innihalda 1 staf | Stytt úttak verður að minnsta kosti að innihalda {length} stafi\nMoments Ago: rétt áðan\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Skjátextar\n    Closed Captions: Þýðingartextar\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nýtt\n    3D: 3D\nKeys:\n  arrowright: Hægri-ör\n  arrowleft: Vinstri-ör\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Niður-ör\n  arrowup: Upp-ör\n  shift: Shift\n  enter: Enter\n  plus: Plús\nRight-click or hold to see history: Hægri-smelltu til að sjá feril\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nAutoplay Interruption Timer: Hætt sjálfvirkri spilun vegna {autoplayInterruptionIntervalHours} klst án aðgerða\nDescription:\n  Expand Description: '...meira'\n  Collapse Description: Birta minna\nKeyboardShortcutPrompt:\n  Sections:\n    Video:\n      Playback: Myndskeið: Afspilun\n      General: Myndskeið: Almennt\n    App:\n      Situational: 'Forrit: Aðstaða'\n      General: Forrit: Almennt\n  Show Keyboard Shortcuts: Birta flýtivísanir á lyklaborði\n  Captions: Víxla skýringartextum af/á\n  Full Window: Víxla fullum glugga af/á\n  Theatre Mode: Víxla bíóham af/á\n  Toggle Developer Tools: Víxla forritunarverkfærum af/á\n  Play: Víxla spilun / í bið\n  Next Frame: Næsti rammi (í bið)\n  Volume Up: Auka hljóðstyrk\n  Focus Search: Færa virkni í leitarreitinn\n  Search in New Window: Leita í nýjum glugga\n  Last Frame: Fyrri rammi (í bið)\n  Volume Down: Minnka hljóðstyrk\n  Last Chapter: Síðasti kafli\n  Next Chapter: Næsti kafli\n  Small Rewind: Spóla til baka um X sekúndur út frá hámarksbili milli afspilana og fyrirliggjandi afspilunarhraða\n  Small Fast Forward: Spóla áfram um X sekúndur út frá hámarksbili milli afspilana og fyrirliggjandi afspilunarhraða\n  History Backward: Fara til baka um eina síðu\n  History Forward: Fara áfram um eina síðu\n  New Window: Búa til nýjan glugga\n  Navigate to Settings: Fara á stillingasíðuna\n  Navigate to History: Fara á ferilssíðuna\n  Refresh: Endurlesa streymi með nýjasta efni\n  Large Rewind: Spóla til baka um 10 sekúndur / Spóla myndskeið til baka út frá fyrirliggjandi afspilunarhraða\n  Fullscreen: Víxla skjáfylli af/á\n  Stats: Birta tölfræði myndskeiðs\n  Picture in Picture: Víxla mynd-í-mynd-ham af/á\n  Decrease Video Speed: Minnka afspilunarhraða út frá hámarksbili milli afspilunar myndskeiða\n  Mute: Víxla hljóði af/á\n  Large Fast Forward: Spóla áfram um 10 sekúndur / Spóla myndskeið áfram út frá fyrirliggjandi afspilunarhraða\n  Increase Video Speed: Auka afspilunarhraða út frá hámarksbili milli afspilunar myndskeiða\n  Take Screenshot: Taka skjámynd\n  Minimize Window: Lágmarka glugga\n  Close Window: Loka glugga\n  Reset Zoom: Endurstilla aðdráttarstig / kvarða viðmóts\n  Zoom In: Renna að\n  Zoom Out: Renna frá\n  Skip by Tenths: Hoppa í prósentum í gegnum myndskeið (3 sleppir yfir á 30% tímalengdar)\n  Keyboard Shortcuts: Flýtivísanir á lyklaborði\n  Focus Secondary Search: Færa virkni í hinn leitarreitinn (ef annar er til staðar)\n  Home: Hoppa í upphaf myndskeiðsins\n  End: Hoppa í enda myndskeiðsins\n  Skip to Next Video: Sleppa yfir á næsta myndskeið í spilunarlista eða næsta myndskeið sem mælt er með\n  Skip to Previous Video: Sleppa yfir á fyrra myndskeið í spilunarlista\nshortcutLabelSeparator: ｜\nCompact side navigation: Þjöppuð hliðarflakkstika\nExpand side navigation: Fella út hliðarflakkstiku\n"
  },
  {
    "path": "static/locales/it.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Italiano'\n\n# Webkit Menu Bar\nFile: 'File'\nQuit: 'Esci'\nEdit: 'Modifica'\nUndo: 'Rifai'\nRedo: 'Ripeti'\nCut: 'Taglia'\nCopy: 'Copia'\nPaste: 'Incolla'\nDelete: 'Elimina'\nSelect all: 'Seleziona tutto'\nToggle Developer Tools: 'Attiva/disattiva strumenti per sviluppatori'\nActual size: 'Dimensione reale'\nZoom in: 'Ingrandisci'\nZoom out: 'Rimpicciolisci'\nToggle fullscreen: 'Attiva/disattiva schermo intero'\nWindow: 'Finestra'\nMinimize: 'Riduci'\nClose: 'Chiudi'\nBack: 'Indietro'\nForward: 'Avanti'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video'\n  Shorts: Video brevi\n  Live: Dal vivo\n  Posts: Post\n  Sort By: Ordina per\n\n# Search Bar\n  Counts:\n    Video Count: 1 video | {count} video\n    Channel Count: 1 canale | {count} canali\n    Subscriber Count: 1 iscritto | {count} iscritti\n    View Count: 1 visualizzazione | {count} visualizzazioni\n    Watching Count: 1 spettatore | {count} spettatori\n    Comment Count: 1 commento | {count} commenti\n    Like Count: 1 mi piace | {count} mi piace\nSearch / Go to URL: 'Ricerca o aggiungi URL YouTube'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtri di ricerca'\n  Sort By:\n    Most Relevant: 'Più rilevante'\n    Rating: 'Valutazione'\n    Upload Date: 'Data di caricamento'\n    View Count: 'Visualizzazioni'\n  Time:\n    Time: 'Tempo'\n    Any Time: 'Sempre'\n    Last Hour: 'Ultima ora'\n    Today: 'Oggi'\n    This Week: 'Questa settimana'\n    This Month: 'Questo mese'\n    This Year: 'Quest’anno'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Tutti i tipi'\n    Videos: 'Video'\n    Channels: 'Canali'\n    #& Playlists\n    Movies: Film\n  Duration:\n    Duration: 'Durata'\n    All Durations: 'Tutte le durate'\n    Short (< 4 minutes): 'Corto (< 4 minuti)'\n    Long (> 20 minutes): 'Lungo (> 20 minuti)'\n  # On Search Page\n    Medium (4 - 20 minutes): Medio (4 - 20 minuti)\n  Search Results: 'Risultati della ricerca'\n  Fetching results. Please wait: 'Caricamento risultati. Per favore attendi'\n  Fetch more results: 'Carica più risultati'\n# Sidebar\n  There are no more results for this search: Non ci sono altri risultati per questa ricerca\n  Features:\n    Features: Caratteristiche\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Dal vivo\n    4K: 4K\n    Location: Posizione\n    HDR: HDR\n    HD: HD\n    Subtitles: Sottotitoli\n    360 Video: Video 360\n    VR180: VR180\n  Clear Filters: Cancella filtri\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Iscrizioni'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Il tuo elenco di iscrizioni è attualmente vuoto. Se vuoi importare le tue iscrizioni puoi andare su Impostazioni dati e selezionare Importa iscrizioni oppure puoi cercare un canale e iscriverti ad esso.'\n  Load More Videos: Carica più video\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Questo profilo ha un grande numero di iscrizioni. Userò RSS per evitare limitazioni\n  Error Channels: Canali con errori\n  Disabled Automatic Fetching: Hai disabilitato il recupero automatico dell'iscrizione. Aggiorna le iscrizioni per vederle qui.\n  Empty Channels: I canali a cui sei iscritto attualmente non hanno alcun video.\n  Subscriptions Tabs: Schede iscrizioni\n  All Subscription Tabs Hidden: Tutte le schede di iscrizione sono nascoste. Per vedere i contenuti qui, scopri le schede nella sezione \"{subsection}\" in \"{settingsSection}\".\n  Load More Posts: Carica più post\n  Empty Posts: I canali a cui sei iscritto attualmente non hanno post.\nTrending:\n  Trending: 'Tendenze'\n  Trending Tabs: Schede di tendenza\n  Gaming: Videogiochi\n  Sports: Sport\nMost Popular: 'Più popolari'\nPlaylists: 'Playlist'\nUser Playlists:\n  Your Playlists: 'Le tue playlist'\n  Search bar placeholder: Ricerca nelle playlist\n  Empty Search Message: Non ci sono video in questa playlist che corrispondono alla tua ricerca\n  AddVideoPrompt:\n    Search in Playlists: Ricerca nelle playlist\n    Save: Salva\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Video aggiunti a 1 playlist | Video aggiunti a {playlistCount} playlist\"\n      You haven't selected any playlist yet.: Non hai ancora selezionato nessuna playlist.\n    Select a playlist to add your N videos to: Seleziona una playlist a cui aggiungere il tuo video | Seleziona una playlist a cui aggiungere i tuoi {videoCount} video\n    N playlists selected: '{playlistCount} selezionate'\n    Added {count} Times: Già aggiunto | Aggiunti {count} volte\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": Verranno aggiunti {videoCount}/{totalVideoCount} video\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": Sono già stati aggiunti {videoCount}/{totalVideoCount} video\n    Allow Adding Duplicate Video(s): Consenti l'aggiunta di video duplicati\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Non c'erano video da rimuovere.\n      Video has been removed: Il video è stato rimosso\n      Playlist has been updated.: La playlist è stata aggiornata.\n      There was an issue with updating this playlist.: Si è verificato un problema con l'aggiornamento di questa playlist.\n      This video cannot be moved up.: Questo video non può essere spostato verso l'alto.\n      This playlist is protected and cannot be removed.: Questa playlist è protetta e non può essere rimossa.\n      Playlist {playlistName} has been deleted.: La playlist {playlistName} è stata eliminata.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Alcuni video nella playlist non sono ancora stati caricati. Fai clic qui per copiare comunque.\n      This playlist does not exist: Questa playlist non esiste\n      Playlist name cannot be empty. Please input a name.: Il nome della playlist non può essere vuoto. Per favore inserisci un nome.\n      There was a problem with removing this video: Si è verificato un problema durante la rimozione di questo video\n      \"{videoCount} video(s) have been removed\": 1 video è stato rimosso | {videoCount} video sono stati rimossi\n      This video cannot be moved down.: Questo video non può essere spostato verso il basso.\n      This playlist is now used for quick bookmark: Questa playlist è ora usata per i segnalibri rapidi\n      Reverted to use {oldPlaylistName} for quick bookmark: Ripristinato l'uso di {oldPlaylistName} per i segnalibri rapidi\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Questa playlist è ora usata per i segnalibri rapidi al posto di {oldPlaylistName}. Fai clic qui per annullare\n      This playlist is already being used for quick bookmark.: Questa playlist è già utilizzata per i segnalibri rapidi.\n      This playlist has a video with a duration error: Questa playlist contiene almeno un video che non ha durata; verranno ordinati come se la loro durata fosse zero.\n      Video has been removed. Click here to undo.: Il video è stato rimosso. Clicca qui per annullare.\n    Search for Videos: Ricerca nei video\n  Are you sure you want to delete this playlist? This cannot be undone: Sei sicuro di voler eliminare questa playlist? Questa operazione non può essere annullata.\n  Sort By:\n    LatestPlayedFirst: Data di riproduzione (più recente)\n    EarliestCreatedFirst: Data di creazione (più vecchia)\n    LatestCreatedFirst: Data di creazione (più recente)\n    EarliestUpdatedFirst: Data di aggiornamento (più vecchia)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Data di riproduzione (più vecchia)\n    LatestUpdatedFirst: Data di aggiornamento (più recente)\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Non hai playlist. Fai clic sul pulsante Crea nuova playlist per crearne una nuova.\n  Remove from Playlist: Rimuovi dalla playlist\n  Save Changes: Salva le modifiche\n  CreatePlaylistPrompt:\n    Create: Crea\n    Toast:\n      There was an issue with creating the playlist.: Si è verificato un problema con la creazione della playlist.\n      Playlist {playlistName} has been successfully created.: La playlist {playlistName} è stata creata correttamente.\n      There is already a playlist with this name. Please pick a different name.: Esiste già una playlist con questo nome. Scegli un nome diverso.\n    New Playlist Name: Nuovo nome della playlist\n  This playlist currently has no videos.: Questa playlist attualmente non contiene video.\n  Add to Playlist: Aggiungi alla playlist\n  Move Video Down: Sposta il video in basso\n  Playlist Name: Nome della playlist\n  Remove Watched Videos: Rimuovi i video guardati\n  Move Video Up: Sposta il video in alto\n  Cancel: Annulla\n  Delete Playlist: Elimina playlist\n  Create New Playlist: Crea nuova playlist\n  Edit Playlist Info: Modifica informazioni playlist\n  Copy Playlist: Copia playlist\n  Playlist Description: Descrizione della playlist\n  Add to Favorites: Aggiungi a {playlistName}\n  Remove from Favorites: Rimuovi da {playlistName}\n  Enable Quick Bookmark With This Playlist: Abilita segnalibro rapido con questa playlist\n  Playlists with Matching Videos: Playlist con video correlati\n  Cannot delete the quick bookmark target playlist.: Impossibile eliminare la playlist di destinazione dei segnalibri rapidi.\n  Quick Bookmark Enabled: Segnalibro rapido abilitato\n  Remove Duplicate Videos: Rimuovi i video duplicati\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Sei sicuro di voler rimuovere 1 video duplicato da questa playlist? Questa operazione non può essere annullata. | Vuoi rimuovere {playlistItemCount} video duplicati da questa playlist? Questa operazione non può essere annullata.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Sei sicuro di voler rimuovere 1 video guardato da questa playlist? Questa operazione non può essere annullata. | Vuoi rimuovere {playlistItemCount} video guardati da questa playlist? Questa operazione non può essere annullata.\n  Export Playlist: Esporta questa playlist\n  The playlist has been successfully exported: La playlist è stata esportata correttamente\n  TotalTimePlaylist: 'Tempo totale: {duration}'\n  Export list of URLs: Esporta l'elenco degli URL\nHistory:\n  # On History Page\n  History: 'Cronologia'\n  Watch History: 'Cronologia delle visualizzazioni'\n  Your history list is currently empty.: 'La tua Cronologia è attualmente vuota.'\n  Search bar placeholder: Ricerca nella Cronologia\n  Empty Search Message: Non ci sono video nella tua Cronologia che corrispondono alla tua ricerca\n  Case Sensitive Search: Ricerca con distinzione tra maiuscole e minuscole\n  DateOldestHistory: Data di visione (più vecchia)\n  DateNewestHistory: Data di visione (più recente)\nSettings:\n  # On Settings Page\n  Settings: 'Impostazioni'\n  General Settings:\n    General Settings: 'Generale'\n    Fallback to Non-Preferred Backend on Failure: 'Ritorna al backend non preferito in caso di errore'\n    Enable Search Suggestions: 'Abilita suggerimenti di ricerca'\n    Default Landing Page: 'Pagina iniziale predefinita'\n    Locale Preference: 'Lingua predefinita'\n    Preferred API Backend:\n      Preferred API Backend: 'Backend API preferito'\n      Local API: 'API locali'\n      Invidious API: 'API di Invidious'\n    Video View Type:\n      Video View Type: 'Modalità di visualizzazione video'\n      Grid: 'Griglia'\n      List: 'Elenco'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferenze delle miniature'\n      Default: 'Predefinito'\n      Beginning: 'Inizio'\n      Middle: 'Nel mezzo'\n      End: 'Fine'\n      Hidden: Nascoste\n      Blur: Sfocatura\n    Region for Trending: 'Regione per le tendenze'\n        #! List countries\n    Check for Latest Blog Posts: Controlla gli ultimi post del blog\n    Check for Updates: Controlla gli aggiornamenti\n    View all Invidious instance information: Visualizza tutti i dati dell'istanza Invidious\n    Clear Default Instance: Cancella istanza predefinita\n    Set Current Instance as Default: Imposta l'attuale istanza come predefinita\n    Current instance will be randomized on startup: L'attuale istanza sarà sostituita all'avvio da una generata casualmente\n    No default instance has been set: Non è stata impostata alcuna istanza predefinita\n    The currently set default instance is {instance}: Attualmente l'istanza impostata come predefinita è {instance}\n    Current Invidious Instance: Attuale istanza di Invidious\n    System Default: Predefinito del sistema\n    External Link Handling:\n      No Action: Nessuna azione\n      Ask Before Opening Link: Chiedi prima di aprire il link\n      Open Link: Apri link\n      External Link Handling: Gestione dei link esterni\n    Auto Load Next Page:\n      Label: Carica automaticamente la pagina successiva\n      Tooltip: Carica automaticamente pagine e commenti aggiuntivi.\n    Open Deep Links In New Window: Apri URL passati a FreeTube in una nuova finestra\n    Minimize to system tray: Riduci a icona nella barra delle applicazioni\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Abbina la barra superiore al colore principale'\n    Base Theme:\n      Base Theme: 'Tema di base'\n      Black: 'Nero'\n      Dark: 'Scuro'\n      Light: 'Chiaro'\n      Dracula: 'Dracula'\n      System Default: Predefinito del sistema\n      Catppuccin Mocha: Cappuccino moka\n      Pastel Pink: Rosa pastello\n      Hot Pink: Rosa caldo\n      Nordic: Nordico\n      Solarized Dark: Solarizzato scuro\n      Solarized Light: Solarizzato chiaro\n      Gruvbox Light: Gruvbox chiaro\n      Gruvbox Dark: Gruvbox scuro\n      Catppuccin Frappe: Cappuccino frappè\n      Everforest Dark Medium: Foresta sempreverde scura media\n      Everforest Dark Low: Foresta sempreverde scura debole\n      Everforest Light Low: Foresta sempreverde chiara debole\n      Everforest Light Medium: Foresta sempreverde chiara media\n      Everforest Dark Hard: Foresta sempreverde scura forte\n      Everforest Light Hard: Foresta sempreverde chiara forte\n      Catppuccin Latte: Cappuccino latte\n    Main Color Theme:\n      Main Color Theme: 'Colore principale del tema'\n      Red: 'Rosso'\n      Pink: 'Rosa'\n      Purple: 'Viola'\n      Deep Purple: 'Viola scuro'\n      Indigo: 'Indaco'\n      Blue: 'Blu'\n      Light Blue: 'Blu chiaro'\n      Cyan: 'Ciano'\n      Teal: 'Verde acqua'\n      Green: 'Verde'\n      Light Green: 'Verde chiaro'\n      Lime: 'Lime'\n      Yellow: 'Giallo'\n      Amber: 'Ambra'\n      Orange: 'Arancione'\n      Deep Orange: 'Arancione scuro'\n      Dracula Cyan: 'Dracula ciano'\n      Dracula Green: 'Dracula verde'\n      Dracula Orange: 'Dracula arancione'\n      Dracula Pink: 'Dracula rosa'\n      Dracula Purple: 'Dracula viola'\n      Dracula Red: 'Dracula rosso'\n      Dracula Yellow: 'Dracula giallo'\n      Catppuccin Mocha Pink: Cappuccino moka rosa\n      Catppuccin Mocha Mauve: Cappuccino moka malva\n      Catppuccin Mocha Red: Cappuccino moka rosso\n      Catppuccin Mocha Maroon: Cappuccino moka marrone\n      Catppuccin Mocha Blue: Cappuccino moka blu\n      Catppuccin Mocha Green: Cappuccino moka verde\n      Catppuccin Mocha Sapphire: Cappuccino moka zaffiro\n      Catppuccin Mocha Yellow: Cappuccino moka giallo\n      Catppuccin Mocha Rosewater: Cappuccino moka acqua di rose\n      Catppuccin Mocha Flamingo: Cappuccino moka fenicottero\n      Catppuccin Mocha Lavender: Cappuccino moka lavanda\n      Catppuccin Mocha Peach: Cappuccino moka pesca\n      Catppuccin Mocha Teal: Cappuccino moka alzavola\n      Catppuccin Mocha Sky: Cappuccino moka cielo\n      Solarized Yellow: Solarizzato giallo\n      Solarized Orange: Solarizzato arancione\n      Solarized Red: Solarizzato rosso\n      Solarized Magenta: Solarizzato magenta\n      Solarized Violet: Solarizzato viola\n      Solarized Cyan: Solarizzato ciano\n      Solarized Green: Solarizzato verde\n      Solarized Blue: Solarizzato blu\n      Gruvbox Dark Yellow: Gruvbox giallo scuro\n      Gruvbox Dark Purple: Gruvbox viola scuro\n      Gruvbox Light Blue: Gruvbox blu chiaro\n      Gruvbox Light Purple: Gruvbox viola chiaro\n      Gruvbox Light Orange: Gruvbox arancione chiaro\n      Gruvbox Dark Aqua: Gruvbox acqua marina scuro\n      Gruvbox Dark Green: Gruvbox verde scuro\n      Gruvbox Dark Blue: Gruvbox blu scuro\n      Gruvbox Light Red: Gruvbox rosso chiaro\n      Gruvbox Dark Orange: Gruvbox arancione scuro\n      Catppuccin Frappe Rosewater: Cappuccino frappè acqua di rose\n      Catppuccin Frappe Flamingo: Cappuccino frappè fenicottero\n      Catppuccin Frappe Pink: Cappuccino frappè rosa\n      Catppuccin Frappe Mauve: Cappuccino frappè malva\n      Catppuccin Frappe Red: Cappuccino frappè rosso\n      Catppuccin Frappe Maroon: Cappuccino frappè marrone\n      Catppuccin Frappe Peach: Cappuccino frappè pesca\n      Catppuccin Frappe Yellow: Cappuccino frappè giallo\n      Catppuccin Frappe Green: Cappuccino frappè verde\n      Catppuccin Frappe Teal: Cappuccino frappè alzavola\n      Catppuccin Frappe Sky: Cappuccino frappè cielo\n      Catppuccin Frappe Sapphire: Cappuccino frappè zaffiro\n      Catppuccin Frappe Blue: Cappuccino frappè blu\n      Catppuccin Frappe Lavender: Cappuccino frappè lavanda\n      Everforest Dark Red: Foresta sempreverde scura rossa\n      Everforest Dark Orange: Foresta sempreverde scura arancione\n      Everforest Dark Yellow: Foresta sempreverde scura gialla\n      Everforest Dark Green: Foresta sempreverde scura verde\n      Everforest Light Red: Foresta sempreverde chiara rossa\n      Everforest Light Orange: Foresta sempreverde chiara arancione\n      Everforest Dark Aqua: Foresta sempreverde scura acqua marina\n      Everforest Dark Blue: Foresta sempreverde scura blu\n      Everforest Light Yellow: Foresta sempreverde chiara gialla\n      Everforest Light Green: Foresta sempreverde chiara verde\n      Everforest Light Aqua: Foresta sempreverde chiara acqua marina\n      Everforest Light Blue: Foresta sempreverde chiara blu\n      Everforest Light Purple: Foresta sempreverde chiara viola\n      Everforest Dark Purple: Foresta sempreverde scura viola\n      Catppuccin Latte Mauve: Cappuccino latte malva\n      Catppuccin Latte Red: Cappuccino latte rosso\n    Secondary Color Theme: 'Colore secondario del tema'\n        #* Main Color Theme\n    UI Scale: Dimensioni dell'interfaccia utente\n    Disable Smooth Scrolling: Disabilita lo scorrimento fluido\n    Expand Side Bar by Default: Espandi automaticamente la barra laterale\n    Hide Side Bar Labels: Nascondi le etichette della barra laterale\n    Hide FreeTube Header Logo: Nascondi il logo dell'intestazione di FreeTube\n  Player Settings:\n    Player Settings: 'Lettore'\n    Play Next Video: 'Riproduzione automatica dei video consigliati'\n    Turn on Subtitles by Default: 'Abilita i sottotitoli per impostazione predefinita'\n    Autoplay Videos: 'Avvia video automaticamente'\n    Proxy Videos Through Invidious: 'Proxy dei video tramite Invidious'\n    Autoplay Playlists: 'Riproduzione automatica dei video della playlist'\n    Enable Theatre Mode by Default: 'Abilita la modalità teatro come predefinita'\n    Default Volume: 'Volume predefinito'\n    Default Playback Rate: 'Velocità di riproduzione predefinita'\n    Default Video Format:\n      Default Video Format: 'Formato video predefinito'\n      Dash Formats: 'Formati DASH'\n      Legacy Formats: 'Formati compatibili'\n      Audio Formats: 'Formati audio'\n    Default Quality:\n      Default Quality: 'Qualità predefinita'\n      Auto: 'Automatica'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: Avanzamento veloce o riavvolgimento video\n    Next Video Interval: Timer di conto alla rovescia per la riproduzione automatica\n    Display Play Button In Video Player: Visualizza il pulsante di riproduzione nel lettore video\n    Scroll Volume Over Video Player: Controlla il volume scorrendo sul lettore video\n    Scroll Playback Rate Over Video Player: Scorri la velocità di riproduzione sul lettore video\n    Video Playback Rate Interval: Intervallo di riproduzione video\n    Max Video Playback Rate: Velocità massima di riproduzione video\n    Screenshot:\n      Folder Label: Cartella screenshot\n      Folder Button: Seleziona cartella\n      File Name Label: Modello nome del file\n      Error:\n        Forbidden Characters: Caratteri non accettati\n        Empty File Name: Nome file vuoto\n      Quality Label: Qualità screenshot\n      Enable: Abilita screenshot\n      Format Label: Formato screenshot\n      Ask Path: Chiedi cartella di salvataggio\n      File Name Tooltip: Puoi usare le seguenti variabili. %Y Anno 4 cifre. %M Mese 2 cifre. %D Giorno 2 cifre. %H Ora 2 cifre. %N Minuto 2 cifre. %S Secondo 2 cifre. %T Millisecondo 3 cifre. %s Durata in secondi del video. %t Millisecondi del video 3 cifre. %i ID video.\n    Enter Fullscreen on Display Rotate: Entra a schermo intero su Ruota schermo\n    Skip by Scrolling Over Video Player: Salta tramite scorrimento sul lettore video\n    Autoplay Interruption Timer: Timer di interruzione della riproduzione automatica\n    Default Viewing Mode:\n      Full Screen: Schermo intero\n      Picture in Picture: Immagine nell'immagine\n      External Player: Lettore esterno ({externalPlayerName})\n      Default Viewing Mode: Modalità di visualizzazione predefinita\n      Theater: Teatro\n  Privacy Settings:\n    Privacy Settings: 'Privacy'\n    Remember History: 'Ricorda la Cronologia delle visualizzazioni'\n    Save Watched Progress: 'Salva i progressi raggiunti'\n    Clear Search Cache: 'Svuota la cache della ricerca'\n    Are you sure you want to clear out your search cache?: 'Sei sicuro di voler svuotare la cache della ricerca?'\n    Search cache has been cleared: 'La cache della ricerca è stata svuotata'\n    Remove Watch History: 'Rimuovi la Cronologia delle visualizzazioni'\n    Are you sure you want to remove your entire watch history?: 'Sei sicuro di voler rimuovere l''intera Cronologia delle visualizzazioni?'\n    Watch history has been cleared: 'La Cronologia delle visualizzazioni è stata svuotata'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Sei sicuro di volere eliminare tutte le iscrizioni e i profili? L'operazione non può essere annullata.\n    Remove All Subscriptions / Profiles: Elimina tutte le iscrizioni e i profili\n    Save Watched Videos With Last Viewed Playlist: Salva i video guardati con l'ultima playlist vista\n    All playlists have been removed: Tutte le playlist sono state rimosse\n    Remove All Playlists: Rimuovi tutte le playlist\n    Are you sure you want to remove all your playlists?: Sei sicuro di voler rimuovere tutte le tue playlist?\n    Are you sure you want to clear out your search history and cache?: Vuoi davvero cancellare la Cronologia delle ricerche e la cache?\n    Search history and cache have been cleared: La Cronologia delle ricerche e la cache sono state cancellate\n    Remember Search History: Ricorda la Cronologia delle ricerche\n    Clear Search History and Cache: Cancella la Cronologia delle ricerche e la cache\n    Watched Progress Saving Mode:\n      Tooltip: Automaico = Salva a ogni uscita dalla pagina video, quando il video è terminato e si è verificato un errore (ad esempio, ratelimited e sessione di visione scaduta). Semiautomatico = Come Automaico, tranne all'uscita dalla pagina video e può salvare manualmente i progressi tramite un pulsante denominato Salva i progressi guardati, situato sotto il lettore video.\n      Modes:\n        Never: Mai\n        Semi-auto: Semiautomatico\n        Auto: Automatico\n  Subscription Settings:\n    Subscription Settings: 'Iscrizioni'\n    Fetch Feeds from RSS: Scarica gli aggiornamenti dai flussi RSS\n    Fetch Automatically: Recupera i feed automaticamente\n    Confirm Before Unsubscribing: Evita la cancellazione accidentale dell'iscrizione\n\n    'Limit the number of videos displayed for each channel': Limita il numero di video visualizzati per ogni canale\n    To: A\n  Data Settings:\n    How do I import my subscriptions?: Come posso importare le mie iscrizioni?\n    Unknown data key: Chiave dati sconosciuta\n    Unable to write file: Impossibile salvare il file\n    Unable to read file: Impossibile leggere il file\n    All watched history has been successfully exported: La Cronologia delle visualizzazioni è stata esportata correttamente\n    All watched history has been successfully imported: La Cronologia delle visualizzazioni è stata importata correttamente\n    History object has insufficient data, skipping item: La Cronologia ha dati insufficienti, non verrà elaborata\n    Import Subscriptions: Importa le iscrizioni\n    Subscriptions have been successfully exported: Tutte le iscrizioni sono state esportate correttamente\n    Invalid history file: File Cronologia non valido\n    Invalid subscriptions file: File iscrizioni non valido\n    All subscriptions have been successfully imported: Tutte le iscrizioni sono state importate correttamente\n    All subscriptions and profiles have been successfully imported: Tutte le iscrizioni e i profili sono stati importati correttamente\n    Profile object has insufficient data, skipping item: Il profilo selezionato ha dati insufficienti, quindi non sarà aggiunto\n    Export History: Esporta la Cronologia\n    Import History: Importa la Cronologia\n    Export NewPipe: Esporta per NewPipe\n    Export YouTube: Esporta per YouTube\n    Export FreeTube: Esporta per FreeTube\n    Export Subscriptions: Esporta le iscrizioni\n    Select Export Type: Seleziona il tipo di esportazione\n    Data Settings: Dati\n    Manage Subscriptions: Gestisci i profili\n    Import Playlists: Importa playlist\n    Export Playlists: Esporta playlist\n    Playlist insufficient data: Dati insufficienti per la playlist \"{playlist}\", elemento saltato\n    All playlists has been successfully imported: Tutte le playlist sono state importate correttamente\n    All playlists has been successfully exported: Tutte le playlist sono state esportate correttamente\n    History File: File della Cronologia\n    Subscription File: File delle iscrizioni\n    Playlist File: File delle playlist\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Questa opzione esporta i video da tutte le playlist in una playlist denominata \\\"Preferiti\\\".\\nCome esportare e importare video nelle playlist per una versione precedente di FreeTube:\\n1. Esporta le tue playlist con questa opzione abilitata.\\n2. Elimina tutte le playlist esistenti usando l'opzione Rimuovi tutte le playlist in Impostazioni della privacy.\\n3. Avvia la versione precedente di FreeTube e importa le playlist esportate.\"\n      Label: Esporta playlist per versioni precedenti di FreeTube\n    Search history file: File della cronologia delle ricerche\n    Search history: Cronologia delle ricerche\n    Import search history: Importa cronologia ricerche\n    Export search history: Esporta cronologia ricerche\n    All search history has been successfully imported: Tutta la cronologia ricerche è stata importata correttamente\n    All search history has been successfully exported: Tutta la cronologia ricerche è stata esportata correttamente\n  Distraction Free Settings:\n    Hide Popular Videos: Nascondi i video più popolari\n    Hide Trending Videos: Nascondi le tendenze\n    Hide Recommended Videos: Nascondi i suggerimenti sui video successivi\n    Hide Comment Likes: Nascondi Mi piace dai commenti\n    Hide Channel Subscribers: Nascondi il numero di iscritti\n    Hide Video Views: Nascondi le visualizzazioni dei video\n    Distraction Free Settings: Modalità senza distrazioni\n    Hide Live Chat: Nascondi la chat dal vivo\n    Hide Video Likes And Dislikes: Nascondi Mi piace e Non mi piace\n    Hide Active Subscriptions: Nascondi le iscrizioni attive\n    Hide Playlists: Nascondi le playlist\n    Hide Comments: Nascondi i commenti\n    Hide Live Streams: Nascondi i video dal vivo\n    Hide Sharing Actions: Nascondi le azioni di condivisione\n    Hide Videos on Watch: 'Nascondi i video visualizzati'\n    Hide Video Description: Nascondi la descrizione del video\n    Hide Chapters: Nascondi i capitoli\n    Hide Upcoming Premieres: Nascondi le prossime Première\n    Hide Channels: Nascondi i video dai canali\n    Hide Channels Placeholder: ID del canale\n    Display Titles Without Excessive Capitalisation: Visualizza i titoli senza maiuscole e punteggiatura eccessive\n    Hide Featured Channels: Nascondi i canali in evidenza\n    Hide Channel Playlists: Nascondi la scheda \"Playlist\" del canale\n    Hide Channel Shorts: Nascondi i \"Video brevi\" del canale\n    Sections:\n      General: Generale\n      Watch Page: Pagina di visualizzazione\n      Side Bar: Barra laterale\n      Channel Page: Pagina del canale\n      Subscriptions Page: Pagina delle iscrizioni\n    Hide Channel Podcasts: Nascondi la scheda \"Podcast\" del canale\n    Hide Channel Releases: Nascondi la scheda \"Rilasci\" del canale\n    Hide Subscriptions Live: Nascondi le iscrizioni dal vivo\n    Hide Subscriptions Videos: Nascondi i video delle iscrizioni\n    Hide Subscriptions Shorts: Nascondi le iscrizioni ai video brevi\n    Hide Profile Pictures in Comments: Nascondi le immagini del profilo nei commenti\n    Hide Channels Invalid: L'ID canale fornito non è valido\n    Hide Channels Disabled Message: Alcuni canali sono stati bloccati usando l'ID e non sono stati elaborati. La funzionalità è bloccata durante l'aggiornamento di tali ID\n    Hide Channels Already Exists: L'ID canale esiste già\n    Hide Channels API Error: Errore durante il recupero dell'utente con l'ID fornito. Controlla di nuovo se l'ID è corretto.\n    Hide Videos, Playlists and Channels Containing Text: Nascondi i video e le playlist contenenti il testo\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Parola, frammento di parola o frase\n    Hide Channel Home: Nascondi la scheda \"Pagina iniziale\" del canale\n    Show Added Items: Mostra elementi aggiunti\n    Hide Channel Courses: Nascondi la scheda \"Corsi\" del canale\n    Hide Channel Posts: Nascondi la scheda \"Post\" del canale\n    Hide Subscriptions Posts: Nascondi i post delle iscrizioni\n  The app needs to restart for changes to take effect. Restart and apply change?: L'app deve essere riavviata affinché le modifiche abbiano effetto. Riavviare e applicare la modifica?\n  Proxy Settings:\n    Proxy Protocol: Protocollo Proxy\n    Enable Tor / Proxy: Attiva Tor o Proxy\n    Proxy Settings: Proxy\n    Error getting network information. Is your proxy configured properly?: C'è stato un errore di acquisizione delle informazioni di rete. Il proxy è stato configurato correttamente?\n    City: Città\n    Region: Regione\n    Country: Nazione\n    Ip: Ip\n    Your Info: Le tue informazioni\n    Test Proxy: Testa proxy\n    Clicking on Test Proxy will send a request to: Facendo clic su Testa proxy verrà inviata una richiesta a\n    Proxy Port Number: Numero di porta del proxy\n    Proxy Host: Host del proxy\n    Proxy Warning: FreeTube non ha un proxy integrato ma può connettersi a un proxy esterno, come uno in esecuzione sul tuo computer come Tor o un proxy esterno come un proxy SOCKS5 fornito da alcune VPN. Se abilitato, assicurati che il tuo proxy/Tor sia configurato correttamente, altrimenti FreeTube non sarà in grado di recuperare alcun dato.\n    Proxy Username: Nome utente proxy\n    Proxy Password: Password proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notifica quando un segmento sponsor viene saltato\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL dell'API di SponsorBlock (l'impostazione predefinita è https://sponsor.ajay.app)\n    Enable SponsorBlock: Abilita SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Salta l'opzione\n      Show In Seek Bar: Mostra nella barra di scorrimento\n      Auto Skip: Salto automatico\n      Prompt To Skip: Chiedi di saltare\n      Do Nothing: Non fare nulla\n    Category Color: Colore della categoria\n    UseDeArrowTitles: Usa i titoli dei video di DeArrow\n    UseDeArrowThumbnails: Usa DeArrow per le miniature\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL dell'API del generatore di miniature DeArrow (l'impostazione predefinita è https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Argomenti del lettore esterno personalizzato\n    Custom External Player Executable: File eseguibile del lettore esterno personalizzato\n    Ignore Unsupported Action Warnings: Ignora avvisi per azioni non supportate\n    External Player: Lettore esterno\n    External Player Settings: Lettore esterno\n    Players:\n      None:\n        Name: Nessuno\n    Ignore Default Arguments: Ignora argomenti predefiniti\n  Parental Control Settings:\n    Hide Unsubscribe Button: Nascondi il pulsante Annulla iscrizione\n    Parental Control Settings: Controllo genitori\n    Show Family Friendly Only: Mostra Solo per famiglie\n    Hide Search Bar: Nascondi la barra di ricerca\n    Hide Uploader on Watch page: Nascondi l'autore del caricamento dalla Pagina di visualizzazione\n  Experimental Settings:\n    Replace HTTP Cache: Sostituisci la cache HTTP\n    Experimental Settings: Sperimentale\n    Warning: Queste Impostazioni sono sperimentali, causano arresti anomali se abilitate. Si consiglia prima di fare un backup. Usare a proprio rischio!\n  Password Dialog:\n    Enter Password To Unlock: Inserisci la password per sbloccare le Impostazioni\n    Password: Password\n  Password Settings:\n    Set Password: Imposta password\n    Password Settings: Password\n    Set Password To Prevent Access: Imposta una password per impedire l'accesso alle Impostazioni\n    Remove Password: Rimuovi password\n  Sort Settings Sections (A-Z): Ordina le sezioni delle Impostazioni (A-Z)\n  Return to Settings Menu: Torna al menu Impostazioni\nAbout:\n  #On About page\n  About: 'Informazioni'\n  #& About\n#On Channel Page\n  Donate: Dona\n  Blog: Blog\n  GitHub issues: Segnalazioni GitHub\n  Report a problem: Segnala un problema\n  FAQ: Domande frequenti\n  FreeTube Wiki: Wiki FreeTube\n  Help: Aiuto\n  Downloads / Changelog: Download / Registro delle modifiche\n  GitHub releases: Versioni di GitHub\n  these people and projects: queste persone e questi progetti\n  Credits: Crediti\n  Translate: Traduzioni\n  room rules: regole stanza\n  Chat on Matrix: Chatta su Matrix\n  Mastodon: Mastodon\n  Email: E-mail\n  Website: Sito web\n  Please check for duplicates before posting: Controlla se ci sono duplicati prima di pubblicare\n  Source code: Codice sorgente\n  Beta: Beta\n  Discussions: Discussioni\n  AGPLv3: AGPLv3\n  FreeTube is made possible by {creditsPageLink}: FreeTube è reso possibile da {creditsPageLink}\n  Licensed under the {licenseLink}: Concesso in licenza con {licenseLink}\n  Please read the {roomRulesLink}: Per favore leggi il {roomRulesLink}\nChannel:\n  Subscribe: 'Iscriviti'\n  Unsubscribe: 'Disiscriviti'\n  Search Channel: 'Ricerca nel canale'\n  Your search results have returned 0 results: 'La tua ricerca ha prodotto 0 risultati'\n  Videos:\n    Videos: 'Video'\n    This channel does not currently have any videos: 'Questo canale attualmente non ha alcun video'\n    Sort Types:\n      Newest: 'Più nuovi'\n      Oldest: 'Più vecchi'\n      Most Popular: 'Più popolari'\n  Playlists:\n    Playlists: 'Playlist'\n    This channel does not currently have any playlists: 'Questo canale attualmente non ha alcuna playlist'\n    Sort Types:\n      Last Video Added: 'Ultimo video aggiunto'\n      Newest: 'Più nuovi'\n      Oldest: 'Più vecchi'\n  About:\n    About: 'Informazioni'\n    Channel Description: 'Descrizione canale'\n    Featured Channels: 'Canali in evidenza'\n    Tags:\n      Search for: Ricerca \"{tag}\"\n      Tags: Etichette\n    Details: Dettagli\n    Joined: Iscrizione\n    Location: Posizione\n  Added channel to your subscriptions: Il canale è stato aggiunto alle tue iscrizioni\n  Removed subscription from {count} other channel(s): È stata rimossa l'iscrizione dagli altri canali di {count}\n  Channel has been removed from your subscriptions: Il canale è stato rimosso dalle tue iscrizioni\n  This channel does not exist: Questo canale non esiste\n  This channel does not allow searching: Questo canale non consente la ricerca\n  Channel Tabs: Schede canale\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Questo canale è soggetto a limiti di età e al momento non può essere visualizzato su FreeTube.\n  Posts:\n    This channel currently does not have any posts: Questo canale attualmente non ha alcun post\n    votes: '{votes} voti'\n    Reveal Answers: Rivela le risposte\n    Hide Answers: Nascondi le risposte\n    Video hidden by FreeTube: Video nascosto da FreeTube\n    Viewing Posts Only Supported By Invidious: La visualizzazione dei post è supportata solo da Invidious. Vai alla scheda comunità di un canale per visualizzare i contenuti senza Invidious.\n    View Full Post: Visualizza il post completo\n  Live:\n    Live: Dal vivo\n    This channel does not currently have any live streams: Questo canale attualmente non ha alcun video dal vivo\n  Shorts:\n    This channel does not currently have any shorts: Questo canale attualmente non ha video brevi\n  Podcasts:\n    Podcasts: Podcast\n    This channel does not currently have any podcasts: Questo canale non ha attualmente alcun podcast\n  Releases:\n    Releases: Rilasci\n    This channel does not currently have any releases: Questo canale non ha attualmente alcun rilascio\n  Home:\n    Home: Pagina iniziale\n    View Playlist: Visualizza la playlist\n  Courses:\n    This channel does not currently have any courses: Questo canale al momento non ha corsi\n    Courses: Corsi\nVideo:\n  Mark As Watched: 'Contrassegna come guardato'\n  Remove From History: 'Rimuovi dalla Cronologia'\n  Video has been marked as watched: 'Il video è stato contrassegnato come guardato'\n  Video has been removed from your history: 'Il video è stato rimosso dalla Cronologia'\n  Open in YouTube: 'Apri con YouTube'\n  Copy YouTube Link: 'Copia link YouTube'\n  Open YouTube Embedded Player: 'Apri il lettore incorporato di YouTube'\n  Copy YouTube Embedded Player Link: 'Copia link del lettore incorporato di YouTube'\n  Open in Invidious: 'Apri con Invidious'\n  Copy Invidious Link: 'Copia link Invidious'\n  Views: 'Visualizzazioni'\n  Watched: 'Guardato'\n  # As in a Live Video\n  Live: 'Dal vivo'\n  Live Now: 'Dal vivo ora'\n  Live Chat: 'Chat dal vivo'\n  Enable Live Chat: 'Abilita chat dal vivo'\n  Live Chat is currently not supported in this build.: 'La chat dal vivo non è attualmente supportata in questa versione.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'La chat dal vivo è abilitata. I messaggi appariranno qui una volta inviati.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'La chat dal vivo non è attualmente supportata con le API di Invidious. È necessaria una connessione diretta a YouTube.'\n  Published:\n    In less than a minute: In meno di un minuto\n  Published on: 'Pubblicato il'\n#& Videos\n  Previous: Precedente\n  Next: Successivo\n  Reverse Playlist: Playlist al contrario\n  Shuffle Playlist: Riproduzione playlist casuale\n  Loop Playlist: Riproduzione continua playlist\n  Autoplay: Riproduzione automatica\n  Starting soon, please refresh the page to check again: La riproduzione partirà tra breve, aggiorna la pagina per ricontrollare\n  Copy Invidious Channel Link: Copia link canale Invidious\n  Open Channel in Invidious: Apri il canale con Invidious\n  Copy YouTube Channel Link: Copia link canale YouTube\n  Open Channel in YouTube: Apri il canale con YouTube\n  Started streaming on: Trasmissione iniziata il\n  Streamed on: Trasmesso il\n  Video has been removed from your saved list: Il video è stato rimosso dall'elenco\n  Video has been saved: Il video è stato salvato\n  Save Video: Salva il video\n  External Player:\n    Unsupported Actions:\n      looping playlists: riproduzione continua delle playlist\n      shuffling playlists: riproduzione casuale delle playlist\n      reversing playlists: invertire le playlist\n      opening specific video in a playlist (falling back to opening the video): apertura di un video specifico in una playlist (in caso di errore vai all'apertura del video)\n      setting a playback rate: impostazione di una velocità di riproduzione\n      opening playlists: apertura delle playlist\n      starting video at offset: avviare il video da un determinato punto\n    UnsupportedActionTemplate: '{externalPlayer} non supporta: {action}'\n    OpeningTemplate: Apertura di {videoOrPlaylist} con {externalPlayer}...\n    playlist: playlist\n    video: video\n    OpenInTemplate: Apri con {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Musica fuori tema\n    interaction: Interazione\n    self-promotion: Autopromozione\n    outro: Conclusione\n    intro: Introduzione\n    sponsor: Sponsor\n    recap: Ricapitolazione\n    filler: Riempitivo\n  Premieres: Première\n  Scroll to Bottom: Scorri fino in fondo\n  Show Super Chat Comment: Mostra commento Super Chat\n  Upcoming: In arrivo\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': La chat dal vivo non è disponibile per questo video. Potrebbe essere stata disattivata dall'autore del caricamento.\n  Unhide Channel: Mostra canale\n  Hide Channel: Nascondi canale\n  More Options: Più opzioni\n  Player:\n    TranslatedCaptionTemplate: '{language} (tradotto da \"{originalLanguage}\")'\n    Audio Tracks: Tracce audio\n    Theatre Mode: Modalità teatro\n    Exit Theatre Mode: Esci dalla Modalità teatro\n    Show Stats: Mostra statistiche\n    Stats:\n      Media Formats: 'Formati multimediali: {formats}'\n      Resolution: 'Risoluzione: {width}×{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensioni del lettore: {width}×{height}'\n      Stats: Statistiche\n      Video ID: 'ID video: {videoId}'\n      Bitrate: 'Bitrate: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Larghezza di banda: {bandwidth} kbps'\n      Buffered: 'Bufferizzato: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Fotogrammi persi: {droppedFrames} / Fotogrammi totali: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Codec: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codec: {videoCodec} / {audioCodec}'\n    Hide Stats: Nascondi statistiche\n    Full Window: Finestra intera\n    Exit Full Window: Esci da Finestra intera\n    Take Screenshot: Acquisisci screenshot\n    You appear to be offline: Sembra che tu sia offline.\n    Playback will resume automatically when your connection comes back: La riproduzione riprenderà automaticamente quando verrà ripristinata la connessione.\n    Skipped segment: Segmento {segmentCategory} saltato\n    Autoplay is off: La riproduzione automatica è disattivata\n    Autoplay is on: La riproduzione automatica è attiva\n  IP block: YouTube ha bloccato il tuo indirizzo IP impedendogli di guardare i video. Prova a passare a una VPN o a un proxy diverso.\n  Unlisted: Non elencato\n  MembersOnly: I video riservati agli abbonati non possono essere guardati con FreeTube, poiché richiedono l'accesso a Google e l'iscrizione a pagamento al canale dell'utente che li ha caricati.\n  AgeRestricted: I video con limiti di età non possono essere guardati con FreeTube poiché richiedono l'accesso a Google e l'utilizzo di un account YouTube con età verificata.\n  DeArrow:\n    Show Original Details: Mostra dettagli originali\n    Show Modified Details: Mostra dettagli modificati\n  DRMProtected: I video protetti da DRM non possono essere riprodotti in FreeTube, poiché richiedono componenti proprietari e closed source. Se vuoi guardare questo video, guardalo sul sito Web ufficiale di YouTube in un browser Web abilitato DRM.\n#& Playlists\n  Watched Progress Saved: Progresso guardato salvato\n  Save Watched Progress: Salva i progressi raggiunti\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': \"Tempo rimanente per l'annuncio preroll: {remindingTimeSeconds}s\"\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Tempo di backoff SABR rimanente: {remindingTimeSeconds}s'\n  Popout Live Chat: Chat popout\nPlaylist:\n  #& About\n  View Full Playlist: 'Guarda playlist completa'\n  Last Updated On: 'Ultimo aggiornamento il'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlist\n  Sort By:\n    Custom: Personalizzato\n    VideoTitleDescending: Titolo (Z-A)\n    AuthorDescending: Autore (Z-A)\n    AuthorAscending: Autore (A-Z)\n    DateAddedNewest: Data aggiunta (più recente)\n    DateAddedOldest: Data aggiunta (più vecchia)\n    VideoTitleAscending: Titolo (A-Z)\n    VideoDurationAscending: Durata (più breve)\n    VideoDurationDescending: Durata (più lunga)\n    PublishedNewest: Data di pubblicazione (più recente)\n    PublishedOldest: Data di pubblicazione (più vecchia)\nChange Format:\n  Change Media Formats: 'Cambia formato video'\n  Use Dash Formats: 'Usa i formati DASH'\n  Use Legacy Formats: 'Usa i formati compatibili'\n  Use Audio Formats: 'Usa i formati audio'\n  Audio formats are not available for this video: I formati audio non sono disponibili per questo video\n  Dash formats are not available for this video: I formati DASH non sono disponibili per questo video\n  Legacy formats are not available for this video: I formati compatibili non sono disponibili per questo video\nShare:\n  Share Video: 'Condividi video'\n  Share Playlist: 'Condividi playlist'\n  Copy Link: 'Copia link'\n  Open Link: 'Apri link'\n  Copy Embed: 'Copia codice da incorporare'\n  Open Embed: 'Apri codice da incorporare'\n  # On Click\n  Invidious URL copied to clipboard: 'URL di Invidious copiato negli appunti'\n  Invidious Embed URL copied to clipboard: 'URL di incorporamento di Invidious copiato negli appunti'\n  YouTube URL copied to clipboard: 'URL di YouTube copiato negli appunti'\n  YouTube Embed URL copied to clipboard: 'URL di incorporamento di YouTube copiato negli appunti'\n  Include Timestamp: Includi indicazione temporale\n  YouTube Channel URL copied to clipboard: URL del canale YouTube copiato negli appunti\n  Invidious Channel URL copied to clipboard: URL del canale Invidious copiato negli appunti\n  Share Channel: Condividi canale\n  Share Post: Condividi post\nMini Player: 'Mini visualizzatore'\nComments:\n  Comments: 'Commenti'\n  Click to View Comments: 'Fai clic per vedere i commenti'\n  Getting comment replies, please wait: 'Sto scaricando le risposte ai commenti, per favore attendi'\n  Hide Comments: 'Nascondi i commenti'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Non ci sono commenti disponibili per questo video'\n  Load More Comments: 'Carica più commenti'\n  There are no more comments for this video: Non ci sono più commenti per questo video\n  Top comments: Commenti migliori\n  Newest first: I più nuovi\n  Show More Replies: Mostra altre risposte\n  Pinned by: Messo in primo piano da\n  Member: Membro\n  Hearted: Di cuore\n  View {replyCount} replies: Visualizza 1 risposta | Visualizza {replyCount} risposte\n  Subscribed: Iscritto\n  There are no comments available for this post: Non ci sono commenti disponibili per questo post\n  Hide {replyCount} replies: Nascondi 1 risposta | Nascondi {replyCount} risposte\n  View 1 reply from {channelName}: Visualizza 1 risposta da {channelName}\n  View {replyCount} replies from {channelName} and others: Visualizza {replyCount} risposte da {channelName} e altri\nUp Next: 'Prossimi video'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Errore API locale (fai clic per copiare)'\nInvidious API Error (Click to copy): 'Errore API Invidious (fai clic per copiare)'\nFalling back to Invidious API: 'Torno alle API Invidious'\nFalling back to Local API: 'Torno alle API locali'\nLoop is now disabled: 'Il loop è ora disabilitato'\nLoop is now enabled: 'Il loop è ora abilitato'\nShuffle is now disabled: 'La riproduzione casuale è disabilitata'\nShuffle is now enabled: 'La riproduzione casuale è abilitata'\nPlaying Next Video: 'Riproduzione del video successivo'\nPlaying Previous Video: 'Riproduzione del video precedente'\nCanceled next video autoplay: 'Riproduzione automatica del prossimo video annullata'\n'The playlist has ended. Enable loop to continue playing': 'La playlist è terminata. Abilita la riproduzione a ciclo continuo per continuare la riproduzione'\n\nYes: 'Sì'\nNo: 'No'\nA new blog is now available, {blogTitle}. Click to view more: 'Un nuovo blog è ora disponibile, {blogTitle}. Fai clic per saperne di più'\nVersion {versionNumber} is now available!  Click for more details: La versione {versionNumber} è ora disponibile! Fai clic per maggiori dettagli\nDownload From Site: Scarica dal sito\nThe playlist has been reversed: La playlist è stata invertita\nProfile:\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Sei sicuro di voler eliminare i canali selezionati? L'operazione non eliminerà i canali da nessun altro profilo.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Questo è il tuo profilo primario. Sei sicuro di voler eliminare i canali selezionati? Gli stessi canali saranno eliminati da ogni profilo in cui sono presenti.\n  No channel(s) have been selected: Nessun canale è stato selezionato\n  Add Selected To Profile: Aggiungi i selezionati al profilo\n  Delete Selected: Elimina i selezionati\n  Select None: Deseleziona tutto\n  Select All: Seleziona tutto\n  '{number} selected': '{number} selezionato'\n  Other Channels: Altri canali\n  Subscription List: Elenco iscrizioni\n  '{profile} is now the active profile': '{profile} è diventato il tuo profilo attivo'\n  Your default profile has been changed to your primary profile: Il tuo profilo predefinito è stato cambiato in profilo primario\n  Removed {profile} from your profiles: Hai rimosso {profile} dai tuoi profili\n  Your default profile has been set to {profile}: '{profile} è stato impostato come profilo predefinito'\n  Profile has been updated: Il profilo è stato aggiornato\n  Profile has been created: Il profilo è stato creato\n  Your profile name cannot be empty: Il nome del profilo non può essere vuoto\n  All subscriptions will also be deleted.: Tutte le iscrizioni saranno eliminate.\n  Are you sure you want to delete this profile?: Sei sicuro di voler eliminare questo profilo?\n  Delete Profile: Elimina profilo\n  Make Default Profile: Imposta come profilo predefinito\n  Update Profile: Aggiorna profilo\n  Create Profile: Crea profilo\n  Profile Preview: Anteprima del profilo\n  Custom Color: Colore personalizzato\n  Color Picker: Selettore del colore\n  Edit Profile: Modifica il profilo\n  Create New Profile: Crea un nuovo profilo\n  Profile Manager: Gestione dei profili\n  All Channels: Tutti i canali\n  Profile Select: Seleziona il profilo\n  Profile Filter: Filtro del profilo\n  Profile Settings: Profilo\n  Toggle Profile List: Attiva/disattiva elenco profili\n  Open Profile Dropdown: Apri il menu a discesa del profilo\n  Close Profile Dropdown: Chiudi il menu a discesa del profilo\n  Profile Name: Nome del profilo\n  Edit Profile Name: Modifica il nome del profilo\n  Create Profile Name: Crea un nome per il profilo\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Questo video non è disponibile a causa di alcuni formati mancanti. Questo può succedere in caso di mancata disponibilità della nazione.\nTooltips:\n  Player Settings:\n    Default Video Format: Imposta i formati usati quando un video viene riprodotto. I formati DASH possono riprodurre qualità maggiore. I formati compatibili sono limitati ad un massimo di 360p ma usano meno banda. I formati audio riproducono solo l'audio.\n    Proxy Videos Through Invidious: Connessione a Invidious per riprodurre i video invece di una connessione diretta a YouTube.\n    Scroll Playback Rate Over Video Player: Mentre il cursore si trova sul video, tieni premuto il tasto Control (Command su Mac) e ruota la rotellina del mouse in avanti o all'indietro per regolare la velocità di riproduzione. Tieni premuto il tasto Control (Command su Mac) e fai clic con il tasto sinistro del mouse per tornare rapidamente alla velocità di riproduzione predefinita (1x, a meno che non sia stata modificata nelle impostazioni).\n    Skip by Scrolling Over Video Player: Usa la rotella di scorrimento per saltare il video, in stile MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: Se abilitato, FreeTube userà gli RSS invece del metodo standard per leggere le iscrizioni. Gli RSS sono più veloci e impediscono il blocco dell'IP, ma non forniscono determinate informazioni come la durata del video, lo stato dal vivo o i post\n    Fetch Automatically: Se abilitato, FreeTube recupererà automaticamente il feed delle tue iscrizioni all'avvio e quando viene aperta una nuova finestra.\n  General Settings:\n    Invidious Instance: Istanza Invidious che FreeTube usa per le chiamate API.\n    Thumbnail Preference: Tutte le miniature su FreeTube verranno sostituite con un fotogramma del video, sfocato o nascosto al posto della miniatura predefinita.\n    Fallback to Non-Preferred Backend on Failure: Quando le API preferite hanno un problema, FreeTube userà automaticamente le API secondarie come riserva (se abilitate).\n    Preferred API Backend: Scegli il backend usato da FreeTube per ottenere i dati. Le API locali sono integrate nel programma. Le API Invidious richiedono un server Invidious al quale connettersi.\n    Region for Trending: La regione delle tendenze permette di scegliere la nazione di cui si vogliono vedere i video di tendenza.\n    External Link Handling: \"Scegli il comportamento predefinito quando si fa clic su un link che non può essere aperto in FreeTube.\\nPer impostazione predefinita, FreeTube aprirà il link cliccato nel browser predefinito.\\n\"\n    Open Deep Links In New Window: Gli URL passati a FreeTube, ad esempio tramite estensioni del browser di reindirizzamento o argomenti della riga di comando, vengono aperti in una nuova finestra.\n  External Player Settings:\n    Ignore Warnings: Non notifica gli avvisi quando il lettore esterno selezionato non supporta l'azione richiesta (ad esempio invertire la playlist, etc.).\n    Custom External Player Arguments: Invia al lettore esterno qualsiasi argomento personalizzato dalla linea di comando.\n    Custom External Player Executable: Per impostazione predefinita, FreeTube imposta il lettore esterno scelto tramite la variabile d'ambiente PATH. Se necessario, un percorso personalizzato può essere impostato qui.\n    External Player: Scegliendo un lettore esterno sarà visualizzata sulla miniatura un'icona per aprire il video nel lettore esterno (se la playlist lo supporta). Attenzione, le Impostazioni Invidious non influiscono sui lettori esterni.\n    DefaultCustomArgumentsTemplate: '(Predefinito: {defaultCustomArguments})'\n    Ignore Default Arguments: Non inviare argomenti predefiniti al lettore esterno oltre all'URL del video (ad esempio velocità di riproduzione, URL della playlist, ecc.). Gli argomenti personalizzati verranno comunque trasmessi.\n  Experimental Settings:\n    Replace HTTP Cache: Disabilita la cache HTTP basata su disco Electron e abilita una cache di immagini in memoria personalizzata. Comporta un aumento dell'uso della RAM.\n  Distraction Free Settings:\n    Hide Channels: Inserisci l'ID di un canale per impedire che tutti i video, le playlist e il canale stesso vengano visualizzati nelle ricerche, tendenze, più popolari e consigliati. Il nome del canale inserito deve avere una corrispondenza completa e fa distinzione tra maiuscole e minuscole.\n    Hide Subscriptions Live: Questa impostazione è sovrascritta dall'impostazione \"{appWideSetting}\" a livello di app, nella sezione \"{subsection}\" di \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Inserisci una parola, un frammento di parola o una frase (senza distinzione tra maiuscole e minuscole) per nascondere tutti i video e le playlist i cui titoli originali la contengono in tutto FreeTube, escludendo solo Cronologia, Le tue playlist e i video all'interno delle playlist.\n    Hide Videos on Watch: Nasconde i video guardati dalle schede Video, Video brevi e Dal vivo nelle pagine Iscrizioni e Canali. Questo non influisce sulla scheda Pagina iniziale nelle pagine Canali\n  SponsorBlock Settings:\n    UseDeArrowTitles: Sostituisci i titoli dei video coi titoli inviati dagli utenti di DeArrow.\n    UseDeArrowThumbnails: Sostituisci le miniature dei video con le miniature di DeArrow.\nPlaying Next Video Interval: Riproduzione del video successivo tra un attimo. Fai clic per annullare. | Riproduzione del video successivo tra {nextVideoInterval} secondi. Fai clic per annullare. | Riproduzione del video successivo tra {nextVideoInterval} secondi. Fai clic per annullare.\nMore: Altro\nOpen New Window: Apri una nuova finestra\nDefault Invidious instance has been cleared: L'istanza predefinita di Invidious è stata cancellata\nDefault Invidious instance has been set to {instance}: L'istanza predefinita di Invidious è stata impostata a {instance}\nUnknown YouTube url type, cannot be opened in app: Tipo di URL YouTube sconosciuto, impossibile aprirlo nell'app\nSearch Bar:\n  Clear Input: Pulisci ricerca\n  Remove: Rimuovi\nExternal link opening has been disabled in the general settings: L'apertura dei link esterni è stata disabilitata nelle Impostazioni generali\nAre you sure you want to open this link?: Sei sicuro di voler aprire questo link?\nScreenshot Success: Screenshot salvato\nScreenshot Error: Screenshot non riuscito. {error}\nNew Window: Nuova finestra\nChannels:\n  Title: Elenco canali\n  Channels: Canali\n  Search bar placeholder: Ricerca canali\n  Count: '{number} canali trovati.'\n  Empty: L'elenco dei tuoi canali è attualmente vuoto.\n  Unsubscribe Prompt: Sei sicuro di voler annullare l'iscrizione a \"{channelName}\"?\nClipboard:\n  Cannot access clipboard without a secure connection: Impossibile accedere agli appunti senza una connessione sicura\n  Copy failed: Copia negli appunti non riuscita\nChapters:\n  Chapters: Capitoli\n  Key Moments: Momenti chiave\nPreferences: Preferenze\nOk: OK\nHashtag:\n  This hashtag does not currently have any videos: Questo hashtag attualmente non ha alcun video\n  Hashtag: Hashtag\nChannel Hidden: '{channel} aggiunto al filtro canali'\nGo to page: Vai a {page}\nChannel Unhidden: '{channel} rimosso dal filtro canali'\nTag already exists: Il tag \"{tagName}\" esiste già\nTrimmed input must be at least N characters long: L'input troncato deve essere lungo almeno 1 carattere | L'input troncato deve essere lungo almeno {length} caratteri\nAge Restricted:\n  This video is age restricted: Questo video è soggetto a limiti di età\n  This channel is age restricted: Questo canale è soggetto a limiti di età\nClose Banner: Chiudi banner\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nMoments Ago: pochi istanti fa\nFeed:\n  Feed Last Updated: 'Ultimo aggiornamento del feed {feedName}: {date}'\n  Refresh Feed: Aggiorna {subscriptionName}\nYes, Delete: Sì, elimina\nYes, Restart: Sì, riavvia\nYes, Open Link: Sì, apri link\nCancel: Annulla\nSearch character limit: La query di ricerca supera il limite di caratteri {searchCharacterLimit}\nSearch Listing:\n  Label:\n    4K: 4K\n    Closed Captions: Sottotitoli per non udenti\n    Subtitles: Sottotitoli\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nuovo\n    3D: 3D\nshortcutJoinOperator: +\nKeys:\n  ctrl: Ctrl\n  arrowdown: Freccia giù\n  arrowleft: Freccia sinistra\n  arrowright: Freccia destra\n  arrowup: Freccia su\n  alt: Alt\n  shift: Shift\n  enter: Enter\n  plus: Più\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: Fai clic con il tasto destro o tieni premuto per visualizzare la Cronologia\nAutoplay Interruption Timer: Riproduzione automatica annullata a causa di {autoplayInterruptionIntervalHours} ore di inattività\nDescription:\n  Expand Description: '...di più'\n  Collapse Description: Mostra meno\nKeyboardShortcutPrompt:\n  Focus Secondary Search: Focus sulla barra di ricerca secondaria (se presente)\n  Navigate to History: Vai alla pagina Cronologia\n  Refresh: Aggiorna il feed con i contenuti più recenti\n  New Window: Crea una nuova finestra\n  Navigate to Settings: Vai alla pagina Impostazioni\n  Keyboard Shortcuts: Scorciatoie da tastiera\n  Sections:\n    Video:\n      Playback: 'Video: Riproduzione'\n      General: 'Video: Generale'\n    App:\n      Situational: 'App: Situazionali'\n      General: 'App: Generale'\n  Show Keyboard Shortcuts: Mostra le scorciatoie da tastiera\n  History Backward: Torna indietro di una pagina\n  History Forward: Vai avanti di una pagina\n  Stats: Mostra le statistiche video\n  Fullscreen: Attiva/disattiva schermo intero\n  Picture in Picture: Attiva/disattiva la modalità Picture-in-Picture\n  Play: Attiva/disattiva riproduzione/pausa\n  Large Fast Forward: Avanti di 10 secondi / Avanzamento rapido del video in base alla velocità di riproduzione video attuale\n  Decrease Video Speed: Riduci la velocità del video in base all'intervallo di velocità di riproduzione video\n  Increase Video Speed: Aumenta la velocità del video in base all'intervallo di velocità di riproduzione video\n  Full Window: Attiva/disattiva finestra intera\n  Toggle Developer Tools: Attiva/disattiva gli strumenti per sviluppatori\n  Reset Zoom: Ripristina livello zoom / scala interfaccia utente\n  Theatre Mode: Attiva/disattiva la modalità teatro\n  Zoom Out: Rimpicciolisci\n  Zoom In: Ingrandisci\n  Search in New Window: Ricerca in una nuova finestra\n  Small Rewind: Riavvolgi X secondi in base all'intervallo di riavvolgimento e alla velocità di riproduzione video attuale\n  Last Chapter: Ultimo capitolo\n  Skip by Tenths: Salta il video in percentuale (3 salti al 30% della durata)\n  Large Rewind: Riavvolgi 10 secondi / Riavvolgi il video in base alla velocità di riproduzione video attuale\n  Last Frame: Fotogramma precedente (mentre è in pausa)\n  Small Fast Forward: Avanzamento rapido di X secondi in base all'intervallo di avanzamento rapido e alla velocità di riproduzione video attuale\n  Focus Search: Focus sulla barra di ricerca\n  Captions: Attiva/disattiva le didascalie\n  Mute: Attiva/disattiva audio\n  Take Screenshot: Fai uno screenshot\n  Minimize Window: Riduci a icona la finestra\n  Close Window: Chiudi la finestra\n  Next Chapter: Prossimo capitolo\n  Next Frame: Fotogramma successivo (mentre è in pausa)\n  Volume Up: Aumenta il volume\n  Volume Down: Diminuisci il volume\n  End: Vai alla fine del video\n  Home: Vai all'inizio del video\n  Skip to Next Video: Salta al video successivo in una playlist o al video consigliato successivo\n  Skip to Previous Video: Salta al video precedente in una playlist\nshortcutLabelSeparator: ｜\nExpand side navigation: Espandi la navigazione laterale\nCompact side navigation: Compatta la navigazione laterale\n"
  },
  {
    "path": "static/locales/ja.yaml",
    "content": "# Webkit Menu Bar\nFile: 'ファイル'\nQuit: '終了'\nEdit: '編集'\nUndo: '元に戻す'\nRedo: 'やり直し'\nCut: '切り取り'\nCopy: 'コピー'\nPaste: '貼り付け'\nDelete: '削除'\nSelect all: 'すべて選択'\nToggle Developer Tools: '開発者ツールの切替'\nActual size: '実際のサイズ'\nZoom in: '拡大'\nZoom out: '縮小'\nToggle fullscreen: '全画面の切替'\nWindow: 'ウィンドウ'\nMinimize: '最小化'\nClose: '閉じる'\nBack: '戻る'\nForward: '進む'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: '動画'\n  Shorts: ショート動画\n  Live: ライブ配信\n  Posts: 投稿\n  Sort By: 並び替え\n\n# Search Bar\n  Counts:\n    Video Count: 1 件の動画 | {count} 件の動画\n    Subscriber Count: 1 登録者 | {count} 登録者\n    View Count: 1 回視聴 | {count} 回視聴\n    Watching Count: 1 人が視聴中 | {count} 人が視聴中\n    Channel Count: 1 チャンネル | {count} チャンネル\n    Comment Count: 1 コメント｜{count} コメント\n    Like Count: 1 いいね｜{count} いいね\nSearch / Go to URL: '検索 / URL に移動'\n  # In Filter Button\nSearch Filters:\n  Search Filters: '検索の絞り込み'\n  Sort By:\n    Most Relevant: '関連度'\n    Rating: '評価'\n    Upload Date: 'アップロード日'\n    View Count: '再生数'\n  Time:\n    Time: '日時'\n    Any Time: '期間指定なし'\n    Last Hour: '1 時間以内'\n    Today: '今日'\n    This Week: '今週'\n    This Month: '今月'\n    This Year: '今年'\n  Type:\n    Type: '種類'\n    All Types: '種類指定なし'\n    Videos: '動画'\n    Channels: 'チャンネル'\n    #& Playlists\n    Movies: 映画\n  Duration:\n    Duration: '動画時間'\n    All Durations: 'すべての長さ'\n    Short (< 4 minutes): '短編（< 4 分未満）'\n    Long (> 20 minutes): '長編（> 20 分以上）'\n  # On Search Page\n    Medium (4 - 20 minutes): 中編（4 - 20 分間）\n  Search Results: '検索結果'\n  Fetching results. Please wait: '結果の取得中。お待ちください'\n  Fetch more results: 'もっと見る'\n# Sidebar\n  There are no more results for this search: 検索結果はこれ以上ありません\n  Features:\n    Features: 特徴\n    3D: 3D\n    VR180: VR180\n    4K: 4K\n    HD: HD\n    Live: ライブ\n    Subtitles: 字幕\n    HDR: HDR\n    Creative Commons: クリエイティブ・コモンズ\n    Location: 場所\n    360 Video: 360° 動画\n  Clear Filters: フィルターをクリア\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: '登録チャンネル'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': '登録チャンネルリストは現在空です。登録チャンネルをインポートするには、設定からデータの設定に移動して登録チャンネルをインポートするか、チャンネルを検索して登録することができます。'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: このプロファイルの登録チャンネル数が多いようです。接続制限を回避するため RSS を使用します\n  Load More Videos: もっと見る\n  Error Channels: エラーが発生したチャンネル\n  Disabled Automatic Fetching: 登録チャンネルの自動取得が無効になっています。動画を表示するには更新をしてください。\n  Empty Channels: 現在、チャンネル登録しているチャンネルには動画がありません。\n  Subscriptions Tabs: 登録チャンネル タブ\n  All Subscription Tabs Hidden: 全ての登録チャンネル タブが非表示になっています。こちらのコンテンツをご覧いただくには、\"{settingsSection}\" 内の \"{subsection}\" 項目でいくつかのタブの非表示を解除してください。\n  Load More Posts: もっと見る\n  Empty Posts: 現在、登録しているチャンネルには動画はありません。\nTrending:\n  Trending: '急上昇'\n  Trending Tabs: 急上昇のタブ\n  Gaming: ゲーム\n  Sports: スポーツ\nMost Popular: '人気'\nPlaylists: '再生リスト'\nUser Playlists:\n  Your Playlists: 'あなたの再生リスト'\n  Search bar placeholder: 再生リストの検索\n  Empty Search Message: この再生リストに、検索に一致する動画はありません\n  This playlist currently has no videos.: 現在、この再生リストには動画がありません。\n  Create New Playlist: 新しい再生リストの作成\n  Sort By:\n    NameAscending: A-Z\n    EarliestCreatedFirst: 作成日（古い順）\n    LatestUpdatedFirst: 更新日（新しい順）\n    EarliestUpdatedFirst: 更新日（古い順）\n    EarliestPlayedFirst: 再生日（古い順）\n    LatestPlayedFirst: 再生日（新しい順）\n    LatestCreatedFirst: 作成日（新しい順）\n    NameDescending: Z-A\n  Remove from Favorites: '{playlistName} から削除'\n  Move Video Down: 動画を下へ移動\n  Playlist Name: 再生リストの名前\n  Remove from Playlist: 再生リストから削除\n  Playlist Description: 再生リストの説明\n  Copy Playlist: 再生リストのコピー\n  Edit Playlist Info: 再生リスト情報の編集\n  Remove Watched Videos: 視聴済み動画の削除\n  Enable Quick Bookmark With This Playlist: この再生リストでクイックブックマークを有効にする\n  SinglePlaylistView:\n    Toast:\n      This playlist is protected and cannot be removed.: この再生リストは保護されており、削除できません。\n      This video cannot be moved down.: この動画は下に移動できません.\n      This video cannot be moved up.: この動画は上に移動できません.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 再生リスト内のすべての動画が読み込まれていません。とにかくコピーするにはここをクリック。\n      There was an issue with updating this playlist.: この再生リストの更新に問題が発生しました。\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: この再生リストは、{oldPlaylistName} の代わりにクイックブックマークとして使用されるようになりました。元に戻すにはここをクリック\n      Video has been removed: 動画は削除されました\n      There was a problem with removing this video: この動画の削除に問題が発生しました\n      This playlist is now used for quick bookmark: このプレイリストは現在、クイックブックマークとして使用されています\n      Playlist has been updated.: 再生リストを更新しました。\n      Playlist name cannot be empty. Please input a name.: 再生リストの名前は空白にできません。名前を入力してください.\n      Reverted to use {oldPlaylistName} for quick bookmark: クイックブックマークを {oldPlaylistName} に戻しました\n      \"{videoCount} video(s) have been removed\": 1 本の動画を削除しました | {videoCount} 本の動画を削除しました\n      Playlist {playlistName} has been deleted.: 再生リスト {playlistName} が削除されました。\n      There were no videos to remove.: 削除する動画はありません。\n      This playlist does not exist: この再生リストは存在しません\n      This playlist is already being used for quick bookmark.: この再生リストはすでにクイックブックマークとして使用されています。\n      This playlist has a video with a duration error: このプレイリストには、再生時間のない動画が少なくとも 1 つ含まれています。これらの動画は、再生時間が 0 であるかのように並べられます。\n      Video has been removed. Click here to undo.: 動画が削除されました。元に戻すにはここをクリック。\n    Search for Videos: 動画検索\n  Save Changes: 変更の保存\n  Move Video Up: 動画を上へ移動\n  Add to Favorites: '{playlistName} に追加'\n  Playlists with Matching Videos: 動画付き再生リスト\n  Add to Playlist: 再生リストに追加\n  Delete Playlist: 再生リストの削除\n  Cancel: キャンセル\n  Are you sure you want to delete this playlist? This cannot be undone: この再生リストを削除してもいいですか？復元は不可能です。\n  You have no playlists. Click on the create new playlist button to create a new one.: 再生リストがありません。新しい再生リストを作成するには、「新しい再生リストの作成」ボタンをクリックしてください。\n  AddVideoPrompt:\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} 本の動画が追加されます'\n    Select a playlist to add your N videos to: 動画を追加する再生リストを選択してください | {videoCount} 本の動画を追加する再生リストを選択してください\n    Allow Adding Duplicate Video(s): 重複した動画の追加を許可する\n    Toast:\n      You haven't selected any playlist yet.: まだ再生リストを選択していません。\n      \"Video(s) added to {playlistCount} playlists\": \"動画を {playlistCount} 個の再生リストに追加しました\"\n    Search in Playlists: 再生リストで検索\n    N playlists selected: '{playlistCount} 選択中'\n    Save: 保存\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} 本の動画はすでに追加されています'\n    Added {count} Times: すでに追加済み | {count} 回追加済み\n  CreatePlaylistPrompt:\n    Toast:\n      There was an issue with creating the playlist.: 再生リストの作成中に問題が発生しました。\n      There is already a playlist with this name. Please pick a different name.: この名前の再生リストはすでに存在します。別の名前を選んでください。\n      Playlist {playlistName} has been successfully created.: 再生リスト {playlistName} が正常に作成されました。\n    New Playlist Name: 新しい再生リスト名\n    Create: 作成\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: この再生リストから重複する1本の動画を削除してもよろしいですか？この操作は元に戻せません。 | この再生リストから重複する {playlistItemCount} 本の動画を削除してもよろしいですか？この操作は元に戻せません。\n  Cannot delete the quick bookmark target playlist.: クイックブックマーク対象の再生リストは削除できません。\n  Quick Bookmark Enabled: クイックブックマーク有効\n  Remove Duplicate Videos: 重複した動画を削除\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: この再生リストから視聴済みの動画を1本削除してもよろしいですか？この操作は元に戻せません。 | この再生リストから視聴済みの {playlistItemCount} 本の動画を削除してもよろしいですか？この操作は元に戻せません。\n  The playlist has been successfully exported: 再生リストのエクスポートに成功しました\n  Export Playlist: この再生リストをエクスポート\n  TotalTimePlaylist: '合計時間: {duration}'\n  Export list of URLs: URL のリストをエクスポート\nHistory:\n  # On History Page\n  History: '履歴'\n  Watch History: '視聴履歴'\n  Your history list is currently empty.: 現在、履歴リストは空です。\n  Search bar placeholder: 履歴の検索\n  Empty Search Message: 検索条件に一致する動画は履歴にありません\n  Case Sensitive Search: 大文字小文字を区別した検索\n  DateOldestHistory: 視聴日（古い順）\n  DateNewestHistory: 視聴日（新しい順）\nSettings:\n  # On Settings Page\n  Settings: '設定'\n  General Settings:\n    General Settings: '一般'\n    Fallback to Non-Preferred Backend on Failure: 'データ取得の問題発生時には取得方法を自動変更'\n    Enable Search Suggestions: '検索候補の有効化'\n    Default Landing Page: '起動時の表示'\n    Locale Preference: '言語設定'\n    Preferred API Backend:\n      Preferred API Backend: 'データ取得方法の選択'\n      Local API: '内部 API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: '動画一覧の表示方法'\n      Grid: 'グリッド'\n      List: 'リスト'\n    Thumbnail Preference:\n      Thumbnail Preference: 'サムネイルの設定'\n      Default: 'デフォルト'\n      Beginning: '開始'\n      Middle: '中間'\n      End: '最後'\n      Hidden: 非表示\n      Blur: ぼかし\n    Region for Trending: '急上昇の地域設定'\n        #! List countries\n    Check for Latest Blog Posts: 新着ブログの確認\n    Check for Updates: 更新の確認\n    View all Invidious instance information: すべての Invidious インスタンス情報の表示\n    System Default: システム初期設定\n    Clear Default Instance: 既定のインスタンスをクリア\n    Set Current Instance as Default: 現在のインスタンスを既定として設定する\n    Current instance will be randomized on startup: 現在のインスタンスは起動時にランダム化されます\n    No default instance has been set: 既定のインスタンスが設定されていません\n    The currently set default instance is {instance}: 現在設定されているインスタンスは {instance} です\n    Current Invidious Instance: 現在の invidious インスタンス\n    External Link Handling:\n      No Action: 何もしない\n      Ask Before Opening Link: リンクを開く前に確認\n      Open Link: リンクの表示\n      External Link Handling: 外部リンク処理\n    Auto Load Next Page:\n      Label: 次のページを自動で読み込む\n      Tooltip: 追加のページやコメント欄の続きを自動的に読み込みます。\n    Open Deep Links In New Window: FreeTube に渡された URL を新しいウィンドウで開く\n    Minimize to system tray: システムトレイに最小化\n  Theme Settings:\n    Theme Settings: 'テーマ'\n    Match Top Bar with Main Color: '上部のバーをメインカラーに合わせる'\n    Base Theme:\n      Base Theme: 'テーマの選択'\n      Black: '黒'\n      Dark: 'ダーク'\n      Light: 'ライト'\n      Dracula: 'ドラキュラ'\n      System Default: システム初期設定\n      Catppuccin Mocha: キャプチーノ・モカ\n      Pastel Pink: パステルピンク\n      Hot Pink: ホットピンク\n      Nordic: ノルディック\n      Solarized Dark: ソラライズド・ダーク\n      Solarized Light: ソラライズド・ライト\n      Gruvbox Dark: Gruvbox ダーク\n      Gruvbox Light: Gruvbox ライト\n      Catppuccin Frappe: キャプチーノ・フラッペ\n      Everforest Dark Low: エバーフォレスト・ダーク・ロー\n      Everforest Light Hard: エバーフォレスト・ライト・ハード\n      Everforest Light Medium: エバーフォレスト・ライト・ミディアム\n      Everforest Light Low: エバーフォレスト・ライト・ロー\n      Everforest Dark Hard: エバーフォレスト・ダーク・ハード\n      Everforest Dark Medium: エバーフォレスト・ダーク・ミディアム\n      Catppuccin Latte: キャプチーノ・ラテ\n    Main Color Theme:\n      Main Color Theme: 'テーマのメイン カラー'\n      Red: '赤'\n      Pink: '桃'\n      Purple: '紫'\n      Deep Purple: '濃い紫'\n      Indigo: '藍'\n      Blue: '青'\n      Light Blue: '明るい青'\n      Cyan: 'シアン'\n      Teal: '青緑'\n      Green: '緑'\n      Light Green: '明るい緑'\n      Lime: 'ライム'\n      Yellow: '黄'\n      Amber: '琥珀'\n      Orange: 'オレンジ'\n      Deep Orange: '濃いオレンジ'\n      Dracula Cyan: 'ドラキュラ シアン'\n      Dracula Green: 'ドラキュラ 緑'\n      Dracula Orange: 'ドラキュラ オレンジ'\n      Dracula Pink: 'ドラキュラ 桃'\n      Dracula Purple: 'ドラキュラ 紫'\n      Dracula Red: 'ドラキュラ 赤'\n      Dracula Yellow: 'ドラキュラ 黄'\n      Catppuccin Mocha Rosewater: キャプチーノ・モカ 淡いピンク\n      Catppuccin Mocha Flamingo: キャプチーノ・モカ 明るいピンク\n      Catppuccin Mocha Pink: キャプチーノ・モカ ピンク\n      Catppuccin Mocha Mauve: キャプチーノ・モカ 淡い紫\n      Catppuccin Mocha Red: キャプチーノ・モカ 赤色\n      Catppuccin Mocha Maroon: キャプチーノ・モカ 暗い赤茶色\n      Catppuccin Mocha Peach: キャプチーノ・モカ 桃色\n      Catppuccin Mocha Yellow: キャプチーノ・モカ 黄色\n      Catppuccin Mocha Green: キャプチーノ・モカ 緑色\n      Catppuccin Mocha Teal: キャプチーノ・モカ 青緑\n      Catppuccin Mocha Sky: キャプチーノ・モカ 空色\n      Catppuccin Mocha Sapphire: キャプチーノ・モカ 深い青\n      Catppuccin Mocha Blue: キャプチーノ・モカ 青色\n      Catppuccin Mocha Lavender: キャプチーノ・モカ 淡い紫\n      Solarized Yellow: ソラライズド・イエロー\n      Solarized Orange: ソラライズド・オレンジ\n      Solarized Red: ソラライズド・レッド\n      Solarized Magenta: ソラライズド・マジェンタ\n      Solarized Violet: ソラライズド・バイオレット\n      Solarized Cyan: ソラライズド・シアン\n      Solarized Green: ソラライズド・グリーン\n      Solarized Blue: ソラライズド・ブルー\n      Gruvbox Dark Green: Gruvbox ダークグリーン\n      Gruvbox Dark Blue: Gruvbox ダークブルー\n      Gruvbox Dark Aqua: Gruvbox ダークアクア\n      Gruvbox Light Red: Gruvbox ライトレッド\n      Gruvbox Light Blue: Gruvbox ライトブルー\n      Gruvbox Light Purple: Gruvbox ライトパープル\n      Gruvbox Dark Orange: Gruvbox ダークオレンジ\n      Gruvbox Dark Yellow: Gruvbox ダークイエロー\n      Gruvbox Dark Purple: Gruvbox ダークパープル\n      Gruvbox Light Orange: Gruvbox ライトオレンジ\n      Catppuccin Frappe Sky: キャプチーノ・フラッペ スカイ\n      Catppuccin Frappe Rosewater: キャプチーノ・フラッペ ローズウォーター\n      Catppuccin Frappe Flamingo: キャプチーノ・フラッペ フラミンゴ\n      Catppuccin Frappe Pink: キャプチーノ・フラッペ ピンク\n      Catppuccin Frappe Mauve: キャプチーノ・フラッペ モーブ\n      Catppuccin Frappe Red: キャプチーノ・フラッペ レッド\n      Catppuccin Frappe Maroon: キャプチーノ・フラッペ マルーン\n      Catppuccin Frappe Peach: キャプチーノ・フラッペ ピーチ\n      Catppuccin Frappe Yellow: キャプチーノ・フラッペ イエロー\n      Catppuccin Frappe Green: キャプチーノ・フラッペ グリーン\n      Catppuccin Frappe Teal: キャプチーノ・フラッペ ティール\n      Catppuccin Frappe Blue: キャプチーノ・フラッペ ブルー\n      Catppuccin Frappe Lavender: キャプチーノ・フラッペ ラベンダー\n      Catppuccin Frappe Sapphire: キャプチーノ・フラッペ サファイア\n      Everforest Dark Orange: エバーフォレスト・ダークオレンジ\n      Everforest Dark Aqua: エバーフォレスト・ダークアクア\n      Everforest Dark Blue: エバーフォレスト・ダークブルー\n      Everforest Light Red: エバーフォレスト・ライトレッド\n      Everforest Light Green: エバーフォレスト・ライトグリーン\n      Everforest Light Aqua: エバーフォレスト・ライトアクア\n      Everforest Light Yellow: エバーフォレスト・ライトイエロー\n      Everforest Dark Red: エバーフォレスト・ダークレッド\n      Everforest Dark Yellow: エバーフォレスト・ダークイエロー\n      Everforest Dark Green: エバーフォレスト・ダークグリーン\n      Everforest Dark Purple: エバーフォレスト・ダークパープル\n      Everforest Light Orange: エバーフォレスト・ライトオレンジ\n      Everforest Light Blue: エバーフォレスト・ライトブルー\n      Everforest Light Purple: エバーフォレスト・ライトパープル\n      Catppuccin Latte Mauve: キャプチーノ・ラテ モーヴ\n      Catppuccin Latte Red: キャプチーノ・ラテ レッド\n    Secondary Color Theme: 'テーマのアクセント カラー'\n        #* Main Color Theme\n    UI Scale: UIの拡大率\n    Expand Side Bar by Default: 幅広のサイド バーで起動\n    Disable Smooth Scrolling: スムーズ スクロールの無効化\n    Hide Side Bar Labels: サイドバー ラベルの非表示\n    Hide FreeTube Header Logo: FreeTube ヘッダー ロゴの非表示\n  Player Settings:\n    Player Settings: 'プレーヤー'\n    Play Next Video: 'おすすめの動画を自動再生'\n    Turn on Subtitles by Default: 'デフォルトで字幕を有効にする'\n    Autoplay Videos: '動画を自動的に再生する'\n    Proxy Videos Through Invidious: '動画を Invidious プロキシを経由して取得'\n    Autoplay Playlists: '再生リスト動画の自動再生'\n    Enable Theatre Mode by Default: 'デフォルトでシアターモードを有効にする'\n    Default Volume: 'デフォルトの音量'\n    Default Playback Rate: 'デフォルトの再生速度'\n    Default Video Format:\n      Default Video Format: '動画形式の設定'\n      Dash Formats: 'DASH 形式'\n      Legacy Formats: '旧形式'\n      Audio Formats: '音声形式'\n    Default Quality:\n      Default Quality: '動画品質の設定'\n      Auto: '自動'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4K'\n      8k: '8K'\n    Next Video Interval: 次の動画までの間隔\n    Fast-Forward / Rewind Interval: 早送り/巻き戻し間隔\n    Display Play Button In Video Player: 動画プレーヤーに再生ボタンを表示する\n    Scroll Volume Over Video Player: 動画プレーヤーをスクロールして音量を変更\n    Scroll Playback Rate Over Video Player: 動画プレーヤーをスクロールして再生速度を変更\n    Max Video Playback Rate: 最大動画再生速度\n    Video Playback Rate Interval: 動画再生速度間隔\n    Screenshot:\n      File Name Label: ファイル名のパターン\n      File Name Tooltip: 以下の変数が使用可能です。%Y 年（4桁）%M 月（2桁）%D 日（2桁）%H 時間（2桁）%N 分（2桁）%S 秒（2桁）%T ミリ秒（3桁）%s 動画の秒数 %t 動画のミリ秒（3桁）%i 動画ID が使用できます。\n      Error:\n        Forbidden Characters: 使用禁止文字\n        Empty File Name: 空のファイル名\n      Folder Label: スクリーンショットの保存先\n      Quality Label: スクリーンショットの品質\n      Enable: スクリーンショットの有効化\n      Format Label: スクリーンショットの形式\n      Ask Path: 保存フォルダを尋ねる\n      Folder Button: フォルダの選択\n    Enter Fullscreen on Display Rotate: 画面の回転時に全画面表示にする\n    Skip by Scrolling Over Video Player: 動画プレーヤーをスクロールして動画をスキップ\n    Autoplay Interruption Timer: 自動再生の停止タイマー\n    Default Viewing Mode:\n      Theater: シアター\n      Default Viewing Mode: デフォルト表示モード\n      Picture in Picture: 子画面表示\n      Full Screen: フルスクリーン\n      External Player: 外部プレーヤー ({externalPlayerName})\n  Subscription Settings:\n    Subscription Settings: '登録チャンネル'\n    Fetch Feeds from RSS: RSS から情報取得\n    Fetch Automatically: フィードの自動取得\n    Confirm Before Unsubscribing: 登録解除する前に確認画面を表示する\n    'Limit the number of videos displayed for each channel': 各チャンネルに表示する動画の数を制限する\n    To: 上限\n  Privacy Settings:\n    Save Watched Progress: 再生位置を記憶する\n    Remember History: 視聴履歴を記憶する\n    Watch history has been cleared: 視聴履歴を削除しました\n    Are you sure you want to remove your entire watch history?: 視聴履歴をすべて削除しますか？\n    Remove Watch History: 視聴履歴の削除\n    Search cache has been cleared: 検索キャッシュを削除しました\n    Are you sure you want to clear out your search cache?: 検索キャッシュを削除しますか？\n    Clear Search Cache: 検索キャッシュの削除\n    Privacy Settings: プライバシー\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: すべての登録チャンネルとプロファイルを削除しますか？これは元に戻せません。\n    Remove All Subscriptions / Profiles: 登録とプロファイルをすべて削除\n    Save Watched Videos With Last Viewed Playlist: 視聴済み動画を最後に見た再生リストと共に保存する\n    Remove All Playlists: 再生リストをすべて削除\n    All playlists have been removed: すべての再生リストが削除されました\n    Are you sure you want to remove all your playlists?: すべての再生リストを削除してもよろしいですか？\n    Remember Search History: 検索履歴を記憶する\n    Are you sure you want to clear out your search history and cache?: 本当に検索履歴とキャッシュを削除しますか？\n    Clear Search History and Cache: 検索履歴とキャッシュを削除する\n    Search history and cache have been cleared: 検索履歴とキャッシュが削除されました\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: 自動\n        Semi-auto: 半自動\n        Never: 保存しない\n      Tooltip: '自動 = 動画ページを退出する際、動画が終了した際、またはエラーが発生した際（例: レート制限や視聴セッションの期限切れ）に進捗を保存します。半自動 = 自動と似ていますが、動画ページを退出する際には保存されません。代わりに、動画プレーヤーの下にある「視聴進捗を保存」というボタンを使って手動で進捗を保存できます。'\n  Data Settings:\n    How do I import my subscriptions?: 登録チャンネルをインポートするには？\n    Unknown data key: 不明なデータキー\n    Unable to write file: ファイルに書き込めません\n    Unable to read file: ファイルを読み込めません\n    All watched history has been successfully exported: すべての視聴履歴を正常にエクスポートしました\n    All watched history has been successfully imported: すべての視聴履歴を正常にインポートしました\n    Profile object has insufficient data, skipping item: プロファイルのデータが不完全なため、この項目の処理を省略します\n    History object has insufficient data, skipping item: 履歴情報に問題があるので、破損したデータは除外して実行します\n    Subscriptions have been successfully exported: 登録チャンネルを正常にエクスポートしました\n    Invalid history file: 無効な履歴ファイル\n    Invalid subscriptions file: 無効な登録チャンネルのファイル\n    All subscriptions have been successfully imported: すべての登録チャンネルを正常にインポートしました\n    All subscriptions and profiles have been successfully imported: すべての登録チャンネルとプロファイルを正常にインポートしました\n    Export History: 履歴のエクスポート\n    Import History: 履歴のインポート\n    Export NewPipe: NewPipe エクスポート\n    Export YouTube: YouTube エクスポート\n    Export FreeTube: FreeTube エクスポート\n    Export Subscriptions: 登録チャンネルのエクスポート\n    Import Subscriptions: 登録チャンネルのインポート\n    Select Export Type: エクスポート形式の選択\n    Data Settings: データ\n    Manage Subscriptions: 登録チャンネルの管理\n    Playlist insufficient data: 再生リスト「{playlist}」のデータが不十分なため、項目をスキップします\n    All playlists has been successfully imported: すべての再生リストが正常にインポートされました\n    All playlists has been successfully exported: すべての再生リストが正常にエクスポートされました\n    Import Playlists: 再生リストのインポート\n    Export Playlists: 再生リストのエクスポート\n    Subscription File: 登録チャンネル ファイル\n    History File: 履歴ファイル\n    Playlist File: 再生リスト\n    Export Playlists For Older FreeTube Versions:\n      Label: 古いバージョンの FreeTube 用に再生リストをエクスポートする\n      Tooltip: \"このオプションは、すべての再生リストから動画をエクスポートし、1つの再生リスト「Favorites」にまとめます。\\n古いバージョンのFreeTube用に再生リストの動画をエクスポートおよびインポートする方法は以下の通りです：\\n 1. このオプションを有効にして再生リストをエクスポートします。\\n2. プライバシー設定の「再生リストをすべて削除」オプションを使用して、既存のすべての再生リストを削除します。\\n 3. 古いバージョンのFreeTubeを起動し、エクスポートした再生リストをインポートします。\"\n    Search history file: 検索履歴ファイル\n    Search history: 検索履歴\n    Import search history: 検索履歴のインポート\n    Export search history: 検索履歴のエクスポート\n    All search history has been successfully imported: すべての検索履歴が正常にインポートされました\n    All search history has been successfully exported: すべての検索履歴が正常にエクスポートされました\n  Distraction Free Settings:\n    Hide Live Chat: ライブチャットの非表示\n    Hide Popular Videos: 人気動画の非表示\n    Hide Trending Videos: 急上昇動画の非表示\n    Hide Recommended Videos: おすすめ動画の非表示\n    Hide Comment Likes: コメント欄の評価の非表示\n    Hide Channel Subscribers: チャンネル登録者数の非表示\n    Hide Video Views: 再生数の非表示\n    Hide Video Likes And Dislikes: 評価の非表示\n    Distraction Free Settings: 集中モード\n    Hide Active Subscriptions: 登録チャンネルの非表示\n    Hide Playlists: 再生リストの非表示\n    Hide Video Description: 動画概要欄の非表示\n    Hide Comments: コメントの非表示\n    Hide Live Streams: ライブ配信の非表示\n    Hide Sharing Actions: 共有ボタンの非表示\n    Hide Videos on Watch: '視聴済みの動画を非表示にする'\n    Hide Chapters: チャプターの非表示\n    Hide Upcoming Premieres: 今後のプレミア公開を非表示\n    Hide Channels: チャンネルから動画を非表示にする\n    Hide Channels Placeholder: チャンネル ID\n    Display Titles Without Excessive Capitalisation: 過剰な大文字や句読点のないタイトルの表示\n    Hide Channel Playlists: チャンネルの「再生リスト」タブを非表示\n    Sections:\n      Side Bar: サイドバー\n      Channel Page: チャンネル ページ\n      Watch Page: 視聴ページ\n      General: 一般\n      Subscriptions Page: 登録チャンネル ページ\n    Hide Featured Channels: おすすめチャンネルの非表示\n    Hide Channel Shorts: チャンネルの「ショート動画」タブを非表示\n    Hide Channel Podcasts: チャンネルの「ポッドキャスト」タブを非表示\n    Hide Subscriptions Shorts: 登録チャンネルのショート動画の非表示\n    Hide Subscriptions Live: 登録チャンネルのライブ配信の非表示\n    Hide Subscriptions Videos: 登録チャンネルの動画の非表示\n    Hide Channel Releases: チャンネルの「新着情報」タブを非表示\n    Hide Profile Pictures in Comments: コメント欄のプロフィール写真を非表示\n    Hide Channels Invalid: 提供されたチャンネル ID が無効です\n    Hide Channels Disabled Message: 一部のチャンネルが ID を使用してブロックされ、処理されませんでした。これらの ID が更新されている間、機能はブロックされます\n    Hide Channels Already Exists: チャンネル ID は既に存在します\n    Hide Channels API Error: 指定されたIDのユーザーを検索する際にエラーが発生しました。IDが正しいかもう一度確認してください。\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 単語、単語の一部、またはフレーズ\n    Hide Videos, Playlists and Channels Containing Text: 特定のテキストを含む動画と再生リストを非表示にする\n    Hide Channel Home: チャンネルの「ホーム」タブを非表示\n    Show Added Items: 追加された項目を表示\n    Hide Channel Courses: チャンネルの「コース」タブを非表示\n    Hide Channel Posts: チャンネルの「投稿」タブを非表示\n    Hide Subscriptions Posts: 登録チャンネルの投稿を非表示\n  The app needs to restart for changes to take effect. Restart and apply change?: 変更の反映には、アプリの再起動が必要です。再起動して変更を適用しますか？\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: ネットワーク情報の取得中にエラーが発生しました。プロキシーを正しく設定してますか?\n    City: 都市名\n    Region: 地域\n    Country: 国名\n    Ip: IP\n    Your Info: あなたの情報\n    Test Proxy: プロキシのテスト\n    Clicking on Test Proxy will send a request to: プロキシのテストをクリックして、送信するリクエスト先は\n    Proxy Port Number: プロキシのポート番号\n    Proxy Host: プロキシのホスト\n    Proxy Protocol: プロキシのプロトコル\n    Enable Tor / Proxy: Tor / プロキシの有効化\n    Proxy Settings: プロキシ\n    Proxy Warning: FreeTube にはプロキシは内蔵されていませんが、Tor のようなご使用のマシン上で動作するものや、一部の VPN が提供する SOCKS5 プロキシのような外部プロキシに接続することができます。有効にした場合は、プロキシ/Tor が適切に設定されていることを確認してください。そうでないと、FreeTube はデータを取得できなくなります。\n    Proxy Username: プロキシのユーザー名\n    Proxy Password: プロキシのパスワード\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: スポンサーセグメントがスキップされたときに通知する\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': スポンサーブロック APIのURL（デフォルト https://sponsor.ajay.app）\n    Enable SponsorBlock: スポンサーブロックの有効化\n    SponsorBlock Settings: スポンサーブロック\n    Skip Options:\n      Skip Option: スキップの設定\n      Auto Skip: 自動スキップ\n      Show In Seek Bar: 進行バーに表示\n      Prompt To Skip: プロンプトをスキップ\n      Do Nothing: 何もしない\n    Category Color: カテゴリの色\n    UseDeArrowTitles: DeArrow の動画タイトルを使用する\n    UseDeArrowThumbnails: DeArrow のサムネイルを使用する\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Thumbnail Generator API Url (デフォルト https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: カスタム外部プレーヤー引数\n    Custom External Player Executable: カスタム外部プレーヤーの実行可能ファイル\n    Ignore Unsupported Action Warnings: 未対応のアクションの警告を無視\n    External Player: 外部プレーヤー\n    External Player Settings: 外部プレーヤー\n    Players:\n      None:\n        Name: なし\n    Ignore Default Arguments: デフォルト引数を無視する\n  Parental Control Settings:\n    Hide Search Bar: 検索バーの非表示\n    Parental Control Settings: 制限付きモード\n    Show Family Friendly Only: ファミリー向けのみ表示\n    Hide Unsubscribe Button: 登録解除ボタンの非表示\n    Hide Uploader on Watch page: 視聴ページで投稿者情報を非表示\n  Experimental Settings:\n    Replace HTTP Cache: HTTP キャッシュの置換\n    Experimental Settings: 試験的\n    Warning: これらの設定は実験的なものであり、有効にするとアプリのクラッシュを引き起こす恐れがあります。バックアップをとっておくことを強くお勧めします。自己責任で使用してください！\n  Password Settings:\n    Password Settings: パスワード\n    Set Password To Prevent Access: 設定にアクセスするためのパスワードの設定\n    Set Password: パスワードを設定\n    Remove Password: パスワードを削除\n  Password Dialog:\n    Enter Password To Unlock: パスワードを入力して設定を解除\n    Password: パスワード\n  Sort Settings Sections (A-Z): 設定項目の並べ替え（A-Z）\n  Return to Settings Menu: 設定に戻る\nAbout:\n  #On About page\n  About: '概要'\n  #& About\n#On Channel Page\n  Donate: 寄付\n  these people and projects: これらの人々とプロジェクト\n  Credits: クレジット\n  Translate: 翻訳\n  room rules: ルームの規則\n  Chat on Matrix: Matrix でチャット\n  Mastodon: マストドン\n  Email: メールアドレス\n  Blog: ブログ\n  Website: ウェブサイト\n  Please check for duplicates before posting: 投稿する前に重複を確認してください\n  GitHub issues: GitHub の課題\n  Report a problem: 問題の報告\n  FAQ: よくある質問\n  FreeTube Wiki: FreeTube の Wiki\n  Help: ヘルプ\n  GitHub releases: GitHub リリース\n  Downloads / Changelog: ダウンロード / 変更ログ\n  Source code: ソースコード\n  Beta: ベータ\n  Discussions: 議論\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: '{licenseLink} に基づいてライセンス供与されています'\n  Please read the {roomRulesLink}: '{roomRulesLink} をお読みください'\n  FreeTube is made possible by {creditsPageLink}: FreeTube は {creditsPageLink} によって支えられています\nChannel:\n  Subscribe: 'チャンネル登録'\n  Unsubscribe: '登録解除'\n  Search Channel: 'チャンネル内検索'\n  Your search results have returned 0 results: '検索結果が0件です'\n  Videos:\n    Videos: '動画'\n    This channel does not currently have any videos: 'このチャンネルには動画がありません'\n    Sort Types:\n      Newest: '新しい'\n      Oldest: '古い'\n      Most Popular: '人気'\n  Playlists:\n    Playlists: '再生リスト'\n    This channel does not currently have any playlists: 'このチャンネルには再生リストがありません'\n    Sort Types:\n      Last Video Added: '最近追加された動画'\n      Newest: '新しい'\n      Oldest: '古い'\n  About:\n    About: '概要'\n    Channel Description: 'チャンネルの説明'\n    Featured Channels: '注目のチャンネル'\n    Tags:\n      Tags: タグ\n      Search for: 「{tag}」を検索\n    Details: 詳細\n    Joined: 参加日\n    Location: 場所\n  Added channel to your subscriptions: チャンネルを登録しました\n  Channel has been removed from your subscriptions: チャンネルがあなたの登録チャンネルから削除されました\n  Removed subscription from {count} other channel(s): ほかの {count} チャンネルから登録を削除しました\n  Posts:\n    This channel currently does not have any posts: このチャンネルには現在投稿がありません\n    votes: '{votes} 投票'\n    Reveal Answers: 回答を表示\n    Hide Answers: 回答を非表示\n    Video hidden by FreeTube: FreeTube によって非表示にされた動画\n    View Full Post: 全文表示\n    Viewing Posts Only Supported By Invidious: 投稿の閲覧は Invidious でのみサポートされています。Invidious がなくても、チャンネルのコミュニティタブでコンテンツを見ることができます。\n  This channel does not exist: このチャンネルは存在しません\n  This channel does not allow searching: このチャンネルでは検索できません\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: このチャンネルは年齢制限があり、現在 FreeTube では視聴できません。\n  Channel Tabs: チャンネル タブ\n  Live:\n    This channel does not currently have any live streams: このチャンネルは現在、ライブ配信を行っていません\n    Live: ライブ配信\n  Shorts:\n    This channel does not currently have any shorts: このチャンネルには現在ショート動画がありません\n  Releases:\n    Releases: 新着情報\n    This channel does not currently have any releases: 現在、このチャンネルには公開されたものはありません\n  Podcasts:\n    This channel does not currently have any podcasts: このチャンネルにはポッドキャストがありません\n    Podcasts: ポッドキャスト\n  Home:\n    View Playlist: 再生リストを表示\n    Home: ホーム\n  Courses:\n    Courses: コース\n    This channel does not currently have any courses: このチャンネルには現在コースはありません\nVideo:\n  Open in YouTube: 'YouTube で表示'\n  Copy YouTube Link: 'YouTube リンクのコピー'\n  Open YouTube Embedded Player: 'YouTube 埋め込みプレーヤーで表示'\n  Copy YouTube Embedded Player Link: 'YouTube 埋め込みプレーヤーへのリンクのコピー'\n  Open in Invidious: 'Invidious で表示'\n  Copy Invidious Link: 'Invidious リンクのコピー'\n  Views: '総再生回数'\n  Watched: '視聴済み'\n  # As in a Live Video\n  Live: 'ライブ配信'\n  Live Now: 'ライブ配信中'\n  Live Chat: 'ライブチャット'\n  Enable Live Chat: 'ライブチャットの有効化'\n  Live Chat is currently not supported in this build.: '現在、このビルドはライブチャットに未対応です。'\n  Live chat is enabled. Chat messages will appear here once sent.: 'ライブチャットは有効です。チャットが送信されるとここに表示されます。'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': '現在、ライブチャットは Invidious API では未対応です。直接 YouTube への接続が必要です。'\n  Published:\n    In less than a minute: 1 分以内\n  Published on: '公開日'\n#& Videos\n  Video has been removed from your history: 動画を履歴から削除しました\n  Remove From History: 履歴から削除\n  Video has been marked as watched: 視聴済みに変更しました\n  Mark As Watched: 視聴済みに変更\n  Autoplay: 自動再生\n  Previous: 前へ\n  Next: 次へ\n  Reverse Playlist: 再生リストを逆順にする\n  Shuffle Playlist: 再生リストをシャッフル\n  Loop Playlist: 再生リストのループ\n  Starting soon, please refresh the page to check again: すぐに再生されます、ページを再読み込みしてお待ちください\n  Copy Invidious Channel Link: Invidious チャンネルへのリンクのコピー\n  Open Channel in Invidious: Invidious でチャンネル表示\n  Copy YouTube Channel Link: YouTube チャンネルへのリンクのコピー\n  Open Channel in YouTube: YouTube でチャンネル表示\n  Started streaming on: ライブ開始日\n  Streamed on: ライブ配信\n  Video has been removed from your saved list: 動画を保存一覧から削除しました\n  Video has been saved: 動画を保存しました\n  Save Video: 動画の保存\n  Sponsor Block category:\n    sponsor: スポンサー\n    music offtopic: 音楽以外\n    interaction: インタラクション\n    self-promotion: 自己紹介\n    outro: アウトロ（末尾）\n    intro: イントロ（冒頭）\n    recap: 要約\n    filler: フィラー（穴埋め）\n  External Player:\n    OpeningTemplate: '{externalPlayer} で {videoOrPlaylist} を開く...'\n    Unsupported Actions:\n      looping playlists: 再生リストのループ\n      shuffling playlists: シャッフル再生リスト\n      reversing playlists: 再生リストを反転させる\n      opening specific video in a playlist (falling back to opening the video): 再生リストで特定の動画を開く (動画を開く前にフォールバック)\n      opening playlists: 再生リストを開く\n      setting a playback rate: 再生レートの設定\n      starting video at offset: オフセットで動画の再生\n    UnsupportedActionTemplate: '{externalPlayer} はサポートしていません： {action}'\n    playlist: 再生リスト\n    video: 動画\n    OpenInTemplate: '{externalPlayer} で開く'\n  Premieres: プレミア公開\n  Show Super Chat Comment: Super Chat のコメント表示\n  Scroll to Bottom: 下までスクロール\n  Upcoming: 近日公開\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': この配信ではライブチャットは使用できません。配信者によって無効に設定されているようです。\n  Hide Channel: チャンネルを非表示\n  Unhide Channel: チャンネルを表示\n  More Options: その他の設定\n  Player:\n    Stats:\n      Dropped Frames / Total Frames: 'コマ落ち： {droppedFrames} / 総コマ数： {totalFrames}'\n      CodecAudio: 'コーデック： {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'コーデック： {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'コーデック： {videoCodec} / {audioCodec}'\n      Video ID: '動画 ID： {videoId}'\n      Media Formats: 'メディア形式： {formats}'\n      Resolution: '解像度： {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'プレーヤーの寸法： {width}x{height}'\n      Bitrate: 'ビットレート： {bitrate} kbps'\n      Volume: '音量： {volumePercentage}%'\n      Bandwidth: '帯域幅： {bandwidth} kbps'\n      Buffered: 'バッファ済み： {bufferedPercentage}%'\n      Stats: 統計\n    You appear to be offline: オフラインのようです。\n    Playback will resume automatically when your connection comes back: ネットワーク接続が回復すると再生が自動的に再開されます。\n    Skipped segment: '{segmentCategory} 区分をスキップしました'\n    TranslatedCaptionTemplate: '{language}（「{originalLanguage}」から翻訳）'\n    Audio Tracks: オーディオ トラック\n    Theatre Mode: シアターモード\n    Exit Theatre Mode: シアターモードを終了\n    Exit Full Window: フルウィンドウを終了\n    Full Window: フルウィンドウ\n    Hide Stats: 統計を非表示\n    Take Screenshot: スクリーンショットを撮る\n    Show Stats: 統計を表示\n    Autoplay is off: 自動再生 オフ\n    Autoplay is on: 自動再生 オン\n  IP block: YouTube はあなたのIPアドレスからの動画視聴をブロックしました。別の VPN またはプロキシに切り替えてみてください。\n  Unlisted: 限定公開\n  MembersOnly: メンバー限定動画は Google にログインし、投稿チャンネルに課金する必要があるので FreeTube から直接見ることはできません。\n  AgeRestricted: 年齢制限がかかっている 動画 は Google にログインしておりかつ年齢確認を済ましている YouTube アカウントが必要なため、FreeTube から直接見ることはできません。\n  DeArrow:\n    Show Original Details: 元の情報を表示\n    Show Modified Details: 変更された詳細を表示\n  DRMProtected: DRM保護された動画はFreeTubeでは再生できません。これらの動画には、独自の非オープンソースのコンポーネントが必要です。この動画を視聴したい場合は、DRM対応のウェブブラウザで公式のYouTubeウェブサイトでご覧ください。\n#& Playlists\n  Save Watched Progress: 視聴進捗を保存\n  Watched Progress Saved: 視聴進捗を保存しました\n  Popout Live Chat: チャットをポップアウト\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': '残りのプレロール広告時間: {remindingTimeSeconds}秒'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': '残りのSABRバックオフ時間: {remindingTimeSeconds}秒'\nPlaylist:\n  #& About\n  View Full Playlist: '完全な再生リストの表示'\n  Last Updated On: '最終更新日'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: 再生リスト\n  Sort By:\n    Custom: カスタム\n    VideoTitleDescending: タイトル（Z-A）\n    DateAddedOldest: 追加日（古い順）\n    DateAddedNewest: 追加日（新しい順）\n    AuthorAscending: 著者名（A-Z）\n    AuthorDescending: 著者名（Z-A）\n    VideoTitleAscending: タイトル（A-Z）\n    VideoDurationAscending: 再生時間（短い順）\n    VideoDurationDescending: 再生時間（長い順）\n    PublishedNewest: 公開日（新しい順）\n    PublishedOldest: 公開日（古い順）\nChange Format:\n  Change Media Formats: '動画形式の変更'\n  Use Dash Formats: 'DASH 形式の使用'\n  Use Legacy Formats: '旧形式の使用'\n  Use Audio Formats: '音声形式の使用'\n  Audio formats are not available for this video: この動画には音声形式はありません\n  Dash formats are not available for this video: この動画には DASH 形式はありません\n  Legacy formats are not available for this video: この動画には旧形式を使用できません\nShare:\n  Share Video: '動画の共有'\n  Share Playlist: '再生リストの共有'\n  Copy Link: 'リンクのコピー'\n  Open Link: 'リンクの表示'\n  Copy Embed: '埋め込みのコピー'\n  Open Embed: '埋め込みの表示'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL をコピーしました'\n  Invidious Embed URL copied to clipboard: 'Invidious の埋め込み URL をコピーしました'\n  YouTube URL copied to clipboard: 'YouTube URL をコピーしました'\n  YouTube Embed URL copied to clipboard: 'YouTube の埋め込み URL をコピーしました'\n  Include Timestamp: 視聴中の位置から再生\n  YouTube Channel URL copied to clipboard: クリップボードにコピーした YouTube チャンネルの URL\n  Invidious Channel URL copied to clipboard: クリップボードにコピーした Invidious チャンネルの URL\n  Share Channel: チャンネルを共有\n  Share Post: ポストの共有\nMini Player: 'ミニプレーヤー'\nComments:\n  Comments: 'コメント'\n  Click to View Comments: 'コメント表示'\n  Getting comment replies, please wait: 'コメント返信を取得中。お待ちください'\n  Hide Comments: 'コメント非表示'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'この動画にはコメントがありません'\n  Load More Comments: 'もっと見る'\n  There are no more comments for this video: この動画へのコメントはまだありません\n  Top comments: 評価順\n  Newest first: 新しい順\n  Show More Replies: 返信をもっと見る\n  Pinned by: 固定\n  Member: メンバー\n  Hearted: ハート\n  View {replyCount} replies: '1 件の返信を見る | {replyCount} 件の返信を見る'\n  Subscribed: チャンネル登録済み\n  There are no comments available for this post: この記事にコメントはありません\n  Hide {replyCount} replies: 1 件の返信を非表示にする | {replyCount} 件の返信を非表示にする\n  View 1 reply from {channelName}: '{channelName} からの 1 件の返信を見る'\n  View {replyCount} replies from {channelName} and others: '{channelName} や他のユーザーからの {replyCount} 件の返信を見る'\nUp Next: '次の動画'\n\n# Toast Messages\nLocal API Error (Click to copy): '内部 API エラー（クリックしてコピー）'\nInvidious API Error (Click to copy): 'Invidious API エラー（クリックしてコピー）'\nFalling back to Invidious API: '代替の Invidious API に切替'\nFalling back to Local API: '代替の内部 API に切替'\nLoop is now disabled: 'ループ再生を無効にしました'\nLoop is now enabled: 'ループ再生を有効にしました'\nShuffle is now disabled: 'シャッフル再生を無効にしました'\nShuffle is now enabled: 'シャッフル再生を有効にしました'\nPlaying Next Video: '次の動画を再生'\nPlaying Previous Video: '前の動画を再生'\nCanceled next video autoplay: '次の動画の自動再生をキャンセルしました'\n'The playlist has ended. Enable loop to continue playing': '再生リストが終了しました。再生を続けるにはループを有効にしてください'\n\nYes: 'はい'\nNo: 'いいえ'\nLocale Name: '日本語'\nProfile:\n  '{profile} is now the active profile': '{profile} プロファイルに変更しました'\n  Your default profile has been changed to your primary profile: 起動時のプロファイルを、上位のプロファイルに変更しました\n  Removed {profile} from your profiles: プロファイルから {profile} を削除しました\n  Your default profile has been set to {profile}: 標準プロファイルが{profile}に設定されました\n  Profile has been updated: プロファイルを更新しました\n  Profile has been created: プロファイルを作成しました\n  Your profile name cannot be empty: プロファイル名は空にできません\n  All subscriptions will also be deleted.: すべての登録チャンネルも削除されます。\n  Are you sure you want to delete this profile?: このプロファイルを削除しますか？\n  Delete Profile: プロファイルの削除\n  Make Default Profile: 標準のプロファイルに設定\n  Create Profile: プロファイルの作成\n  Update Profile: プロファイルの更新\n  Profile Preview: プロファイルのプレビュー\n  Custom Color: 色の指定\n  Color Picker: 色の選択\n  Edit Profile: プロファイルの編集\n  Create New Profile: プロファイルの新規作成\n  Profile Manager: プロファイル管理\n  All Channels: すべてのチャンネル\n  Profile Select: プロファイルの選択\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 選択したチャンネルを削除しますか？ほかのプロファイルからは削除されません。\n  No channel(s) have been selected: チャンネルが選択されていません\n  Delete Selected: 選択項目の削除\n  Select None: 選択なし\n  Select All: すべて選択\n  Other Channels: ほかのチャンネル\n  Subscription List: 登録チャンネル一覧\n  '{number} selected': '{number} 件選択済み'\n  Add Selected To Profile: 選択項目をプロファイルに追加\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : これはあなたのメインのプロファイルです。選択したチャンネルを本当に削除しますか？同じチャンネルがほかのプロファイルにも登録されていれば削除されます。\n  Profile Filter: プロファイルのフィルター\n  Profile Settings: プロファイル\n  Toggle Profile List: プロファイル一覧の切替\n  Create Profile Name: プロファイル名を作成\n  Profile Name: プロファイル名\n  Edit Profile Name: プロファイル名を編集\n  Close Profile Dropdown: プロフィールドロップダウンを閉じる\n  Open Profile Dropdown: プロフィールドロップダウンを開く\nThe playlist has been reversed: 再生リストを逆順にしました\nA new blog is now available, {blogTitle}. Click to view more: '新着ブログ公開、{blogTitle}。クリックしてブログを読む'\nDownload From Site: サイトからダウンロード\nVersion {versionNumber} is now available!  Click for more details: 最新バージョン {versionNumber} が利用可能！　詳細はこちらをクリック\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: この動画は、動画形式の情報が利用できないため再生できません。再生が許可されていない国で発生します。\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: 有効にすると、FreeTube は通常の方法の代わりに RSS を使用して購読フィードを取得します。RSS は高速で IP ブロックを防ぎますが、動画の長さやライブ配信などの情報は提供されません\n    Fetch Automatically: 有効にすると、FreeTube は起動時や新しいウィンドウを開いたときに自動的に登録チャンネルフィードを取得します。\n  Player Settings:\n    Default Video Format: 動画を再生する際に使用する形式を設定します。DASH形式はより高い画質で再生できます。旧形式は最大360pに制限されますが、帯域幅の使用量が少なくなります。音声形式は音声のみです。\n    Proxy Videos Through Invidious: YouTube に直接接続するのではなく、Invidious を通じて動画を提供します。\n    Scroll Playback Rate Over Video Player: カーソルが動画上にあるとき、Ctrl キー（Mac では Command キー）を押したまま、マウスホイールを前後にスクロールして再生速度を調整します。Control キー（Mac では Command キー）を押したままマウスを左クリックすると、すぐにデフォルトの再生速度（設定を変更していない場合は 1 x）に戻ります。\n    Skip by Scrolling Over Video Player: MPVスタイルでスクロールホイールを使って動画をスキップします。\n  General Settings:\n    Invidious Instance: FreeTube が API 呼び出しのために接続する Invidious のインスタンスです。\n    Preferred API Backend: FreeTube がデータを取得するために使用する方法を選択してください。内部 API はアプリ内蔵の取得機能です。 Invidious API は、 Invidious サーバーへの接続が必要です。\n    Thumbnail Preference: FreeTube 全体のすべてのサムネイルが、デフォルトのサムネイルの代わりに動画のフレームに置き換えられ、ぼかされるか非表示になります。\n    Fallback to Non-Preferred Backend on Failure: 有効にすると、選択した API で取得できなければ、FreeTube は自動的に他の API での取得を試みます。\n    Region for Trending: 急上昇の地域設定では、急上昇動画を表示する国を選択できます。\n    External Link Handling: \"FreeTube で開けないリンクをクリックしたときのデフォルトの動作を選択します。\\nデフォルトでは、FreeTube はクリックしたリンクをデフォルトのブラウザで開きます。\\n\"\n    Open Deep Links In New Window: FreeTube に渡された URL は、ブラウザの拡張機能やコマンドライン引数などによって、新しいウィンドウで開かれます。\n  External Player Settings:\n    Custom External Player Arguments: '外部プレーヤーに渡したいカスタムコマンドライン引数。'\n    Ignore Warnings: 現在の外部プレーヤーが、現在のアクションに未対応の場合（再生リストを逆順にするなど）に警告を抑制します。\n    Custom External Player Executable: デフォルトでは、FreeTube は選択した外部プレーヤーが PATH 環境変数を介して見つかると想定します。必要に応じて、カスタム パスをここで設定できます。\n    External Player: 外部プレーヤーを選択すると、動画（対応している場合は再生リスト）を開くためのアイコンがサムネイルに表示されます。警告：Invidious の設定は、外部プレーヤーには影響しません。\n    DefaultCustomArgumentsTemplate: \"（デフォルト： '{defaultCustomArguments}'）\"\n    Ignore Default Arguments: 動画の URL 以外のデフォルトの引数（再生速度、再生リストの URL など）を外部プレーヤーに送信しないでください。カスタム引数はそのまま引き継がれます。\n  Experimental Settings:\n    Replace HTTP Cache: Electron のディスクに基づく HTTP キャッシュを無効化し、メモリ内で独自の画像キャッシュを使用します。このことにより RAM の使用率は増加します。\n  Distraction Free Settings:\n    Hide Channels: チャンネル ID を入力すると、すべての動画、再生リスト、チャンネル自体が検索や人気、およびおすすめに表示されなくなります。入力するチャンネル ID は、大文字と小文字を区別するので完全に一致させてください。\n    Hide Subscriptions Live: この設定は、アプリ全体の \"{appWideSetting}\" 設定により上書きされます。\"{settingsSection}\" 項目の \"{subsection}\" にあります\n    Hide Videos, Playlists and Channels Containing Text: FreeTube 全体での履歴やあなたの再生リストと再生リスト内の動画を除き、元のタイトルにその単語を含む動画や単語の一部または、フレーズ（大文字と小文字を区別しない）が含まれているすべての動画と再生リストを非表示にします。\n    Hide Videos on Watch: 視聴済みの動画を、購読ページやチャンネルページの 動画、ショート、ライブ タブから非表示にします。ただし、チャンネルページの ホーム タブには影響しません\n  SponsorBlock Settings:\n    UseDeArrowTitles: 動画のタイトルを DeArrow からユーザーが投稿したタイトルに置き換えます。\n    UseDeArrowThumbnails: 動画のサムネイルを DeArrow からのサムネイルに置き換えます。\nPlaying Next Video Interval: すぐに次の動画を再生します。クリックするとキャンセル。|次の動画を {nextVideoInterval} 秒で再生します。クリックするとキャンセル。|次の動画を {nextVideoInterval} 秒で再生します。クリックするとキャンセル。\nMore: もっと見る\nUnknown YouTube url type, cannot be opened in app: 不明な YouTube URL タイプのため、アプリで開くことができません\nOpen New Window: 新しいウィンドウを開く\nDefault Invidious instance has been cleared: デフォルトの Invidious インスタンスがクリアされました\nDefault Invidious instance has been set to {instance}: デフォルトの Invidious インスタンスは{instance}に設定されました\nExternal link opening has been disabled in the general settings: 一般設定で外部リンクの表示は無効になっています\nSearch Bar:\n  Clear Input: 入力の消去\n  Remove: 削除\nAre you sure you want to open this link?: このリンクを開きますか？\nChannels:\n  Channels: チャンネル\n  Title: チャンネル一覧\n  Search bar placeholder: チャンネル検索\n  Unsubscribe Prompt: 「{channelName}」のチャンネル登録を解除しますか？\n  Count: '{number} 件のチャンネルが見つかりました。'\n  Empty: 現在、チャンネル一覧は空です。\nScreenshot Success: スクリーンショットを保存しました\nScreenshot Error: スクリーンショットに失敗しました。{error}\nNew Window: 新しいウィンドウ\nClipboard:\n  Copy failed: クリップボードにコピーできませんでした\n  Cannot access clipboard without a secure connection: 安全な接続でなければクリップボードにはアクセスできません\nChapters:\n  Chapters: チャプター\n  Key Moments: ハイライト\nPreferences: 環境設定\nOk: オーケー\nHashtag:\n  Hashtag: ハッシュタグ\n  This hashtag does not currently have any videos: このハッシュタグには現在動画がありません\nClose Banner: バナーを閉じる\nGo to page: '{page} を表示'\nSearch character limit: 検索クエリが {searchCharacterLimit} 文字の制限を超えています\nFeed:\n  Feed Last Updated: '{feedName} フィードの最終更新日時： {date}'\n  Refresh Feed: '{subscriptionName} の更新'\nChannel Hidden: '{channel} をチャンネルフィルターに追加しました'\nChannel Unhidden: '{channel} をチャンネルフィルターから削除しました'\nTag already exists: '\"{tagName}\" のタグはすでに存在します'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: 字幕\n    Closed Captions: クローズドキャプション\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: 最新\n    3D: 3D\nYes, Delete: はい、削除します\nYes, Restart: はい、再起動します\nYes, Open Link: はい、リンクを開きます\nCancel: キャンセル\ncheckmark: ✓\nMoments Ago: たった今\nAge Restricted:\n  This video is age restricted: この動画には年齢制限があります\n  This channel is age restricted: このチャンネルには年齢制限があります\nTrimmed input must be at least N characters long: トリミングされた入力は少なくとも1文字以上でなければなりません | トリミングされた入力は少なくとも {length} 文字以上でなければなりません\nDisplay Label: '{label}：{value}'\nKeyboardShortcutTemplate: '{label} （{shortcut}）'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: ↓\n  arrowleft: ←\n  arrowright: →\n  arrowup: ↑\n  shift: Shift\n  plus: +\n  enter: Enter\nRight-click or hold to see history: 右クリックまたは長押しで 履歴 を表示\nAutoplay Interruption Timer: '{autoplayInterruptionIntervalHours} 時間の無操作状態が続いたため、自動再生をキャンセルしました'\nDescription:\n  Expand Description: '...もっと見る'\n  Collapse Description: 表示を減らす\nKeyboardShortcutPrompt:\n  Navigate to Settings: 設定ページに移動する\n  History Forward: １ページ進む\n  New Window: 新しいウィンドウを開く\n  Navigate to History: 履歴ページに移動する\n  Refresh: フィードを最新の状態に更新\n  Focus Secondary Search: 補助検索バーに移動（存在する場合）\n  Captions: 字幕 オン/オフ の切り替え\n  Stats: 動画の統計情報を表示\n  History Backward: １ページ戻る\n  Fullscreen: フルスクリーンの切り替え\n  Full Window: フルウィンドウの切り替え\n  Theatre Mode: シアターモードの切り替え\n  Take Screenshot: スクリーンショットを撮る\n  Minimize Window: ウィンドウの最小化\n  Play: 再生 / 一時停止 の切り替え\n  Large Fast Forward: 10秒進む / 現在の動画再生速度に基づいて動画を早送り\n  Mute: ミュートの切り替え\n  Decrease Video Speed: 再生速度間隔に基づいて動画の速度を下げる\n  Increase Video Speed: 再生速度間隔に基づいて動画の速度を上げる\n  Reset Zoom: ズームレベル / UI拡大率をリセット\n  Zoom In: 拡大\n  Zoom Out: 縮小\n  Toggle Developer Tools: 開発者ツールの切り替え\n  Focus Search: 検索バーにフォーカスする\n  Keyboard Shortcuts: キーボード ショートカット\n  Sections:\n    Video:\n      Playback: '動画: 再生'\n      General: '動画: 一般'\n    App:\n      Situational: 'アプリ: 状況対応'\n      General: 'アプリ: 一般'\n  Show Keyboard Shortcuts: キーボード ショートカットを表示する\n  Picture in Picture: 子画面モードの切り替え\n  Large Rewind: 10秒巻き戻し / 現在の動画再生速度に基づいて動画を巻き戻す\n  Close Window: ウィンドウを閉じる\n  Search in New Window: 新しいウィンドウで検索\n  Volume Down: 音量を下げる\n  Last Frame: 前のフレーム (一時停止中)\n  Next Frame: 次のフレーム (一時停止中)\n  Volume Up: 音量を上げる\n  Small Rewind: 巻き戻し間隔と現在の再生速度に基づいてX秒巻き戻す\n  Small Fast Forward: 早送り間隔と現在の再生速度に基づいてX秒早送り\n  Last Chapter: 前のチャプター\n  Next Chapter: 次のチャプター\n  Skip by Tenths: 動画をパーセンテージでスキップ (3回スキップで全体の30%に移動)\n  Home: 動画の冒頭を見る\n  End: 動画の最後を見る\n  Skip to Previous Video: 再生リスト内で前の動画にスキップする\n  Skip to Next Video: 再生リスト内の次の動画または次のおすすめ動画にスキップする\nshortcutLabelSeparator: ｜\nCompact side navigation: サイドナビゲーションを折りたたむ\nExpand side navigation: サイドナビゲーションを展開\n"
  },
  {
    "path": "static/locales/ka.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ქართული ენა'\n\n# Webkit Menu Bar\nFile: 'ფაილი'\nNew Window: 'ახალი ფანჯარა'\nQuit: 'გამოსვლა'\nEdit: 'რედაქტირება'\nUndo: 'გაუქმება'\nRedo: 'გამეორება'\nCut: 'ამოჭრა'\nCopy: 'კოპირება'\nPaste: 'ჩასმა'\nDelete: 'წაშლა'\nSelect all: 'ყველას მონიშვნა'\nToggle Developer Tools: 'დამმუშავებლის ინსტრუმენტების გადართვა'\nActual size: 'რეალური ზომა'\nZoom in: 'მასშტაბის გაზრდა'\nZoom out: 'მასშტაბის შემცირება'\nToggle fullscreen: 'სრულ ეკრანზე გადართვა'\nWindow: 'ფანჯარა'\nMinimize: 'ჩაკეცვა'\nClose: 'დახურვა'\nBack: 'უკან'\nForward: 'წინ'\nOpen New Window: 'ახალი ფანჯრის გახსნა'\n\nVersion {versionNumber} is now available!  Click for more details: 'ხელმისაწვდომია {versionNumber} ვერსია!  დააჭირეთ დამატებითი ინფორმაციისთვის'\nDownload From Site: 'საიტიდან ჩამოტვირთვა'\nA new blog is now available, {blogTitle}. Click to view more: 'ხელმისაწვდომია ახალი ბლოგი, {blogTitle}. დააჭირეთ დამატებითი ინფორმაციისთვის'\nAre you sure you want to open this link?: 'დარწმუნებული ხართ, რომ გსურთ ამ ბმულის გახსნა?'\n\nGlobal:\n  Sort By: 'დალაგება'\n\n# Search Bar\n  Videos: ვიდეოები\n  Counts:\n    Subscriber Count: 1 გამომწერი | {count} გამომწერი\n    Like Count: 1 მოწონება | {count} მოწონება\n    View Count: 1 ნახვა | {count} ნახვა\n    Watching Count: 1 მაყურებელი | {count} მაყურებელი\n    Video Count: 1 ვიდეო | {count} ვიდეო\n    Channel Count: 1 არხი | {count} არხი\n    Comment Count: 1 კომენტარი | {count} კომენტარი\n  Shorts: შორტები\n  Live: პირდაპირი\n  Posts: პოსტები\nSearch / Go to URL: 'ძიება / URL მისამართზე გადასვლა'\nSearch Bar:\n  Clear Input: 'შეყვანის გასუფთავება'\n  # In Filter Button\n  Remove: წაშლა\nSearch Filters:\n  Search Filters: 'ძიების ფილტრები'\n  Sort By:\n    Most Relevant: 'ყველაზე შესაბამისი'\n    Rating: 'რეიტინგის მიხედვით'\n    Upload Date: 'ატვირთვის თარიღით'\n    View Count: 'ნახვების რაოდენობით'\n  Time:\n    Time: 'დრო'\n    Any Time: 'ნებისმიერი დრო'\n    Last Hour: 'ბოლო საათი'\n    Today: 'დღეს'\n    This Week: 'ამ კვირაში'\n    This Month: 'ამ თვეში'\n    This Year: 'ამ წელს'\n  Type:\n    Type: 'ტიპი'\n    All Types: 'ყველა ტიპი'\n    Videos: 'ვიდეოები'\n    Channels: 'არხები'\n    #& Playlists\n  Duration:\n    Duration: 'ხანგრძლივობა'\n    All Durations: 'ნებისმიერი ხანგრძლივობის'\n    Short (< 4 minutes): 'მოკლე (< 4 წუთი)'\n    Long (> 20 minutes): 'გრძელი (> 20 წუთი)'\n  # On Search Page\n  Search Results: 'ძიების შედეგი'\n  Fetching results. Please wait: 'მიმდინარეობს შედეგების მიღება. გთხოვთ, დაელოდოთ'\n  Fetch more results: 'მეტი შედეგის მიღება'\n  There are no more results for this search: 'ამ ძიებისთვის მეტი შედეგი არ არის'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'გამოწერები'\n  # channels that were likely deleted\n  Error Channels: 'შეცდომების მქონე არხები'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'ამ ანგარიშს აქვს გამოწერების დიდი რაოდენობა. იძულებით გამოიყენება RSS, რათა არ მოხდეს ტარიფის შეზღუდვა'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'თქვენი გამოწერების სია ამჟამად ცარიელია. თუ გნებავთ, შემოიტანოთ თქვენი გამოწერები, გადადით მონაცემების მორგების ფანჯარაში და აირჩიეთ გამოწერების შემოტანა. ან, შეგიძლიათ, მოძებნოთ არხები და გამოიწეროთ ისინი.'\n  Load More Videos: 'მეტი ვიდეოს ჩატვირთვა'\nMore: 'მეტი'\nChannels:\n  Channels: 'არხები'\n  Title: 'არხების სია'\n  Search bar placeholder: 'არხების ძიება'\n  Count: 'ნაპოვნია {number} არხი.'\n  Empty: 'თქვენი არხების სია ამჟამად ცარიელია.'\n  Unsubscribe Prompt: 'დარწმუნებული ხართ, რომ გსურთ \"{channelName}\"ის გამოწერის გაუქმება?'\nTrending:\n  Trending: 'პოპულარული'\n  Gaming: 'თამაშები'\n  Trending Tabs: 'პოპულარული'\n  Sports: სპორტი\nMost Popular: 'ყველაზე პოპულარული'\nPlaylists: 'დასაკრავი სიები'\nUser Playlists:\n  Your Playlists: 'თქვენი დასაკრავი სიები'\n  Empty Search Message: 'ამ დასაკრავ სიაში თქვენი ძიების შესაბამისი ვიდეოები არ არის'\n  Search bar placeholder: 'დასაკრავი სიების ძებნა'\nHistory:\n  # On History Page\n  History: 'ისტორია'\n  Watch History: 'ნახვის ისტორია'\n  Your history list is currently empty.: 'თქვენი ისტორიების სია ამჟამად ცარიელია.'\n  Empty Search Message: 'თქვენს ისტორიაში არ არის ვიდეოები, რომლებიც ემთხვევა თქვენს ძიებას'\n  Search bar placeholder: \"ისტორიაში ძიება\"\nSettings:\n  # On Settings Page\n  Settings: 'პარამეტრები'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'ცვლილებების ძალაში შესასვლელად საჭიროა აპლიკაციის გადატვირთვა. გსურთ რომ გადატვირთოთ და დაადასტუროთ შეტანილი ცვლილებები?'\n  General Settings:\n    General Settings: 'ზოგადი'\n    Check for Updates: 'განახლებების შემოწმება'\n    Check for Latest Blog Posts: 'უახლესი ბლოგპოსტების შემოწმება'\n    Fallback to Non-Preferred Backend on Failure: 'შეფერხების შემთხვევაში არაუპირატეს ძრავაზე დაბრუნება'\n    Enable Search Suggestions: 'ძიების შემოთავაზებების ჩართვა'\n    Default Landing Page: 'შესვლის სტანდარტული გვერდი'\n    Locale Preference: 'აპლიკაციის ენა'\n    System Default: 'სისტემის შესაბამისი'\n    Preferred API Backend:\n      Preferred API Backend: 'სტანდარტული API'\n      Local API: 'ლოკალური API'\n    Video View Type:\n      Video View Type: 'ვიდეოს ჩვენების ტიპი'\n      Grid: 'ბადე'\n      List: 'სია'\n    Thumbnail Preference:\n      Thumbnail Preference: 'მინიატურების პარამეტრი'\n      Default: 'სტანდარტული'\n      Beginning: 'დასაწყისში'\n      Middle: 'შუაში'\n      End: 'ბოლოში'\n    Current Invidious Instance: 'Invidious-ის მიმდინარე ასლი'\n    The currently set default instance is {instance}: 'ამჟამად დაყენებული ასლია {instance}'\n    No default instance has been set: 'სტანდარტული ასლი არ არის დაყენებული'\n    Current instance will be randomized on startup: 'ჩართვისას მიმდინარე ასლი იქნება შემთხვევით არჩეული'\n    Set Current Instance as Default: 'მიმდინარე ასლის ნაგულისხმევად დაყენება'\n    Clear Default Instance: 'ნაგულისხმევი ასლის გასუფთავება'\n    View all Invidious instance information: 'Invidious-ის ასლის შესახებ ყველა ინფორმაციის ნახვა'\n    Region for Trending: 'პოპულარული ვიდეოების არეალი'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'გარე ბმულების დამუშავება'\n      Open Link: 'ბმულის გახსნა'\n      Ask Before Opening Link: 'შეკითხვა ბმულის გახსნამდე'\n      No Action: 'მოქმედების გარეშე'\n  Theme Settings:\n    Theme Settings: 'თემა'\n    Match Top Bar with Main Color: 'ზედა ზოლისთვის მთავარი ფერის გამოყენება'\n    Expand Side Bar by Default: 'სტანდარტულად გვერდითი პანელის გაფართოება'\n    Disable Smooth Scrolling: 'გლუვი გადახვევის გამორთვა'\n    UI Scale: 'ინტერფეისის მასშტაბი'\n    Hide Side Bar Labels: 'გვერდითი პანელის ლეიბლების დამალვა'\n    Base Theme:\n      Base Theme: 'მთავარი თემა'\n      Black: 'შავი'\n      Dark: 'მუქი'\n      System Default: 'სისტემის შესაბამისი'\n      Light: 'ღია'\n      Dracula: 'დრაკულა'\n    Main Color Theme:\n      Main Color Theme: 'თემის მთავარი ფერი'\n      Red: 'წითელი'\n      Pink: 'ვარდისფერი'\n      Purple: 'იისფერი'\n      Deep Purple: 'მუქი იისფერი'\n      Indigo: 'Indigo'\n      Blue: 'ლურჯი'\n      Light Blue: 'ცისფერი'\n      Cyan: 'ფირუზისფერი'\n      Teal: 'ჩაისფერი'\n      Green: 'მწვანე'\n      Light Green: 'ღია მწვანე'\n      Lime: 'მუქი მწვანე'\n      Yellow: 'ყვითელი'\n      Amber: 'ყვითელ-ნარინჯისფერი'\n      Orange: 'ნარინჯისფერი'\n      Deep Orange: 'მუქი ნარინჯისფერი'\n      Dracula Cyan: 'ფირუზისფერი Dracula'\n      Dracula Green: 'მწვანე Dracula'\n      Dracula Orange: 'ნარინჯისფერი Dracula'\n      Dracula Pink: 'ვარდისფერი Dracula'\n      Dracula Purple: 'იისფერი Dracula'\n      Dracula Red: 'წითელი Dracula'\n      Dracula Yellow: 'ყვითელი Dracula'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mocha ვარდის წყალი'\n      Catppuccin Mocha Flamingo: 'Catppuccin Mocha ფლამინგო'\n      Catppuccin Mocha Pink: 'ვარდისფერი Catppuccin Mocha'\n      Catppuccin Mocha Mauve: 'მეწამულისფერი Catppuccin Mocha'\n      Catppuccin Mocha Red: 'წითელი Catppuccin Mocha'\n      Catppuccin Mocha Maroon: 'შინდისფერი Catppuccin Mocha'\n      Catppuccin Mocha Peach: 'ატმისფერი Catppuccin Mocha'\n  Player Settings: {}\nChannel:\n  Playlists: {}\n  Videos:\n    Videos: ვიდეოები\nVideo:\n  External Player: {}\nTooltips: {}\nAbout:\n  Email: ელფოსტა\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: დამმუშავებლის ინსტრუმენტების გადართვა\n  Zoom In: მასშტაბის გაზრდა\n  Zoom Out: მასშტაბის შემცირება\n  Fullscreen: სრულ ეკრანზე გადართვა\nPreferences: პრეფერენციები\nProfile:\n  Select All: ყველას მონიშვნა\nSearch character limit: ძებნის მოთხოვნა {searchCharacterLimit}-ზე მეტ სიმბოლოს შეიცავს\nGo to page: გადადით გვერდზე\nRight-click or hold to see history: მარჯვენა ღილაკით დააწკაპუნეთ ან დააჭირეთ და გააჩერეთ ისტორიის სანახავად\nClose Banner: დახურვა ბანერის\n"
  },
  {
    "path": "static/locales/km.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ភាសាខ្មែរ'\n\n# Webkit Menu Bar\nFile: 'ឯកសារ'\nQuit: 'ចាកចេញ'\nEdit: 'កែ'\nUndo: 'អាន់ឌូ'\nSearch Filters:\n  Type:\n    Videos: វីដេអូ\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\nChannel:\n  Videos:\n    Videos: វីដេអូ\nTooltips: {}\nNew Window: ផ្ទាំងថ្មី\nCopy: ចម្លង\nRedo: រីឌូ\nSelect all: រើសទាំងអស់\nPaste: បិតភ្ជាប់\nDelete: លុប\nCut: កាត់\nPreferences: ចំណូលចិត្ត\nKeyboardShortcutPrompt:\n  Zoom In: ពង្រីក\n  Zoom Out: បង្រួម\n  Fullscreen: បិទបើកការបង្ហាញពេញអេក្រង់\nProfile:\n  Select All: រើសទាំងអស់\nActual size: ទំហំជាក់ស្តែង\nZoom in: ពង្រីក\nZoom out: បង្រួម\nToggle fullscreen: បិទបើកការបង្ហាញពេញអេក្រង់\nWindow: ផ្ទាំងបង្អួច\nMinimize: បង្រួមតូច\nGlobal:\n  Videos: វីដេអូ\n  Live: បន្តផ្ទាល់\n"
  },
  {
    "path": "static/locales/ko.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: '한국어'\n\n# Webkit Menu Bar\nFile: '파일'\nQuit: '종료'\nEdit: '수정'\nUndo: '실행취소'\nRedo: '재실행'\nCut: '잘라내기'\nCopy: '복사하기'\nPaste: '붙여넣기'\nDelete: '지우기'\nSelect all: '전체선택'\nToggle Developer Tools: '개발자도구 전환'\nActual size: '실제크기'\nZoom in: '확대'\nZoom out: '축소'\nToggle fullscreen: '전체화면'\nWindow: '창모드'\nMinimize: '최소화'\nClose: '닫기'\nBack: '뒤로가기'\nForward: '앞으로가기'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: '동영상'\n\n  Live: 라이브\n  Posts: 게시물\n  Shorts: 쇼츠\n  Sort By: '정렬하기'\n  Counts:\n    Subscriber Count: 1명 구독자 | {count}명 구독\n    View Count: 1회 조회 | {count}회 조회\n    Watching Count: 1명 시청 중 | {count}명 시청 중\n    Video Count: 1개 동영상 | {count} 개 동영상\n    Channel Count: 1개 채널 | {count}개 채널\n    Comment Count: 1개 댓글 | {count}개 댓글\n    Like Count: 1개 좋아요 | {count}개 좋아요\nVersion {versionNumber} is now available!  Click for more details: '{versionNumber} 버전이 사용가능합니다! 클릭하여 자세한 정보를 확인하세요'\nDownload From Site: '사이트로부터 다운로드'\nA new blog is now available, {blogTitle}. Click to view more: '새로운 블로그가 업로드되었습니다, {blogTitle}. 클릭하여 확인하세요'\n\n# Search Bar\nSearch / Go to URL: '검색 / URL로 이동'\n  # In Filter Button\nSearch Filters:\n  Search Filters: '검색필터'\n  Sort By:\n    Most Relevant: '관련성'\n    Rating: '평가순'\n    Upload Date: '업로드일자'\n    View Count: '조회수'\n  Time:\n    Time: '시간'\n    Any Time: '모든시간'\n    Last Hour: '1시간 이내'\n    Today: '오늘'\n    This Week: '이번주'\n    This Month: '이번달'\n    This Year: '올해'\n  Type:\n    Type: '구분'\n    All Types: '전체'\n    Videos: '동영상'\n    Channels: '채널'\n    #& Playlists\n    Movies: 영화\n  Duration:\n    Duration: '영상길이'\n    All Durations: '모두'\n    Short (< 4 minutes): '짧음(4분이내)'\n    Long (> 20 minutes): '긴(20분)'\n  # On Search Page\n    Medium (4 - 20 minutes): 4~20분\n  Search Results: '검색 결과'\n  Fetching results. Please wait: '결과를 불러오는 중입니다. 잠시만 기다려 주세요'\n  Fetch more results: '검색 결과 더 보기'\n# Sidebar\n  There are no more results for this search: 이 검색 결과에 대한 항목이 더 없습니다\n  Features:\n    Creative Commons: 크리에이티브 커먼즈\n    Location: 위치\n    Features: 기능\n    3D: 3D\n    Live: 라이브\n    4K: 4K\n    360 Video: 360도 영상\n    HDR: HDR\n    VR180: VR180\n    HD: HD\n    Subtitles: 자막\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: '구독'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: '이 프로필에는 많은 구독이 있습니다. RSS가 속도 제한을 피하도록 강요합니다'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': '구독 목록이 현재 비어 있습니다. 구독을 가져오려면 데이터 설정으로 이동하여 구독 가져오기를 선택하거나, 채널을 검색하여 구독할 수 있습니다'\n  Load More Videos: '더 많은 동영상 불러오기'\n  Error Channels: 오류가 있는 채널\n  Disabled Automatic Fetching: 자동 구독 정보 수집이 비활성화 되어 있습니다. 구독을 새로고침해주세요.\n  Empty Channels: 구독한 채널들에 업로드 된 영상이 없습니다.\n  Empty Posts: 구독한 채널에 현재 게시물이 없습니다.\n  Subscriptions Tabs: 구독 탭\n  Load More Posts: 더 많은 게시물 불러오기\n  All Subscription Tabs Hidden: 모든 구독 탭이 숨겨져 있습니다. 여기에 콘텐츠를 보려면 \"{settingsSection}\"의 \"{subsection}\" 섹션에서 일부 탭을 표시해 주세요.\nTrending:\n  Trending: '트렌딩'\n  Trending Tabs: 트렌딩 탭\n  Gaming: 게임\n  Sports: 스포츠\nMost Popular: '인기 동영상'\nPlaylists: '재생 목록'\nUser Playlists:\n  Your Playlists: '나의 재생 목록'\n  Search bar placeholder: 재생목록 검색\n  Empty Search Message: 이 재생목록에는 검색어와 일치하는 동영상이 없습니다\n  This playlist currently has no videos.: 이 재생목록에는 현재 동영상이 없습니다.\n  Playlists with Matching Videos: 일치하는 동영상이 포함된 재생목록\n  You have no playlists. Click on the create new playlist button to create a new one.: 재생목록이 없습니다. 새 재생목록을 만들려면 새 재생목록 만들기 버튼을 클릭하세요.\n  Add to Playlist: 재생목록에 추가\n  Create New Playlist: 새 재생목록 만들기\nHistory:\n  # On History Page\n  History: '재생 기록'\n  Watch History: '시청 기록'\n  Your history list is currently empty.: '기록이 없습니다.'\n  Search bar placeholder: 기록에서 검색\n  Empty Search Message: 검색과 일치하는 동영상이 기록에 없습니다\nSettings:\n  # On Settings Page\n  Settings: '설정'\n  The app needs to restart for changes to take effect. Restart and apply change?: '변경된 설정을 적용하려면 재실행해야합니다. 재실행하고 설정을 변경하시겠습니까?'\n  General Settings:\n    General Settings: '일반 설정'\n    Check for Updates: '업데이트 확인하기'\n    Check for Latest Blog Posts: '최신 블로그포스트 확인하기'\n    Fallback to Non-Preferred Backend on Failure: '실패시 선호되지않는 백엔드로 대체하기'\n    Enable Search Suggestions: '검색추천 허용'\n    Default Landing Page: '기본 페이지'\n    Locale Preference: '로케일 설정'\n    Preferred API Backend:\n      Preferred API Backend: '선호하는 API 백엔드'\n      Local API: '로컬 API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: '동영상 목록'\n      Grid: '그리드'\n      List: '리스트'\n    Thumbnail Preference:\n      Thumbnail Preference: '썸네일 설정'\n      Default: '기본'\n      Beginning: '시작장면'\n      Middle: '중간장면'\n      End: '마지막장면'\n    Region for Trending: '트렌드 국가'\n        #! List countries\n    View all Invidious instance information: Indivious 서버의 전체 목록 보기\n    Current Invidious Instance: 현재 Invidious 인스턴스\n    System Default: 시스템 기본설정\n    No default instance has been set: 기본 인스턴스가 설정되지 않았습니다\n    The currently set default instance is {instance}: 현재 설정된 기본 인스턴스는 {instance}입니다\n    Current instance will be randomized on startup: 현재 인스턴스는 시작 시 무작위로 지정됩니다\n    Set Current Instance as Default: 현재 인스턴스를 기본값으로 설정\n    Clear Default Instance: 기본 인스턴스 지우기\n    External Link Handling:\n      External Link Handling: 외부 링크 처리\n      Open Link: 링크 열기\n      Ask Before Opening Link: 링크를 열기 전에 확인\n      No Action: 아무것도 안함\n  Theme Settings:\n    Theme Settings: '테마 설정'\n    Match Top Bar with Main Color: '상단바를 메인컬러와 동기화'\n    Expand Side Bar by Default: '기본으로 사이드바 확장'\n    Disable Smooth Scrolling: '부드러운 스크롤 사용안하기'\n    UI Scale: 'UI 스케일'\n    Base Theme:\n      Base Theme: '기본 테마'\n      Black: '검정'\n      Dark: '어두운 테마'\n      Light: '밝은 테마'\n      Dracula: '드라큘라'\n      System Default: 시스템 기본값\n      Catppuccin Mocha: 카푸치노 모카\n    Main Color Theme:\n      Main Color Theme: '메인 색상 테마'\n      Red: '빨강'\n      Pink: '분홍'\n      Purple: '보라'\n      Deep Purple: '진보라'\n      Indigo: '남색'\n      Blue: '파랑'\n      Light Blue: '하늘'\n      Cyan: '시안'\n      Teal: '청록'\n      Green: '녹색'\n      Light Green: '연녹색'\n      Lime: '라임'\n      Yellow: '노랑'\n      Amber: '호박색'\n      Orange: '주황'\n      Deep Orange: '진주황'\n      Dracula Cyan: '드라큘라 시안'\n      Dracula Green: '드라큘라 녹색'\n      Dracula Orange: '드라큘라 주황'\n      Dracula Pink: '드라큘라 보라'\n      Dracula Purple: '드라큘라 보라'\n      Dracula Red: '드라큘라 빨강'\n      Dracula Yellow: '드라큘라 노랑'\n      Catppuccin Mocha Rosewater: 카푸치노 모카 로즈워터\n      Catppuccin Mocha Flamingo: 카푸치노 모카 플라밍고\n      Catppuccin Mocha Pink: 카푸치노 모카 핑크\n      Catppuccin Mocha Mauve: 카푸치노 모카 자주빛\n      Catppuccin Mocha Red: 카푸치노 모카 빨강\n      Catppuccin Mocha Maroon: 카푸치노 모카 적갈색\n      Catppuccin Mocha Peach: 카푸치노 모카 복숭아\n      Catppuccin Mocha Yellow: 카푸치노 모카 노랑\n      Catppuccin Mocha Green: 카푸치노 모카 녹색\n      Catppuccin Mocha Sapphire: 카푸치노 모카 사파이어\n      Catppuccin Mocha Blue: 카푸치노 모카 파랑\n      Catppuccin Mocha Lavender: 카푸치노 모카 라벤더\n      Catppuccin Mocha Teal: 카푸치노 모카 청록색\n      Catppuccin Mocha Sky: 카푸치노 모카 하늘색\n    Secondary Color Theme: '보조색상테마'\n        #* Main Color Theme\n    Hide Side Bar Labels: 사이드 바 레이블 숨기기\n    Hide FreeTube Header Logo: FreeTube 헤더 로고 숨기기\n  Player Settings:\n    Player Settings: '플레이어 설정'\n    Play Next Video: '다음 동영상 재생'\n    Turn on Subtitles by Default: '기본으로 자막켜기'\n    Autoplay Videos: '동영상 자동재생'\n    Proxy Videos Through Invidious: 'Invidious를 통한 프록시 비디오'\n    Autoplay Playlists: '재생목록 자동재생'\n    Enable Theatre Mode by Default: '기본으로 극장모드 설정'\n    Default Volume: '기본 음량'\n    Default Playback Rate: '기본 재생속도'\n    Default Video Format:\n      Default Video Format: '기본 비디오 포맷'\n      Dash Formats: 'DASH 포맷'\n      Legacy Formats: '레거시'\n      Audio Formats: '오디오'\n    Default Quality:\n      Default Quality: '기본 해상도'\n      Auto: '자동'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: 빨리 감기/되감기 간격\n    Next Video Interval: 다음 비디오 재생 간격\n    Scroll Volume Over Video Player: 플레이어 위로 스크롤하여 볼륨조정\n    Display Play Button In Video Player: 비디오 플레이어 위에 재생 버튼 표시\n    Scroll Playback Rate Over Video Player: 비디오 플레이어 위로 스크롤 재생 속도\n    Max Video Playback Rate: 최대 비디오 재생 속도\n    Video Playback Rate Interval: 비디오 재생 속도 간격\n    Screenshot:\n      Folder Label: 스크린샷 폴더\n      Ask Path: 폴더 저장 요청\n      Folder Button: 폴더 선택\n      Error:\n        Empty File Name: 빈 파일 이름\n        Forbidden Characters: 금지된 문자\n      Enable: 스크린샷 사용\n      Format Label: 스크린샷 형식\n      Quality Label: 스크린샷 품질\n      File Name Label: 파일 이름 패턴\n      File Name Tooltip: 아래 변수를 사용할 수 있습니다. %Y 년 4자리. %M 월 2자리. %D 일 2자리. %H 시간 2자리. %N 분 2자리. %S 초 2자리. %T 밀리초 3자리. %s 비디오초. %t 비디오 밀리초 3자리. %i 비디오 ID.\n    Skip by Scrolling Over Video Player: 비디오 플레이어를 스크롤하여 건너뛰기\n    Enter Fullscreen on Display Rotate: 화면 회전 시 전체화면 활성화하기\n  Privacy Settings:\n    Privacy Settings: '개인정보 설정'\n    Remember History: '기록 저장하기'\n    Save Watched Progress: '마지막으로 시청한 구간 저장'\n    Clear Search Cache: '검색 캐시 삭제'\n    Are you sure you want to clear out your search cache?: '정말로 검색 캐시를 삭제하시겠습니까?'\n    Search cache has been cleared: '검색 캐시가 삭제되었습니다'\n    Remove Watch History: '시청 기록 삭제'\n    Are you sure you want to remove your entire watch history?: '정말로 시청기록을 삭제하시겠습니까?'\n    Watch history has been cleared: '시청기록이 삭제되었습니다'\n    Remove All Subscriptions / Profiles: '모든 구독채널과 프로필 삭제'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: '정말로 모든 구독채널과 프로필을 삭제하시겠습니까? 삭제하면 복구가되지않습니다.'\n  Subscription Settings:\n    Subscription Settings: '구독 설정'\n    Fetch Feeds from RSS: 'RSS에서 피드 가져오기'\n    Fetch Automatically: 자동으로 피드 수집하기\n  Distraction Free Settings:\n    Distraction Free Settings: '방해받지 않는 모드 설정'\n    Hide Video Views: '조회수 숨기기'\n    Hide Video Likes And Dislikes: '좋아하는 비디오와 싫어하는 비디오 숨기기'\n    Hide Channel Subscribers: '채널 구독자 숨기기'\n    Hide Comment Likes: '댓글 좋아요 숨기기'\n    Hide Recommended Videos: '추천 비디오 숨기기'\n    Hide Trending Videos: '트렌드 비디오 숨기기'\n    Hide Popular Videos: '인기 있는 비디오 숨기기'\n    Hide Live Chat: '실시간 댓글 숨기기'\n    Hide Playlists: 재생 목록 숨기기\n    Hide Active Subscriptions: 활성 구독 숨기기\n    Hide Sharing Actions: 공유 작업 숨기기\n    Hide Videos on Watch: '시청한 동영상 숨기기'\n    Hide Live Streams: 라이브 스트림 숨기기\n    Hide Video Description: 비디오 설명 숨기기\n    Hide Comments: 주석 숨기기\n    Hide Upcoming Premieres: 공개 예정 Premiere 숨기기\n    Hide Chapters: 챕터 숨기기\n    Display Titles Without Excessive Capitalisation: 제목에서 과도한 대문자 제거하기\n    Hide Channels: 채널 목록에서 동영상 숨기기\n    Hide Channels Placeholder: 채널 이름이나 ID를 입력하세요\n  Data Settings:\n    Data Settings: '데이터 설정'\n    Select Export Type: '내보내기 유형 선택'\n    Import Subscriptions: '구독 목록 가져오기'\n    Export Subscriptions: '구독 목록 내보내기'\n    Export FreeTube: 'FreeTube 내보내기'\n    Export YouTube: 'YouTube 내보내기'\n    Export NewPipe: 'NewPipe 내보내기'\n    Import History: '재생 기록 가져오기'\n    Export History: '재생 기록 내보내기'\n    Profile object has insufficient data, skipping item: '프로필 개체에 데이터가 부족하여 항목을 건너뜁니다'\n    All subscriptions and profiles have been successfully imported: '모든 구독 및 프로필을 성공적으로 가져왔습니다'\n    All subscriptions have been successfully imported: '모든 구독을 성공적으로 가져왔습니다'\n    Invalid subscriptions file: '잘못된 구독 파일입니다'\n    Invalid history file: '잘못된 기록 파일입니다'\n    Subscriptions have been successfully exported: '구독을 성공적으로 내보냈습니다'\n    History object has insufficient data, skipping item: '기록 개체에 데이터가 부족하여 항목을 건너뜁니다'\n    All watched history has been successfully imported: '시청한 모든 기록을 성공적으로 가져왔습니다'\n    All watched history has been successfully exported: '시청한 모든 기록이 성공적으로 내보내졌습니다'\n    Unable to read file: '파일을 읽을 수 없습니다'\n    Unable to write file: '파일을 쓸 수 없습니다'\n    Unknown data key: '알 수 없는 데이터 키입니다'\n    How do I import my subscriptions?: '구독을 가져오려면 어떻게 해야 합니까?'\n    Manage Subscriptions: 구독 관리\n    Playlist insufficient data: '\"{playlist}\" 재생 목록에 대한 데이터가 부족하여 항목을 건너뜁니다'\n    All playlists has been successfully imported: 모든 재생 목록을 성공적으로 가져왔습니다\n    All playlists has been successfully exported: 모든 재생 목록을 내보냈습니다\n    Import Playlists: 재생 목록 가져오기\n    Export Playlists: 재생 목록 내보내기\n    Subscription File: 구독 정보 파일\n    Playlist File: 재생목록 파일\n    History File: 시청기록 파일\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: 네트워크 정보를 가져오는 중 오류가 발생했습니다. 프록시가 올바르게 구성되어 있습니까?\n    City: 도시\n    Region: 지역\n    Country: 국가\n    Ip: Ip\n    Your Info: 사용자 정보\n    Test Proxy: 프록시 테스트\n    Clicking on Test Proxy will send a request to: 프록시 테스트를 클릭하면 다음 주소로 요청이 전송됩니다\n    Proxy Port Number: 프록시 포트 번호\n    Proxy Host: 프록시 호스트\n    Proxy Protocol: 프록시 프로토콜\n    Enable Tor / Proxy: Tor / Proxy 사용\n    Proxy Settings: 프록시 설정\n  SponsorBlock Settings:\n    SponsorBlock Settings: SponsorBlock 설정\n    Enable SponsorBlock: SponsorBlock 사용\n    Notify when sponsor segment is skipped: 스폰서 구간을 건너뛸 경우 알림\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API 주소 (기본 주소는 https://sponsor.ajay.app 입니다)\n    Skip Options:\n      Auto Skip: 자동 건너뛰기\n      Show In Seek Bar: 탐색 막대에 표시\n      Skip Option: 옵션 건너뛰기\n      Do Nothing: 아무것도 안 함\n      Prompt To Skip: 건너뛰기 확인\n    Category Color: 범주 색상\n  External Player Settings:\n    External Player Settings: 외부 플레이어 설정\n    Custom External Player Arguments: 사용자 정의 외부 플레이어 인수\n    Custom External Player Executable: 사용자 정의 외부 플레이어 실행 파일\n    External Player: 외부 플레이어\n    Ignore Unsupported Action Warnings: 지원되지 않는 작업 경고 무시\n    Players:\n      None:\n        Name: 이름 *\n  Parental Control Settings:\n    Parental Control Settings: 자녀 보호 설정\n    Hide Unsubscribe Button: 구독 취소 단추 숨기기\n    Hide Search Bar: 검색 막대 숨기기\n    Show Family Friendly Only: 가족 친목만 표시\n  Password Dialog:\n    Password: 비밀번호\n    Enter Password To Unlock: 설정을 활성화하기 위해서 비밀번호를 입력하세요\n  Experimental Settings:\n    Experimental Settings: 실험적 기능 설정\n    Warning: 본 설정들은 실험적 기능이며, 활성화 되었을 때 충돌을 유발할 수 있습니다. 백업을 하는 것을 강력히 권장합니다. 모든 책임은 사용자 본인에게 있습니다!\n    Replace HTTP Cache: HTTP 캐시 대체하기\n  Password Settings:\n    Password Settings: 비밀번호 설정\n    Set Password To Prevent Access: 설정 접근에 비밀번호 설정하기\n    Set Password: 비밀번호 설정하기\n    Remove Password: 비밀번호 제거하기\nAbout:\n  #On About page\n  About: '정보'\n  #& About\n  Donate: 기부\n  these people and projects: 이 사람들과 프로젝트\n  Credits: 제작\n  Translate: 번역\n  room rules: 방 규정\n  Chat on Matrix: 매트릭스 채팅\n  Mastodon: 마스토돈\n  Email: 이메일\n  Blog: 블로그\n  Website: 웹사이트\n  Please check for duplicates before posting: 게시하기 전에 중복 항목을 확인하십시오\n  GitHub issues: GitHub 이슈\n  Report a problem: 문제 보고\n  FAQ: FAQ\n  FreeTube Wiki: FreeTube Wiki\n  Help: 도움말\n  GitHub releases: GitHub 릴리스\n  Downloads / Changelog: 다운로드 / 변경 로그\n  Source code: 소스 코드\n  Beta: 베타\nProfile:\n  Profile Select: '프로필 선택'\n  All Channels: '모든 채널'\n  Profile Manager: '프로필 관리자'\n  Create New Profile: '새 프로파일 작성'\n  Edit Profile: '프로필 편집'\n  Color Picker: '색상 선택기'\n  Custom Color: '사용자 지정 색'\n  Profile Preview: '프로필 미리보기'\n  Create Profile: '프로필 작성'\n  Update Profile: '프로필 업데이트'\n  Make Default Profile: '기본 프로파일 만들기'\n  Delete Profile: '프로필 삭제'\n  Are you sure you want to delete this profile?: '이 프로필을 삭제하시겠습니까?'\n  All subscriptions will also be deleted.: '모든 구독도 삭제됩니다.'\n  Your profile name cannot be empty: '프로필 이름은 비워 둘 수 없습니다'\n  Profile has been created: '프로필이 생성되었습니다'\n  Profile has been updated: '프로필이 업데이트되었습니다'\n  Your default profile has been set to {profile}: '기본 프로필이 {profile}로 설정되었습니다'\n  Removed {profile} from your profiles: '프로필에서 {profile}가 제거되었습니다'\n  Your default profile has been changed to your primary profile: '기본값 프로필이 기본 프로필로 변경되었습니다'\n  '{profile} is now the active profile': '{profile}가 현재 활성 프로필입니다'\n  Subscription List: '구독 목록'\n  Other Channels: '기타 채널'\n  '{number} selected': '{number}선택되었습니다'\n  Select All: '모두 선택'\n  Select None: '선택 안 함'\n  Delete Selected: '선택한 항목 삭제'\n  Add Selected To Profile: '프로필에 선택한 항목 추가'\n  No channel(s) have been selected: '선택된 채널이 없습니다'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : '이것은 귀하의 기본 프로필입니다. 선택한 채널을 삭제하시겠습니까? 동일한 채널이 발견되는 모든 프로필에서 삭제됩니다.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: '선택한 채널을 삭제하시겠습니까? 다른 프로파일에서는 채널이 삭제되지 않습니다.'\n#On Channel Page\n  Profile Filter: 프로필 필터\n  Profile Settings: 프로필 설정\nChannel:\n  Subscribe: '구독'\n  Unsubscribe: '구독 취소'\n  Channel has been removed from your subscriptions: '채널이 구독에서 제거되었습니다'\n  Removed subscription from {count} other channel(s): '{count} 다른 채널에서 구독을 제거했습니다'\n  Added channel to your subscriptions: '구독에 채널을 추가했습니다'\n  Search Channel: '채널 검색'\n  Your search results have returned 0 results: '0 건이 검색되었습니다'\n  Videos:\n    Videos: '동영상'\n    This channel does not currently have any videos: '이 채널에는 현재 비디오가 없습니다'\n    Sort Types:\n      Newest: '새로운 영상부터'\n      Oldest: '오래된 영상부터'\n      Most Popular: '인기순으로'\n  Playlists:\n    Playlists: '재생목록'\n    This channel does not currently have any playlists: '이 채널에는 재생목록이 없습니다'\n    Sort Types:\n      Last Video Added: '마지막으로 추가된 동영상'\n      Newest: '최신'\n      Oldest: '오래된'\n  About:\n    About: '정보'\n    Channel Description: '채널 설명'\n    Featured Channels: '추천 채널'\n  Podcasts:\n    Podcasts: 팟캐스트\nVideo:\n  Mark As Watched: '시청함으로 표시'\n  Remove From History: '기록에서 제거'\n  Video has been marked as watched: '동영상이 시청함으로 표시되었습니다'\n  Video has been removed from your history: '동영상이 기록에서 삭제되었습니다'\n  Open in YouTube: 'YouTube에서 열기'\n  Copy YouTube Link: 'YouTube 링크 복사'\n  Open YouTube Embedded Player: 'YouTube 내장 플레이어 열기'\n  Copy YouTube Embedded Player Link: 'YouTube 내장 플레이어 링크 복사'\n  Open in Invidious: 'Invidious에서 열기'\n  Copy Invidious Link: 'Invidious 링크 복사'\n  Open Channel in YouTube: 'YouTube에서 채널 열기'\n  Copy YouTube Channel Link: 'YouTube 채널 링크 복사'\n  Open Channel in Invidious: 'Invidious에서 채널 열기'\n  Copy Invidious Channel Link: 'Invidious 채널 링크 복사'\n  Views: '보기'\n  Loop Playlist: '재생 목록 반복'\n  Shuffle Playlist: '재생 목록 셔플'\n  Reverse Playlist: '재생 목록 역재생'\n  Previous: '이전'\n  Next: '다음'\n  Watched: '시청함'\n  Autoplay: '자동 재생'\n  Starting soon, please refresh the page to check again: '곧 시작됩니다. 다시 확인하려면 페이지를 새로고침하십시오'\n  # As in a Live Video\n  Live: '라이브'\n  Live Now: '지금 생방송'\n  Live Chat: '라이브 채팅'\n  Enable Live Chat: '라이브 채팅 활성화'\n  Live Chat is currently not supported in this build.: '라이브 채팅은 현재 이 빌드에서 지원되지 않습니다.'\n  Live chat is enabled. Chat messages will appear here once sent.: '라이브 채팅이 활성화되었습니다.   채팅 메시지가 전송되면 여기에 표시됩니다.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': '라이브 채팅은 현재 Invidious API에서 지원되지 않습니다.   YouTube에 직접 연결해야 합니다.'\n  Published:\n    In less than a minute: 1분 이내에\n  Published on: '게시일'\n  Streamed on: '스트리밍됨'\n  Started streaming on: '스트리밍 시작'\n#& Videos\n  Video has been saved: 동영상이 저장되었습니다\n  Video has been removed from your saved list: 저장된 목록에서 동영상이 제거되었습니다\n  Save Video: 비디오 저장\n  External Player:\n    Unsupported Actions:\n      opening specific video in a playlist (falling back to opening the video): 재생 목록에서 특정 비디오 열기 (비디오 열기로 되돌아가기)\n      reversing playlists: 재생 목록 되돌리기\n      shuffling playlists: 재생 목록을 뒤섞기\n      looping playlists: 재생 목록 반복\n      starting video at offset: 오프셋에서 비디오 시작\n      setting a playback rate: 재생 속도 설정\n      opening playlists: 재생 목록 열기\n    UnsupportedActionTemplate: '{externalPlayer} 지원하지 않음: {action}'\n    OpenInTemplate: '{externalPlayer}로 열기'\n    OpeningTemplate: '{externalPlayer}에서 {videoOrPlaylist}를 여는 중...'\n    video: 비디오\n    playlist: 재생목록\n  Sponsor Block category:\n    music offtopic: 음악 주제에서 벗어나기\n    recap: 씌우기\n    filler: 필터\n    sponsor: 스폰서\n    intro: 도입부\n    outro: 결말부\n    self-promotion: 자기 홍보\n    interaction: 상호 작용\n  Premieres: 프리미어\n  Upcoming: 공개 예정\n  Show Super Chat Comment: 슈퍼채팅 댓글 보이기\n  Scroll to Bottom: 맨 아래로 스크롤하기\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: '전체 재생 목록 보기'\n  Last Updated On: '마지막 업데이트 날짜'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: 재생 목록\nChange Format:\n  Change Media Formats: '비디오 형식 변경'\n  Use Dash Formats: 'DASH 형식 사용'\n  Use Legacy Formats: '레거시 형식 사용'\n  Use Audio Formats: '오디오 형식 사용'\n  Dash formats are not available for this video: '이 비디오에는 DASH 형식을 사용할 수 없습니다'\n  Audio formats are not available for this video: '이 비디오에는 오디오 형식을 사용할 수 없습니다'\nShare:\n  Share Video: '동영상 공유'\n  Share Playlist: '재생 목록 공유'\n  Include Timestamp: '타임스탬프 포함'\n  Copy Link: '링크 복사'\n  Open Link: '링크 열기'\n  Copy Embed: '임베드 복사'\n  Open Embed: '임베드 열기'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL이 클립보드에 복사되었습니다'\n  Invidious Embed URL copied to clipboard: 'Invidious 임베드 URL이 클립보드에 복사되었습니다'\n  Invidious Channel URL copied to clipboard: 'Invidious 채널 URL이 클립보드에 복사되었습니다'\n  YouTube URL copied to clipboard: 'YouTube URL이 클립보드에 복사되었습니다'\n  YouTube Embed URL copied to clipboard: 'YouTube 임베드 URL이 클립보드에 복사되었습니다'\n  YouTube Channel URL copied to clipboard: 'YouTube 채널 URL이 클립보드에 복사되었습니다'\n\n  Share Channel: 채널 공유하기\nMini Player: '미니 플레이어'\nComments:\n  Comments: '댓글'\n  Click to View Comments: '댓글을 보려면 클릭하세요'\n  Getting comment replies, please wait: '댓글의 답글을 받는 중입니다. 잠시만 기다려 주세요'\n  There are no more comments for this video: '이 영상에 대한 댓글이 더 이상 없습니다'\n  Hide Comments: '댓글 숨기기'\n  Top comments: '인기 댓글'\n  Newest first: '최신 우선'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: '이 영상에 대한 댓글이 없습니다'\n  Load More Comments: '더 많은 댓글 불러오기'\n  Show More Replies: 더 많은 답글 보기\n  Pinned by: 고정된 댓글\n  Member: 구성원\n  Hearted: 좋아요 표시한\n  View {replyCount} replies: '{replyCount} 개의 답글 보기'\nUp Next: '다음 위로'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'FreeTube가 데이터를 얻기 위해 사용하는 백엔드를 선택하십시오. 로컬 API는 기본 제공 추출기입니다. Invidious API는 연결할 Invidious 서버가 필요합니다.'\n    Fallback to Non-Preferred Backend on Failure: '선호하는 API에 문제가 있는 경우 FreeTube는 활성화될 때, 선호하지 않는 API를 대체 방법으로 사용하려고 자동으로 시도합니다.'\n    Thumbnail Preference: 'FreeTube 전체의 모든 썸네일은 기본 썸네일 대신 비디오 프레임으로 대체됩니다.'\n    Invidious Instance: 'FreeTube가 API 호출을 위해 연결할 Invidious 인스턴스입니다.'\n    Region for Trending: '트렌드 지역을 통해 표시하고 싶은 국가의 트렌드 비디오를 선택할 수 있습니다.'\n    External Link Handling: \"FreeTube에서 열 수 없는 링크를 클릭할 때 기본 동작을 선택합니다.\\n기본적으로 FreeTube는 기본 브라우저에서 클릭한 링크를 엽니다.\\n\"\n  Player Settings:\n    Proxy Videos Through Invidious: 'YouTube에 직접 연결하는 대신 Invidious에 연결하여 동영상을 제공합니다. API 기본 설정을 재정의합니다.'\n    Default Video Format: '동영상 재생 시 사용되는 형식을 설정합니다. DASH 형식은 더 높은 품질을 재생할 수 있습니다. 레거시 형식은 최대 720p로 제한되지만 더 적은 대역폭을 사용합니다. 오디오 형식은 오디오 전용 스트림입니다.'\n    Scroll Playback Rate Over Video Player: 커서가 비디오 위에 있는 동안 Control 키( Mac의 경우 Command 키)를 길게 누르고 마우스 휠을 앞뒤로 스크롤하여 재생 속도를 제어합니다. Control 키 (Mac의 경우 Command 키)를 길게 누르고 마우스 왼쪽 버튼을 클릭하여 기본 재생 속도(설정에서 변경되지 않은 경우 1배)로 빠르게 돌아갑니다.\n    Skip by Scrolling Over Video Player: MPV 방식으로 마우스 스크롤을 이용해 영상을 스킵합니다.\n  Subscription Settings:\n    Fetch Feeds from RSS: '활성화되면 FreeTube는 구독 피드를 가져오는 기본 방법 대신 RSS를 사용합니다. RSS는 더 빠르고 IP 차단을 방지하지만 비디오 길이 또는 라이브 상태와 같은 특정 정보를 제공하지 않습니다'\n\n# Toast Messages\n  External Player Settings:\n    DefaultCustomArgumentsTemplate: \"(기본: '{defaultCustomArguments}')\"\n    External Player: 외부 플레이어를 선택하면 썸네일에서 비디오 (지원되는 경우 재생 목록)를 열 수 있는 아이콘이 표시됩니다. 경고, 위반 설정은 외부 플레이어에 영향을 주지 않습니다.\n    Custom External Player Executable: 기본적으로 FreeTube는 PATH 환경 변수를 통해 선택한 외부 플레이어를 찾을 수 있다고 가정합니다. 필요한 경우 여기에서 사용자 정의 경로를 설정할 수 있습니다.\n    Ignore Warnings: '현재 외부 플레이어가 현재 작업을 지원하지 않는 경우(예: 재생 목록 반전 등) 경고를 표시하지 않습니다.'\n    Custom External Player Arguments: 외부 플레이어로 전달되기를 원하는사용자 지정 명령줄 인수는 세미콜론(';')으로 구분됩니다.\n  Distraction Free Settings:\n    Hide Channels: 채널 이름이나 채널 ID를 입력해 해당 채널의 영상이나 재생목록, 채널 자체가 검색이나 인기 영상에 나타나지 않도록 합니다. 입력되는 채널 이름은 완전히 일치해야하며, 대소문자를 구별합니다.\nLocal API Error (Click to copy): '로컬 API 오류(복사하려면 클릭)'\nInvidious API Error (Click to copy): 'Invidious API 오류(복사하려면 클릭)'\nFalling back to Invidious API: 'Invidious API로 대체'\nFalling back to Local API: '로컬 API로 대체'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: '이 동영상은 형식이 누락되어 사용할 수 없습니다. 이는 국가를 사용할 수 없기 때문에 발생할 수 있습니다.'\nLoop is now disabled: '반복이 비활성화되었습니다'\nLoop is now enabled: '반복이 활성화되었습니다'\nShuffle is now disabled: '셔플이 비활성화되었습니다'\nShuffle is now enabled: '셔플이 활성화되었습니다'\nThe playlist has been reversed: '재생 목록이 역순이 되었습니다'\nPlaying Next Video: '다음 비디오 재생'\nPlaying Previous Video: '이전 비디오 재생'\nCanceled next video autoplay: '다음 동영상 자동재생 취소됨'\n'The playlist has ended. Enable loop to continue playing': '재생목록이 종료되었습니다. 계속 재생하려면 반복 활성화'\n\nYes: '예'\nNo: '아니오'\nMore: 더 보기\nUnknown YouTube url type, cannot be opened in app: 알 수 없는 YouTube URL 유형, 앱에서 열 수 없음\nPlaying Next Video Interval: 즉시 다음 동영상을 재생합니다. 취소하려면 클릭하세요. | {nextVideoInterval}초 후에 다음 동영상을 재생합니다. 취소하려면 클릭하세요. | {nextVideoInterval}초 후에 다음 동영상을 재생합니다. 취소하려면 클릭하세요.\nDefault Invidious instance has been set to {instance}: 기본 Invidious 인스턴스가 {instance}로 설정되었습니다\nExternal link opening has been disabled in the general settings: 일반 설정에서 외부 링크 열기가 비활성화되었습니다\nOpen New Window: 새 창 열기\nDefault Invidious instance has been cleared: 기본 Invidious 인스턴스가 제거되었습니다\nAre you sure you want to open this link?: 이 링크를 여시겠습니까?\nSearch Bar:\n  Clear Input: 입력 지우기\n  Remove: 삭제\nNew Window: 새 창\nChannels:\n  Channels: 채널\n  Title: 채널 목록\n  Search bar placeholder: 채널 검색\n  Empty: 채널 목록이 비어 있습니다.\n  Unsubscribe Prompt: '\"{channelName}\"에서 구독을 취소하시겠습니까?'\n  Count: '{number} 채널이 발견되었습니다.'\nScreenshot Error: 스크린샷이 실패했습니다. {error}\nScreenshot Success: 스크린샷을 \"{filePath}\"로 저장\nClipboard:\n  Copy failed: 클립보드에 복사 실패\n  Cannot access clipboard without a secure connection: 안전한 연결 없이 클립보드에 접근할 수 없습니다\nChapters:\n  Chapters: 챕터\nPreferences: 설정\nClose Banner: 배너 닫기\nSearch Listing:\n  Label:\n    4K: 4K\n    New: 새로운\n    Subtitles: 자막\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    3D: 3D\n    Closed Captions: 자막 해설\nSearch character limit: 검색 쿼리가 {searchCharacterLimit}자 제한을 초과했습니다\nKeyboardShortcutPrompt:\n  Focus Search: 검색창에 포커스\n  Last Frame: 이전 프레임 (일시정지 중)\n  Small Fast Forward: 현재 비디오 재생 속도와 빨리 감기 간격을 기준으로 X초 빨리 감기\n  Next Frame: 다음 프레임 (일시정지 중)\n  Volume Up: 볼륨 높이기\n  Toggle Developer Tools: 개발자 도구 전환\n  Reset Zoom: 확대/축소 수준 / UI 크기 초기화\n  Zoom In: 확대\n  Zoom Out: 축소\n  Volume Down: 볼륨 낮추기\n  Small Rewind: 현재 비디오 재생 속도와 되감기 간격을 기준으로 X초 되감기\n  Search in New Window: 새 창에서 검색\n  Fullscreen: 전체화면\nRight-click or hold to see history: 우클릭하거나 길게 눌러 기록을 확인하세요\nGo to page: '{page}로 이동'\nFeed:\n  Feed Last Updated: '{feedName} 피드 마지막 업데이트: {date}'\n  Refresh Feed: '{subscriptionName} 새로 고침'\n"
  },
  {
    "path": "static/locales/ku.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'کوردی ناوەڕاست'\n\n# Webkit Menu Bar\nFile: 'پەڕگە'\nQuit: 'دەرچوون'\nEdit: 'دەستکاری'\nUndo: 'پووچکردنەوە'\nRedo: 'هێنانەوە'\nCut: 'بڕین'\nCopy: 'لەبەرگرتنەوە'\nPaste: 'لکاندن'\nDelete: 'سڕینەوە'\nSelect all: 'دیاریکردنی هەمووی'\nToggle Developer Tools: 'زامنی ئامرازەکانی گەشەپێدەر'\nActual size: 'قەبارەی ڕاستەقینە'\nZoom in: 'زووم کردنە ناوەوە'\nZoom out: 'زووم کردنە دەرەوە'\nToggle fullscreen: 'شاشەکەت پرکەرەوە'\nWindow: 'پەنجەرە'\nMinimize: 'بچوک کردنەوە'\nClose: 'داخستن'\nBack: 'گەڕانەوە'\nForward: 'چونەپێشەوە'\n\nVersion {versionNumber} is now available!  Click for more details: 'ئێستا وەشانی {versionNumber} بەردەستە..بۆ زانیاری زۆرتر کرتە بکە'\nDownload From Site: 'لە وێبگەوە دایگرە'\nA new blog is now available, {blogTitle}. Click to view more: 'بڵۆگێکی نوێ بەردەستە، {blogTitle}. کلیک بکە بۆ بینینی زیاتر'\n\nGlobal:\n  Sort By: 'بگەڕی بە'\n\n# Search Bar\n  Live: ژیاوازی\n  Shorts: شورتەکان\n  Counts:\n    Video Count: 1 ڤیدیۆ | {count} ڤیدیۆکان\n    Subscriber Count: 1 بەشداربوو | {count} بەشداربووان\n    Channel Count: 1 کەناڵ | {count} کەناڵەکان\n    View Count: 1 بینین | {count} بینینەکان\n    Like Count: 1 لایک | {count} لایک\n    Comment Count: 1 کۆمێنت | {count} کۆمێنتەکان\n    Watching Count: 1 سەیرکردنی | {count} سەیرکردن\n  Videos: ویدیوەکان\n  Posts: پۆستەکان\nSearch / Go to URL: 'گەڕان / بڕۆ بۆ لینک'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'فیلتەری گەڕان'\n  Sort By:\n    Most Relevant: 'گرنگترین'\n    Rating: 'ڕەیتینگ'\n    Upload Date: 'کاتی بڵاوکردنەوە'\n    View Count: 'ژماری بینراو'\n  Time:\n    Time: 'کات'\n    Any Time: 'هەرکاتێک'\n    Last Hour: 'کاتژمێری پێشوو'\n    Today: 'ئەمڕۆ'\n    This Week: 'ئەم هەفتەیە'\n    This Month: 'ئەم مانگە'\n    This Year: 'ئەم ساڵە'\n  Type:\n    Type: 'جۆر'\n    All Types: 'گشت جۆر'\n    Videos: 'ڤیدیۆکان'\n    Channels: 'کەناڵەکان'\n    #& Playlists\n    Movies: فلیمەکان\n  Duration:\n    Duration: 'ماوە'\n    All Durations: 'گشت ماوەکان'\n    Short (< 4 minutes): 'کورت (< ٤ خولەک)'\n    Long (> 20 minutes): 'درێژ (> ٢٠ خولەک)'\n  # On Search Page\n    Medium (4 - 20 minutes): مامناوەند (٤ - ٢٠ خولەک)\n  Search Results: 'ئەنجامی گەڕان'\n  Fetching results. Please wait: 'هێنانی ئەنجامەکان. تکایە چاوەڕێکە'\n  Fetch more results: 'ئەنجامی زیاتر بێنە'\n# Sidebar\n  Features:\n    Location: شوێن\n    Features: تەنیاکان\n    Creative Commons: کۆمەڵگەی خەڵکی خلاقی\n    Live: ژیان\n    4K: 4K\n    HD: HD\n    Subtitles: ژێرنووس\n    VR180: VR180\n    360 Video: 360 ڤیدیۆ\n    HDR: HDR\n    3D: 3D\n  There are no more results for this search: هیچ ئەنجامێکی تر بۆ ئەم گەڕانە نییە\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'بەشداریکراوەکان'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'لیستی بەشداریکرداوەکانت لە ئێستادا بەتاڵە. بەشداری لە کەناڵێک بکە بۆ ئەوەی بیانبینیت'\n  Load More Videos: ڤیدیۆی زیاتر بهێنە\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: .ئەم پرۆفایلە ژمارەیەکی زۆری هەیە لە سەبسکریپشن. بۆ دورکەوتنەوە لە سنوور دانان (رسس) بەکاردەهێندرێت\n  Error Channels: کانالەکان بە هەڵە\n  Load More Posts: بە شێوەیەکی زیاتر پەیامەکان بار بکە\n  Empty Channels: چەنالەکانت کە تۆ بەشداریت کردووە لە ئێستادا هیچ ڤیدیۆیەک نییە.\n  Empty Posts: کانالەکانت کە ئەم ڕووداوەی تۆ ئەم شتانی نییە.\n  Disabled Automatic Fetching: تۆ پەیوەندیدانی خۆکارەکان بەرزکردنەوەی پەیوەندیدانەکان بەرزکردووتەوە. بەرزکردنەوەی پەیوەندیدانەکان بۆ بینینی ئەمانە لێرە.\n  All Subscription Tabs Hidden: هەموو تابەکانی بەشداریکردن شاراوەن. بۆ بینینی ناوەڕۆک لێرەدا، تکایە هەندێک تاب لە بەشی \"{subsection}\" لە \"{settingsSection}\" بشارەوە.\n  Subscriptions Tabs: تابەکانی بەشداریکردن\nTrending:\n  Trending: 'زۆر باسکراو'\n  Trending Tabs: تابەکانی ترێندنگ\n  Gaming: یاریکردن\nMost Popular: 'بەناوبانگترین'\nPlaylists: 'پلەیلیست'\nUser Playlists:\n  Your Playlists: 'پلیەلیستەکانت'\n  AddVideoPrompt:\n    Toast:\n      You haven't selected any playlist yet.: هێشتا هیچ لیستێکی پەخشکردنت دیاری نەکردووە.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    Select a playlist to add your N videos to: لیستێکی پەخشکردن دەسنیشان بکە بۆ زیادکردنی ڤیدیۆکەت بۆ | لیستێکی پەخشکردن دەسنیشان بکە بۆ زیادکردنی ڤیدیۆکانی {videoCount} بۆی\n    Allow Adding Duplicate Video(s): ڕێگە بدە بە زیادکردنی ڤیدیۆ(ەکان)ی دووبارە\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} ڤیدیۆکان پێشتر زیادکراون'\n    Added {count} Times: “پێشتر زیاد کراوە | زیادکرا {count} کاتەکان\n    Save: هەڵگرتن\n    N playlists selected: '{playlistCount} هەڵبژێردراوە'\n    Search in Playlists: لە پلەی لیستەکاندا بگەڕێ\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": “{videoCount}/{totalVideoCount} ڤیدیۆکان زیاد دەکرێن\n  Export Playlist: ئەم پەلیەیە بەرز بکەوە\n  SinglePlaylistView:\n    Toast:\n      This playlist is protected and cannot be removed.: ئەم لیستەی پەخشکردن پارێزراوە و ناتوانرێت لاببرێت.\n      There was a problem with removing this video: کێشەیەک هەبوو لە لابردنی ئەم ڤیدیۆیە\n      This playlist is now used for quick bookmark: ئەم لیستەی پەخشکردن ئێستا بەکاردێت بۆ نیشانەی خێرا\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ئەم لیستی پەخشکردنە ئێستا بەکاردێت بۆ نیشانەی خێرا لە جیاتی {oldPlaylistName}. کرتە لێرە بکە بۆ پاشگەزبوونەوە\n      There was an issue with updating this playlist.: کێشەیەک هەبوو لە نوێکردنەوەی ئەم لیستەی پەخشکردن.\n      Video has been removed: ڤیدیۆ لێدابەزێت\n      This playlist is already being used for quick bookmark.: ئەم لیستی پەخشکردنە پێشتر بەکاردەهێنرێت بۆ نیشانەی خێرا.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: هەندێک لە ڤیدیۆکان لە لیستی پەخشکردندا هێشتا بارنەکراون. کلیک لێرە بکە بۆ کۆپیکردن بەهەرحاڵ.\n      Playlist name cannot be empty. Please input a name.: نابێت ناوی لیستی پەخشکردن بەتاڵ بێت. تکایە ناوێک تێبنووسە.\n      This playlist has a video with a duration error: ئەم لیستەی پەخشکردنە بەلایەنی کەمەوە یەک ڤیدیۆیی تێدایە کە ماوەکەی نییە، بەشێوەیەک پۆلێن دەکرێت کە ماوەی سفری بێت.\n      Video has been removed. Click here to undo.: ڤیدیۆ لابرا. کرتە لێرە بکە بۆ پاشگەزبوونەوە.\n      This video cannot be moved up.: ئەم ڤیدیۆیە ناتوانرێت بەرز بکرێت.\n      This video cannot be moved down.: ئەم ویدیوە ناتوانرێت بەرەو خوار بەرز بکرێت.\n      Reverted to use {oldPlaylistName} for quick bookmark: گەڕێنرایەوە بۆ بەکارهێنانی {oldPlaylistName} بۆ نیشاندانی خێرا\n      Playlist {playlistName} has been deleted.: پلەی لیست {playlistName} سڕاوەتەوە.\n      \"{videoCount} video(s) have been removed\": 1 ڤیدۆ لابرا | ڤیدیۆکانی {videoCount} لابراون\n      Playlist has been updated.: …پلەی لیست نوێ کراوەتەوە.\n      There were no videos to remove.: هیچ ڤیدیۆیەک نەبوو بۆ لابردنی.\n      This playlist does not exist: ئەم پلەی لیستە بوونی نییە\n    Search for Videos: گەڕان بەدوای ڤیدیۆدا\n  CreatePlaylistPrompt:\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: لیستێکی پەخشکردن هەیە بەم ناوە. تکایە ناوێکی تر هەڵبژێرە.\n      Playlist {playlistName} has been successfully created.: لیستی پەخشکردنی {playlistName} بە سەرکەوتوویی دروستکرا.\n      There was an issue with creating the playlist.: کێشەیەک هەبوو لە دروستکردنی لیستی پەخشکردن.\n    Create: دروستکردن\n    New Playlist Name: ناوی پلەیلیستی نوێ\n  Enable Quick Bookmark With This Playlist: بەکار هێنانی بەرگەی خێرا لەگەڵ ئەم پەلییەستەیە\n  Remove Watched Videos: فیدیۆی تماشا کراوەکان لابەرەوە\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: تۆ دڵنیایت کە دەتەوێت 1 ڤیدیۆی پەراویە لە ئەم لیستە پەخشیەوە؟ ئەمە ناتوانرێت بگۆرێت. | تۆ دڵنیایت کە دەتەوێت {playlistItemCount} ڤیدیۆی پەراویە لە ئەم لیستە پەخشیەوە؟ ئەمە ناتوانرێت بگۆرێت.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: تۆ دڵنیایت کە دەتەوێت 1 ڤیدیۆی بینراوی لە ئەم لیستە پەخشیەوە؟ ئەمە ناتوانرێت بەرەوپێش بگێڕیت. | تۆ دڵنیایت کە دەتەوێت {playlistItemCount} ڤیدیۆی بینراوی لە ئەم لیستە پەخشیەوە؟ ئەمە ناتوانرێت بەرەوپێش بگێڕیت.\n  Quick Bookmark Enabled: بەکارهێنانی تێبینی تێپەڕەوەی خێرا\n  Cannot delete the quick bookmark target playlist.: ناتوانرێت لیستە پەیوەندیدانی بەرزەکانی خێرایی بێت.\n  Empty Search Message: لەو پەیجەی پلەی لیستەکاندا هیچ ڤیدیۆیەکی پەیوەندیدار بە گەڕانی تۆ نییە\n  You have no playlists. Click on the create new playlist button to create a new one.: تۆ هیچ لیستێکی پلەی نایدە. کرتە لەسەر کلیلەی \"لیستی نوێ دروست بکە\" بکە بۆ دروست کردنی یەکە نوێ.\n  The playlist has been successfully exported: پەلیستەکە بە سەرکەوتویی بەرزراوە\n  Remove Duplicate Videos: ویدیوە دەرچووانەکان لاببرە\n  This playlist currently has no videos.: ئەم پەیجەی ڤیدیۆیە کە ئیستا هیچ ڤیدیۆیەکی نییە.\n  Are you sure you want to delete this playlist? This cannot be undone: تۆ دڵنیایت ئەو پەلیستە بسڕی؟ ئەمە ناتوانرێت بەرەوپێش بەرگردرێت.\n  Search bar placeholder: گەڕان بەدوای پلەی لیستەکاندا\n  Cancel: ڕەتکردنەوە\n  Sort By:\n    NameDescending: Z-A\n    LatestUpdatedFirst: بەم دواییە نوێکراوەتەوە\n    LatestPlayedFirst: بەم دواییە یاری کراوە\n    NameAscending: A-Z\n    LatestCreatedFirst: بەم دواییە دروستکراوە\n    EarliestCreatedFirst: سەرەتاییترین دروستکراوە\n    EarliestUpdatedFirst: زووترین نوێکراوەتەوە\n    EarliestPlayedFirst: زووترین یاری\n  TotalTimePlaylist: 'کۆی گشتی کات: {duration}'\n  Playlists with Matching Videos: پلەی لیستەکان لەگەڵ ڤیدیۆی هاوتا\n  Edit Playlist Info: دەستکاریکردنی زانیاری پلەی لیست\n  Delete Playlist: سڕینەوەی پلەی لیست\n  Add to Favorites: زیادکردن بۆ {playlistName}\n  Playlist Name: ناوی پلەی لیست\n  Save Changes: گۆڕانکارییەکان پاشەکەوت بکە\n  Copy Playlist: پلەی لیست کۆپی بکە\n  Create New Playlist: دروستکردنی پلەی لیستێکی نوێ\n  Add to Playlist: زیادکردن بۆ پلەی لیست\n  Remove from Favorites: لە {playlistName} دەربهێنە\n  Playlist Description: وەسفکردنی پلەی لیست\n  Move Video Up: ڤیدیۆ بگوازەرەوە بۆ سەرەوە\n  Move Video Down: ڤیدیۆ بگوازەرەوە بۆ خوارەوە\n  Remove from Playlist: لە پلەی لیست دەربهێنە\nHistory:\n  # On History Page\n  History: 'مێژوو'\n  Watch History: 'لیستی سەیرکراو'\n  Your history list is currently empty.: 'لیستی سەیرکراوەکانت بەتاڵە.'\n  Empty Search Message: هیچ ڤیدیۆیەک لە مێژووەکەت نییە کە لەگەڵ گەڕانەکەت بگونجێت\n  Search bar placeholder: “گەڕان لە مێژوودا\n  Case Sensitive Search: گەڕانی هەستیاری گەورە و بچووک\nSettings:\n  # On Settings Page\n  Settings: 'دەستکاریکردن'\n  General Settings:\n    General Settings: 'دەستکاریکردنی گشتی'\n    Check for Updates: 'بزانە تازەکاری هاتووە'\n    Check for Latest Blog Posts: 'چێکی تازەترین بلۆگ بکە'\n    Fallback to Non-Preferred Backend on Failure: 'گەڕانەوە بۆ سیستەمە ناخوازراوەکە لەکاتی فەشەلدا'\n    Enable Search Suggestions: 'پێشنیارکردن بەکاربخە لەکاتی گەڕاندا'\n    Locale Preference: پەسەندکردنی ناوچەیی\n    Set Current Instance as Default: نمونەی ئێستا وەک گریمانەیی ڕێک بخە\n    Current instance will be randomized on startup: نمونەی ئێستا بە هەڕەمەکی دەکرێت لە دەستپێک\n    Auto Load Next Page:\n      Label: بارکردنی خۆکار پەڕەی داهاتوو\n      Tooltip: بارکردنی لاپەڕە زیادەکان و لێدوانەکان بە شێوەیەکی خۆکار.\n    External Link Handling:\n      External Link Handling: چارەسەرکردنی لینکی دەرەکی\n      Ask Before Opening Link: پرسیار بکە پێش کردنەوەی بەستەر\n    Open Deep Links In New Window: بەستەرە کراوەکان لە پەنجەرەیەکی نوێدا نێردراون بۆ FreeTube\n    No default instance has been set: هیچ حاڵەتێکی بنەڕەت دانەنراوە\n    Preferred API Backend:\n      Preferred API Backend: پشتەوەی پەسەندکراوی API\n      Invidious API: API ی ئینڤیدیۆس\n      Local API: API ناوخۆیی\n    Video View Type:\n      Video View Type: جۆری پیشاندانی ڤیدیۆ\n      Grid: تۆڕ\n      List: لیست\n    The currently set default instance is {instance}: نمونەی بنەڕەتی دانراوی ئێستاکە بریتییە لە {instance}\n    Clear Default Instance: سڕینەوەی نموونەی گریمانەیی\n    Thumbnail Preference:\n      Thumbnail Preference: هەڵبژاردنی وێنەی بچووک\n    Default Landing Page: لاپەڕەی نیشتنەوەی پێشوەختە\n    System Default: سیستەمی پێشوەختە\n  Theme Settings:\n    Hide FreeTube Header Logo: شاردنەوەی لۆگۆی سەرپەڕەی FreeTube\n    Hide Side Bar Labels: شاردنەوەی پێناسەکانی شریتی تەنیشت\n    Match Top Bar with Main Color: بەراوردی شریتی لوتکە لەگەڵ ڕەنگی سەرەکی\n    Expand Side Bar by Default: فراوانکردنی شریتی تەنیشت بە گریمانەیی\n    Disable Smooth Scrolling: لەکارخستنی ڕاکێشانی نەرم\n    Base Theme:\n      Solarized Dark: تاریکی وزەی خۆر\n      Everforest Dark Hard: ئێڤەرفۆرێست دارک هارد\n      Everforest Dark Medium: هەمیشە دارستانی تاریکی مامناوەند\n      Everforest Dark Low: ئێڤەرفۆرێست دارک نزم\n      Solarized Light: ڕووناکی وزەی خۆر\n    Main Color Theme:\n      Main Color Theme: تێمی ڕەنگی سەرەکی\n  Player Settings:\n    Screenshot:\n      Error:\n        Forbidden Characters: کاراکتەرە قەدەغەکراوەکان\n        Empty File Name: ناوی فایل بەتاڵ بکە\n      Ask Path: پرسیار بکە بۆ هەڵگرتنی فۆڵدەر\n      File Name Tooltip: دەتوانیت گۆڕاوەکانی خوارەوە بەکار بهێنیت. ٪Y ساڵ 4 ژمارە. ٪M مانگ 2 ژمارە. ٪D رۆژ 2 ژمارە. ٪H کاتژمێر 2 ژمارە. ٪N خولەک 2 ژمارە. ٪s دووەم 2 ژمارە. ٪T میلیچرکە 3 ژمارە. ٪s ڤیدیۆی دووەم. ٪t ڤیدیۆ میلی چرکە 3 ژمارە. ٪i ناسنامەی ڤیدیۆ.\n      Folder Label: فۆڵدەری گرتە-شاشە\n    Autoplay Videos: دەستپێکردنی ڤیدیۆکان بە شێوەیەکی خۆکار\n    Turn on Subtitles by Default: ژێرنووسەکان بەتوانا بکە بە شێوەی گریمانەیی\n    Play Next Video: پەخش کردنی خۆکاری ڤیدیۆ پێشنیارکراوەکان\n    Autoplay Playlists: پەخش کردنی خۆکاری ڤیدیۆکانی لیستی پەخشکردن\n    Max Video Playback Rate: زۆرترین ڕێژەی پەخش کردنەوەی ڤیدیۆ\n    Default Playback Rate: ڕێژەی پێشینەی پەخش کردنەوە\n    Video Playback Rate Interval: ماوەی رێژەی پەخش کردنەوەی ڤیدیۆ\n  Data Settings:\n    Unable to read file: 'ناتواندرێت فایلەکە بخوێندرێتەوە'\n    Unable to write file: 'ناتواندریت فایلەکە بنوسرێت'\n    Unknown data key: 'کلیلی داتای نەناسراو'\n    How do I import my subscriptions?: 'چۆن بەشدارییەکانم داخڵ بکەم؟'\n    Manage Subscriptions: بەشدارییەکانت رێکبخە\n    Playlist insufficient data: داتای تەواو نیە بۆ لیستی پەخشکردنی \"{playlist}\"، پەڕاندنی ئایتم\n    Subscriptions have been successfully exported: بەشداربووەکان بە سەرکەوتوویی هەناردە کران\n    All playlists has been successfully imported: هەموو لیستەکانی پەخشکردن بە سەرکەوتوویی هاوردە کران\n    Export FreeTube: هەناردەکردنی FreeTube\n    All playlists has been successfully exported: هەموو لیستەکانی پەخشکردن بە سەرکەوتوویی هەناردە کران\n    History object has insufficient data, skipping item: ئۆبجێکتی مێژوو داتای تەواو ناکات، بڕگە دەپەڕێنێت\n    All watched history has been successfully imported: هەموو مێژووی چاودێریکراو بە سەرکەوتوویی هاوردە کرا\n    All watched history has been successfully exported: سەرجەم مێژووی چاودێری کراو بە سەرکەوتوویی هەناردە کرا\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: کێشە لە وەرگرتنی زانیاری نێتۆرک. ئایە پرۆکسێکەت بە رێکوپێکی رێکخراوە؟\n    City: شار\n    Region: ناوچە\n    Country: وڵات\n    Ip: ئەدرێسی ئەلکترۆنی\n    Your Info: زانیاریت\n    Test Proxy: تاقیکردنەوەی پرۆکسی\n    Clicking on Test Proxy will send a request to: کلیکردن لەسەر تێستی پرۆکسی داواکارییەک دەنێریت بۆ\n    Proxy Port Number: ژمارەی پۆرتی پرۆکسی\n    Proxy Host: پرۆکسی بڵاوکەر\n    Proxy Protocol: پرۆتۆکۆڵی پڕۆکسی\n    Enable Tor / Proxy: تۆر/پرۆکسی بەکاربخە\n    Proxy Settings: گۆڕانکاری پرۆکسی\n    Proxy Warning: FreeTube پرۆکسی ناوەکی نییە بەڵام دەتوانێت بە بریکارێکی دەرەکی گرێ بدات، وەک ئەوەی لەسەر ئامێرەکەت کار دەکات وەک Tor یان پرۆکسی دەرەکی وەک پرۆکسی SOCKS5 کە لەلایەن هەندێک VPN دابینکراوە. ئەگەر چالاک بوو، دڵنیابە لەوەی کە بریکارەکەت بە دروستی شێوەبەند کراوە، ئەگەرنا FreeTube ناتوانێت هیچ داتایەک بهێنێت.\n  The app needs to restart for changes to take effect. Restart and apply change?: ئەم ئەپڵیکەیشنە دەبێت دووبارە بکرێتەوە بۆ ئەوەی گۆڕانکارێکان بگانە ئەنجام. دووبارە کردنەوە و چەسپکردنی گۆڕانکارێکان؟\n  Return to Settings Menu: گەڕانەوە بۆ پێرستی ڕێکبەندەکان\n  Distraction Free Settings:\n    Hide Channels Invalid: ناسنامەی کەناڵ دابینکراو نادروستە\n    Hide Active Subscriptions: شاردنەوەی بەشدارە چالاکەکان\n    Hide Video Description: شاردنەوەی وەسفی ڤیدیۆ\n    Display Titles Without Excessive Capitalisation: ناونیشانەکان پێشانبدە بەبێ پیتی گەورە و خاڵبەندی لە ڕادەبەدەر\n    Hide Sharing Actions: شاردنەوەی چالاکیەکانی هاوبەش کردن\n    Hide Profile Pictures in Comments: شاردنەوەی وێنەی پرۆفایل لە سەرەنجەکان\n    Hide Channels: شاردنەوەی ڤیدیۆکان لە کەناڵەکان\n    Hide Channel Subscribers: شاردنەوەی بەشداربووانی کەناڵ\n    Hide Video Likes And Dislikes: شاردنەوەی حەز و نەخوازراوەکانی ڤیدیۆ\n    Hide Channels Disabled Message: هەندێک لە کەناڵەکان بە بەکارهێنانی ناسنامە بلۆک کراون و چارەسەر نەکراون. تایبەتمەندی بلۆک کراوە لە کاتێکدا ئەو ناسنامانە نوێ دەکرێنەوە\n    Hide Channels API Error: هەڵە لە گەڕاندنەوەی بەکارهێنەر لەگەڵ ناسنامەی دابینکراو. تکایە دووبارە بپشکنە ئەگەر ناسنامەکە دروستە.\n  External Player Settings:\n    Ignore Default Arguments: ئارگیومێنتەکانی گریمانەیی فەرامۆش بکە\n    Ignore Unsupported Action Warnings: ئاگاداریەکانی چالاکی پشتیوانی نەکراو فەرامۆش بکە\n    Custom External Player Executable: جێبەجێکردنی لێدەری دەرەکی ئاسایی\n    Custom External Player Arguments: ئارگیومێنتەکانی لێدەری دەرەکی ئاسایی\n  Privacy Settings:\n    Remember History: مێژووی چاودێریکردن لەبیربێت\n    Are you sure you want to remove all your playlists?: ئایا تۆ پشتڕاستیت کە دەتەوێت هەموو لیستەکانی پەخشکردنت لابدەیت؟\n    Save Watched Progress: پێشکەوتنی چاودێرکراو بپارێزە\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ئایا تۆ پشتڕاستیت کە دەتەوێت هەموو بەشداربوون و پرۆفایلەکان لابدەیت؟ ئەمە ناتوانرێت پاشگەز بکرێتەوە.\n    Are you sure you want to remove your entire watch history?: ئایا تۆ پشتڕاستیت کە دەتەوێت تەواوی مێژووی سەیرکردنت بسڕیتەوە؟\n    Remember Search History: بیرکەوتنەوە مێژووی گەڕان\n    Search history and cache have been cleared: مێژووی گەڕان و حەشارگە خاوێن کراونەتەوە\n    Clear Search History and Cache: خاوێنکردنەوەی مێژووی گەڕان و حەشارگە\n    Save Watched Videos With Last Viewed Playlist: پاشەکەوت کردنی ڤیدیۆکانی سەیرکراو لەگەڵ لیستی پەخشکردنی دوایین بینراو\n    Watched Progress Saving Mode:\n      Tooltip: خودکار = پاشەکەوت کردن لە هەموو دەرچوونێکی لاپەڕەی ڤیدیۆ، کاتێک ڤیدیۆ کۆتایی هات و هەڵە ڕوویدا (بۆ نمونە ratelimited و دانیشتنی سەیرکردن بەسەرچووە). نیمچە خۆکار = وەک خۆکار جگە لە دەرچوون لە پەڕەی ڤیدیۆ و دەتوانێت پێشکەوتن بە دەستی پاشەکەوت بکات لە رێگەی دوگمەیەک پێی دەوترێت پاشەکەوت کردنی پێشکەوتنی سەیرکراو، دەکەوێتە ژێر لێدەری ڤیدیۆ.\n    Are you sure you want to clear out your search history and cache?: ئایا تۆ پشتڕاستیت کە دەتەوێت مێژووی گەڕان و حەشارگە خاوێن بکەیتەوە؟\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: ئاگادارکردنەوە کاتێک پارچەی سپۆنسەر فەرامۆش کرا\n  Password Settings:\n    Set Password To Prevent Access: نهێنوشەیەک دابنێ بۆ ڕێگریکردن لە دەستگەیشتن بە ڕێکبەندەکان\n  Subscription Settings:\n    'Limit the number of videos displayed for each channel': سنوردارکردنی ژمارەی ڤیدیۆکان بۆ هەر کەناڵێک\n  Sort Settings Sections (A-Z): ڕێکخستنەکانی ڕیزبەندی بەشەکان (A-Z)\nAbout:\n  #On About page\n  About: 'دەربارە'\n  #& About\n  Donate: دۆنەیشن\n  these people and projects: ئەم کەسانە و پڕۆژانە\n  Translate: تەرجومە\n  room rules: یاسای ژوورەکە\n  Chat on Matrix: Matrix موناقەشە کە لە\n  Mastodon: ماستۆدۆن\n  Email: نامەی ئەلکترۆنی\n  Blog: بلۆگ\n  Website: وێبسایت\n  Please check for duplicates before posting: تکایە چێک بکە بۆ دووبارە پێش پۆستکردن\n  GitHub issues: GitHub کێشاکانی\n  Report a problem: کێشەیەک ڕاگەیەنە\n  FAQ: پرسیارانەی زۆر دەکرێن\n  FreeTube Wiki: ویکی فریتیوب\n  Help: یارمەتی\n  GitHub releases: GitHub دەرچونەکانی\n  Downloads / Changelog: دابەزاندنەکان / لیستی گۆڕانکاری\n  Source code: سەرچاوەی کۆد\n  Beta: تاقیکارییە\nProfile:\n  Profile Select: 'پرۆفایلەکە دیاریکە'\n  All Channels: 'هەموو کەناڵەکان'\n  Profile Manager: 'ڕێخەری پڕۆفایل'\n  Create New Profile: 'پڕۆفایلێکی نوێ دروستبکە'\n  Edit Profile: 'پڕۆفایل دەستکاری بکە'\n  Color Picker: 'ڕەنگ هەڵبژاردەر'\n  Custom Color: 'رەنگی تایبەت'\n  Profile Preview: 'پڕۆفایل بیشاندە'\n  Create Profile: 'پرۆفایل دروستبکە'\n  Update Profile: 'پرۆفایل تازەبکەرەوە'\n  Make Default Profile: 'بیکە بە پڕۆفایلی ئەسایی'\n  Delete Profile: 'پڕۆفایلەکە بسڕەوە'\n  Are you sure you want to delete this profile?: 'ئایە دڵنیایت کە دەتەوێت ئەم پڕۆفایلە بسڕیتەوە؟'\n  All subscriptions will also be deleted.: 'هەموو بەشداریکردنەکانیش بە هامەنشێوە دەسڕێنەوە.'\n  Your profile name cannot be empty: 'ناوی پڕۆفایلەکەت نابێت بەتاڵبێت'\n  Profile has been created: 'پڕۆفایلەکە دروستکرا'\n  Profile has been updated: 'پرۆفایلەکە تازەکرایەوە'\n  Your default profile has been set to {profile}: 'پرۆفایلە ئاساییەکەت دانراوە بۆ {profile}'\n  Removed {profile} from your profiles: 'سڕاوەتەوە لە پرۆفایلەکانت {profile}'\n  Toggle Profile List: گۆڕینی رەوشی لیستی پرۆفایل\n  Your default profile has been changed to your primary profile: پرۆفایلە گریمانەیەکەت گۆڕدرا بۆ پرۆفایلی سەرەکیت\n  No channel(s) have been selected: هیچ کەناڵێکی دیاری نەکراوە\n  Edit Profile Name: بڵاوکردنەوەی ناوی پرۆفایل\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ئەمە هەژماری سەرەکی تۆیە. ئایا تۆ پشتڕاستیت کە دەتەوێت کەناڵە دەسنیشانکراوەکان بسڕیتەوە؟ هەمان کەناڵەکان لە هەر پرۆفایلێکدا کە تێیدا دەدۆزرێنەوە دەسڕێنەوە.\n  '{profile} is now the active profile': '{profile} ئێستا پرۆفایلی چالاکە'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ئایا تۆ پشتڕاستیت کە دەتەوێت کەناڵە دەسنیشانکراوەکان بسڕیتەوە؟ ئەمە کەناڵەکە لە هیچ پرۆفایلێکی تر ناسڕێتەوە.\n  Select All: دیاریکردنی هەمووی\nChannel:\n  Playlists:\n    This channel does not currently have any playlists: ئەم کەناڵە لە ئێستادا هیچ لیستێکی پەخشکردنی نییە\n  Shorts:\n    This channel does not currently have any shorts: ئه م که ناڵه له ئێستادا هیچ کورته فیلمی نییه و\n  This channel does not allow searching: ئەم کەناڵە ڕێگە بە گەڕان نادات\n  Added channel to your subscriptions: کەناڵێکی زیادکراو بۆ بەشداربوونەکانت\n  Removed subscription from {count} other channel(s): ئابوونە لە کەناڵەکانی تر لابرایەوە\n  Your search results have returned 0 results: ئەنجامەکانی بەدواگەڕانەکەت 0 ئەنجامیان گەڕاندەوە\n  Channel has been removed from your subscriptions: کەناڵەکە لە بەشداربوونەکانت لابراوە\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ئەم کەناڵە تەمەنی سنووردارە و لە ئێستادا ناتوانرێت لە FreeTube ببینرێت.\n  Videos:\n    This channel does not currently have any videos: ئەم کەناڵە لە ئێستادا هیچ ڤیدیۆیەکی نییە\n  Live:\n    This channel does not currently have any live streams: ئەم کەناڵە لە ئێستادا هیچ پەخشێکی ڕاستەوخۆی نییە\nNew Window: پەنجەرەی نوێ\nGo to page: بڕۆ بۆ {page}\nPreferences: هەڵبژاردەکان\nAre you sure you want to open this link?: دڵنیایت دەتەوێت ئەم بەستەرە بکەیتەوە؟\nOpen New Window: کردنەوەی پەنجەرەیەکی نوێ\nChannels:\n  Empty: لیست چەنالی تۆ ئێستا خالیە.\n  Search bar placeholder: گەڕان لە کەناڵەکاندا\n  Unsubscribe Prompt: ئایا دڵنیای کە دەتەوێت بەشداریکردن لە \"{channelName}\" هەڵبوەشێنیتەوە؟\n  Channels: کەناڵەکان\n  Title: لیستی کەناڵەکان\n  Count: '{number} کەناڵ(ەکان) دۆزرایەوە.'\nRight-click or hold to see history: کلیک لە ڕاست یان هەڵبژاردن بەدوورەوە بۆ بینینی مێژووی\nSearch Listing:\n  Label:\n    New: نوێ\n    Subtitles: زیرنویسەکان\n    Closed Captions: نیشانی پەیوەندیدا بەرزراوەکان\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    4K: 4K\n    3D: 3D\nClose Banner: بەندەرەکە بند بکە\nSearch Bar:\n  Clear Input: وەرگێرانی پەیوەندیدار\n  Remove: بەسەرچوون\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: زامنی ئامرازەکانی گەشەپێدەر\n  Zoom In: زووم کردنە ناوەوە\n  Zoom Out: زووم کردنە دەرەوە\n  Fullscreen: شاشەکەت پرکەرەوە\nFeed:\n  Feed Last Updated: '{feedName} فید دوایین نوێکردنەوە: {date}'\n  Refresh Feed: نوێکردنەوە {subscriptionName}\nMore: زیاتر\nSearch character limit: پرسیاری گەڕان لە سەرووی سنووری کاراکتەری {searchCharacterLimit} دایە\n"
  },
  {
    "path": "static/locales/la.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Latina'\n\n# Webkit Menu Bar\nFile: 'tabula'\nQuit: 'Exi'\nEdit: 'Muta'\nUndo: 'Tolle'\nRedo: 'Refac'\nCut: 'Deseca'\nCopy: 'Effinge'\nPaste: 'Agglutina'\nDelete: 'Dele'\nSelect all: 'Omnia selige'\nToggle Developer Tools: 'Mutatio Constitutor Instrumenta'\nActual size: 'Vera magnitudine'\nZoom in: 'Visum propius'\nZoom out: 'Visi repostus'\nToggle fullscreen: 'Totus mutatur ostentationem'\nWindow: 'fenestram'\nMinimize: 'Redigo'\nClose: 'Claude'\nBack: 'Redeo'\nForward: 'Promoveo'\n\nVersion {versionNumber} is now available!  Click for more details: 'Editio {versionNumber}\n  nunc praesto! Tactus pro magis singula res'\nDownload From Site: 'Adepto ex situ'\nA new blog is now available, {blogTitle}. Click to view more: 'Novum scripturam creata\n  est, {blogTitle}. Tangere hic pro magis notitia'\n\nGlobal:\n  Sort By: 'Disponere Per'\n\n# Search Bar\nSearch / Go to URL: 'Requiro / Adeo URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Requiro Filtra'\n  Sort By:\n    Most Relevant: 'Maxime Pertinentes'\n    Rating: 'Transientes'\n    Upload Date: 'Transporto Dies'\n    View Count: 'Iteratio visibus visibile'\n  Time:\n    Time: 'Tempus'\n    Any Time: 'Umquam'\n    Last Hour: 'Intra Horam'\n    Today: 'Hodie'\n    This Week: 'Hoc Septimana'\n    This Month: 'Haec Mensis'\n    This Year: 'Hoc Anno'\n  Type:\n    Type: 'Genus'\n    All Types: 'Omnes'\n    Videos: 'Movens Imaginibus'\n    Channels: 'Canalis'\n    #& Playlists\n  Duration:\n    Duration: 'Diuturnitas'\n    All Durations: 'Omnes Durationes'\n    Short (< 4 minutes): 'Brevis (< 4 minutes)'\n    Long (> 20 minutes): 'Longus (> 20 minutes)'\n  # On Search Page\n  Search Results: 'Quaerere Eventus'\n  Fetching results. Please wait: 'Lignatio eventus. Placet expectare'\n  Fetch more results: 'Adepto plus eventus'\n# Sidebar\n  There are no more results for this search: Adepto plus eventus non possunt\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subscriptio'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Subscription\n    vestri album sit vacua. Incipe addere subscriptions videre hic.'\n  Load More Videos: Voce plus Movens Imaginibus\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Haec\n    profile copia subscriptioni habet. Impono RSS ut impedio restrictionis per celeritatis\nTrending:\n  Trending: 'Inclinant'\nMost Popular: 'Maxime Popular'\nPlaylists: 'Album ludere'\nUser Playlists:\n  Your Playlists: 'Album Ludere Vestra'\nHistory:\n  # On History Page\n  History: 'Historiam'\n  Watch History: 'Specto Historia'\n  Your history list is currently empty.: 'Tua historia album sit amet vacua.'\nSettings:\n  # On Settings Page\n  Settings: 'Optiones'\n  General Settings:\n    General Settings: 'Generalis Occasus'\n    Check for Updates: 'Reprehendo pro Updates'\n    Check for Latest Blog Posts: 'Reprehendo pro recentissimus diurnus ingressum'\n    Fallback to Non-Preferred Backend on Failure: 'Revertere ad secundarium ratio\n      cum defectum'\n    Enable Search Suggestions: 'Permitte Quaerere Conmendatio'\n    Default Landing Page: 'Usitatus Portum Pagina'\n    Locale Preference: 'Locus Praedilectionis'\n    Preferred API Backend:\n      Preferred API Backend: 'Praedilectionis API Ratio'\n      Local API: 'Locus API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Video Modus Visio'\n      Grid: 'Reticulum'\n      List: 'Album'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Parva Imago Occasus'\n      Default: 'Iusto'\n      Beginning: 'Initium'\n      Middle: 'Medium'\n      End: 'Finis'\n    Region for Trending: 'ad usum inclinanatus regionem'\n        #! List countries\n  Theme Settings:\n    Theme Settings: 'Occasus Lemma'\n    Match Top Bar with Main Color: 'par cacumen cum pelagus color'\n    Base Theme:\n      Base Theme: 'Basis Lemma'\n      Black: 'Lividus'\n      Dark: 'Niger'\n      Light: 'Illustris'\n      Dracula: 'Dracula'\n    Main Color Theme:\n      Main Color Theme: 'Pelagus Color Lemma'\n      Red: 'Ruber'\n      Pink: 'Roseus'\n      Purple: 'Purpura'\n      Deep Purple: 'Purpura Tenebris'\n      Indigo: 'Indicus'\n      Blue: 'Caeruleum'\n      Light Blue: 'Caeruleum'\n      Cyan: 'Galben'\n      Teal: 'Querquedulae'\n      Green: 'Prasinus'\n      Light Green: 'Levis Prasinus'\n      Dracula Cyan: 'Dracula Galben'\n      Dracula Green: 'Dracula Prasinus'\n      Dracula Orange: 'Dracula Orange'\n      Dracula Pink: 'Dracula Roseus'\n      Dracula Purple: 'Dracula Purpura'\n      Dracula Red: 'Dracula Ruber'\n      Dracula Yellow: 'Dracula Flavum'\n  Player Settings: {}\nChannel:\n  Videos: {}\n  Playlists: {}\nVideo: {}\nNo: 'nullum'\nMore: plus\nOpen New Window: aperiere fenestram novum\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Mutatio Constitutor Instrumenta\n  Zoom Out: Visi repostus\n  Zoom In: Visum propius\n  Fullscreen: Totus mutatur ostentationem\nProfile:\n  Select All: Omnia selige\n"
  },
  {
    "path": "static/locales/lt.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'lietuvių'\n\n# Webkit Menu Bar\nFile: 'Failas'\nQuit: 'Išeiti'\nEdit: 'Redaguoti'\nUndo: 'Anuliuoti'\nRedo: 'Gražinti'\nCut: 'Iškirpti'\nCopy: 'Kopijuoti'\nPaste: 'Įklijuoti'\nDelete: 'Ištrinti'\nSelect all: 'Pažymėti viską'\nToggle Developer Tools: 'Įjungti kūrėjo įrankius'\nActual size: 'Tikrasis dydis'\nZoom in: 'Pritraukti'\nZoom out: 'Atitolinti'\nToggle fullscreen: 'Viso ekrano rėžimas'\nWindow: 'Lango rėžimas'\nMinimize: 'Nuleisti'\nClose: 'Uždaryti'\nBack: 'Atgal'\nForward: 'Pirmyn'\nOpen New Window: 'Atidaryti naują langą'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vaizdo įrašai'\n\n  Live: Tiesiogiai\n  Shorts: Šortai\n  Posts: Įrašai\n  Sort By: 'Rūšiuoti pagal'\n  Counts:\n    Subscriber Count: 1 prenumeruoti | {count} prenumeratorių\n    Channel Count: 1 kanalas | {count} kanalai\n    Video Count: 1 vaizdo įrašas | {count} vaizdo įrašai\n    View Count: 1 peržiūrėti | {count} peržiūrų\n    Watching Count: 1 žiūri | {count} žiūri\n    Like Count: 1 patinka | {count} patiko\n    Comment Count: 1 komentaras | {count} komentarai\nVersion {versionNumber} is now available!  Click for more details: 'Versija {versionNumber} jau prieinama!  Spustelėkite, jei norite gauti daugiau informacijos'\nDownload From Site: 'Atsisiųsti iš svetainės'\nA new blog is now available, {blogTitle}. Click to view more: 'Naujas įrašas tinklaraštyje, {blogTitle}. Spustelėkite norėdami pamatyti daugiau'\n\n# Search Bar\nSearch / Go to URL: 'Paieška / Eiti į URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Paieškos filtrai'\n  Sort By:\n    Most Relevant: 'Aktualiausi'\n    Rating: 'Reitingas'\n    Upload Date: 'Įkėlimo data'\n    View Count: 'Peržiūrų skaičius'\n  Time:\n    Time: 'Laikas'\n    Any Time: 'Bet kuris laikas'\n    Last Hour: 'Paskutinė valanda'\n    Today: 'Šiandien'\n    This Week: 'Šią savaitę'\n    This Month: 'Šį mėnesį'\n    This Year: 'Šiais metais'\n  Type:\n    Type: 'Tipas'\n    All Types: 'Visi tipai'\n    Videos: 'Vaizdo įrašai'\n    Channels: 'Kanalai'\n    #& Playlists\n    Movies: Filmai\n  Duration:\n    Duration: 'Trukmė'\n    All Durations: 'Visos trukmės'\n    Short (< 4 minutes): 'Trumpas (< 4 minutės)'\n    Long (> 20 minutes): 'Ilgas (> 20 minutės)'\n  # On Search Page\n    Medium (4 - 20 minutes): Vidutinis (4 - 20 minučių)\n  Search Results: 'Paieškos rezultatai'\n  Fetching results. Please wait: 'Rezultatai kraunami. Prašome luktelėti'\n  Fetch more results: 'Įkelti daugiau rezultatų'\n  There are no more results for this search: 'Daugiau nėra rezultatų pagal šią paiešką'\n# Sidebar\n  Clear Filters: Išvalykite filtrus\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Prenumeratos'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Šiame profilyje yra daug prenumeratų.   Vengiant ribojimų RSS bus naudojamas priverstinai'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Jūsų prenumeratų sąrašas šiuo metu tuščias. Pridėkite prenumeratas, kad jas pamatytumėte čia.'\n  Load More Videos: 'Įkelti daugiau vaizdo įrašų'\n  Error Channels: Kanalai su klaidomis\n  Disabled Automatic Fetching: Išjungėte automatinį prenumeratų gavimą. Atnaujinkite prenumeratas, kad jas matytumėte čia.\n  Empty Channels: Šiuo metu jūsų prenumeruojamuose kanaluose nėra jokių vaizdo įrašų.\n  Empty Posts: Jūsų prenumeruojami kanalai šiuo metu neturi jokių įrašų.\nMore: 'Daugiau'\nTrending:\n  Trending: 'Dabar populiaru'\n  Trending Tabs: „Dabar populiaru“ kortelės\n  Gaming: Žaidimai\n  Sports: Sportas\nMost Popular: 'Populiariausia'\nPlaylists: 'Grojaraščiai'\nUser Playlists:\n  Your Playlists: 'Tavo grojaraščiai'\n  Empty Search Message: Šiame grojaraštyje nėra vaizdo įrašų, kurie atitiktų jūsų paiešką\n  Search bar placeholder: Ieškoti grojaraštyje\nHistory:\n  # On History Page\n  History: 'Istorija'\n  Watch History: 'Žiūrėjimo istorija'\n  Your history list is currently empty.: 'Tavo žiūrėjimo istorija kol kas tuščia.'\n  Empty Search Message: Istorijoje nėra vaizdo įrašų, atitinkančių jūsų paiešką\n  Search bar placeholder: Ieškoti istorijoje\nSettings:\n  # On Settings Page\n  Settings: 'Nustatymai'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Kad pakeitimai įsigaliotų, programą reikia paleisti iš naujo. Paleisti iš naujo ir pritaikyti pakeitimus?'\n  General Settings:\n    General Settings: 'Bendrieji nustatymai'\n    Check for Updates: 'Tikrinti ar yra atnaujinimų'\n    Check for Latest Blog Posts: 'Tikrinti ar yra naujų tinklaraščio įrašų'\n    Fallback to Non-Preferred Backend on Failure: 'Nepavykus rinktis alternatyvią posistemę'\n    Enable Search Suggestions: 'Įjungti paieškos pasiūlymus'\n    Default Landing Page: 'Numatytasis pradinis puslapis'\n    Locale Preference: 'Kalbos pasirinkimas'\n    System Default: 'Sistemos numatytieji'\n    Preferred API Backend:\n      Preferred API Backend: 'Pageidaujama API posistemė'\n      Local API: 'Vietinis API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Vaizdo įrašų atvaizdavimo tipas'\n      Grid: 'Tinklelis'\n      List: 'Sąrašas'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatiūrų pasirinkimas'\n      Default: 'Numatytasis'\n      Beginning: 'Vaizdo įrašo pradžia'\n      Middle: 'Vaizdo įrašo vidurys'\n      End: 'Vaizdo įrašo pabaiga'\n    View all Invidious instance information: 'Žiūrėti visą Invidious perdavimo šaltinio informaciją'\n    Region for Trending: '„Dabar populiaru“ regionas'\n        #! List countries\n    Clear Default Instance: Išvalyti numatytąjį perdavimo šaltinį\n    Current Invidious Instance: Esamas Invidious perdavimo šaltinis\n    Set Current Instance as Default: Nustatyti esamą perdavimo šaltinį kaip numatytąjį\n    Current instance will be randomized on startup: Esamas perdavimo šaltinis bus atsitiktinai parinktas paleidimo metu\n    No default instance has been set: Nenustatytas joks numatytasis perdavimo šaltinis\n    The currently set default instance is {instance}: Šiuo metu nustatytas perdavimo šaltinis yra {instance}\n    External Link Handling:\n      No Action: Jokio veiksmo\n      Ask Before Opening Link: Klausti prieš atidarant nuorodą\n      Open Link: Atidaryti nuorodą\n      External Link Handling: Išorinių nuorodų tvarkymas\n  Theme Settings:\n    Theme Settings: 'Temos nustatymai'\n    Match Top Bar with Main Color: 'Derinti viršutinė juosta prie pagrindinės spalvos'\n    Expand Side Bar by Default: 'Išskleisti šoninę juostą pagal numatytuosius nustatymus'\n    Disable Smooth Scrolling: 'Išjungti sklandų slinkimą'\n    UI Scale: 'Naudotojo sąsajos skalė'\n    Base Theme:\n      Base Theme: 'Bazinė tema'\n      Black: 'Juoda'\n      Dark: 'Tamsi'\n      Light: 'Šviesi'\n      Dracula: 'Drakula'\n      Catppuccin Mocha: Catppuccino Mocha\n      System Default: Sistemos numatytoji\n    Main Color Theme:\n      Main Color Theme: 'Pagrindinė temos spalva'\n      Red: 'Raudona'\n      Pink: 'Rožinė'\n      Purple: 'Violetinė'\n      Deep Purple: 'Tamsiai violetinė'\n      Indigo: 'Indigo'\n      Blue: 'Mėlyna'\n      Light Blue: 'Žydra'\n      Cyan: 'Žalsvai mėlyna'\n      Teal: 'Šviesiai smaragdinė'\n      Green: 'Žalia'\n      Light Green: 'Salotinė'\n      Lime: 'Kalkių'\n      Yellow: 'Geltona'\n      Amber: 'Gintaro'\n      Orange: 'Oranžinė'\n      Deep Orange: 'Ryškiai oranžinė'\n      Dracula Cyan: 'Drakula Žalsvai mėlyna'\n      Dracula Green: 'Drakula Žalia'\n      Dracula Orange: 'Drakula Oranžinė'\n      Dracula Pink: 'Drakula Rožinė'\n      Dracula Purple: 'Drakula Violetinė'\n      Dracula Red: 'Drakula Raudona'\n      Dracula Yellow: 'Drakula Geltona'\n      Catppuccin Mocha Rosewater: Catppuccino Mocha Rožių vanduo\n      Catppuccin Mocha Flamingo: Catppuccino Mocha Flamingo\n      Catppuccin Mocha Pink: Catppuccino Mocha rožinė\n      Catppuccin Mocha Mauve: Catppuccino Mocha Mauve\n      Catppuccin Mocha Red: Catppuccino Mocha raudona\n      Catppuccin Mocha Green: Catppuccino Mocha Žalia\n      Catppuccin Mocha Yellow: Catppuccino Mocha Geltona\n      Catppuccin Mocha Peach: Catppuccino Mocha Persiko\n      Catppuccin Mocha Sapphire: Catppuccino Mocha Safyro\n      Catppuccin Mocha Teal: Catppuccino Mocha Žalsvai-mėlyna\n      Catppuccin Mocha Blue: Catppuccino Mocha Mėlyna\n      Catppuccin Mocha Lavender: Catppuccino Mocha Levandos\n      Catppuccin Mocha Sky: Catppuccino Mocha Dangaus\n      Catppuccin Mocha Maroon: Catppuccino Mocha Kaštoninė\n    Secondary Color Theme: 'Papildoma temos spalva'\n        #* Main Color Theme\n    Hide Side Bar Labels: Slėpti šoninės juostos etiketes\n    Hide FreeTube Header Logo: Slėpti FreeTube logotipą antraštėje\n  Player Settings:\n    Player Settings: 'Grotuvo nustatymai'\n    Play Next Video: 'Leisti sekanti vaizdo įrašą'\n    Turn on Subtitles by Default: 'Įjungti subtitrus automatiškai'\n    Autoplay Videos: 'Automatinis vaizdo įrašų paleidimas'\n    Proxy Videos Through Invidious: 'Naudoti įgaliotąjį serverį vaizdo įrašams per Invidious'\n    Autoplay Playlists: 'Automatinis grojaraščių paleidimas'\n    Enable Theatre Mode by Default: 'Įjungti teatro rėžimą automatiškai'\n    Scroll Volume Over Video Player: 'Slinkti per vaizdo grotuvą, kad pakeisti garsumą'\n    Display Play Button In Video Player: 'Rodyti grojimo mygtuką vaizdo grotuve'\n    Next Video Interval: 'Sekantis vaizdo įrašas bus paleistas po'\n    Default Volume: 'Numatytasis garsumas'\n    Default Playback Rate: 'Numatytasis atkūrimo greitis'\n    Default Video Format:\n      Default Video Format: 'Numatytasis vaizdo įrašo formatas'\n      Dash Formats: 'DASH formatai'\n      Legacy Formats: 'Senieji formatai'\n      Audio Formats: 'Audio formatai'\n    Default Quality:\n      Default Quality: 'Numatytoji kokybė'\n      Auto: 'Automatinė'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: Greito persukimo pirmyn / atgal intervalas\n    Scroll Playback Rate Over Video Player: Slinkties atkūrimo dažnis vaizdo įrašų grotuve\n    Screenshot:\n      Enable: Įgalinti ekrano kopijas\n      Format Label: Ekrano kopijos formatas\n      Ask Path: Prašyti aplanko kuriame išsaugoti\n      Folder Label: Ekrano kopijų aplankas\n      Folder Button: Pasirinkite aplanką\n      File Name Label: Failo pavadinimo šablonas\n      Quality Label: Ekrano kopijos kokybė\n      File Name Tooltip: Galite naudoti toliau nurodytus kintamuosius. %Y Metai 4 skaitmenys. %M Mėnuo 2 skaitmenys. %D Diena 2 skaitmenys. %H Valanda 2 skaitmenys. %N Minutė 2 skaitmenys. %S Sekundė 2 skaitmenys. %T Milisekundė 3 skaitmenys. %s Vaizdo sekundė. %t Vaizdo milisekundė 3 skaitmenys. %i Vaizdo įrašo ID.\n      Error:\n        Forbidden Characters: Draudžiami simboliai\n        Empty File Name: Tuščias failo pavadinimas\n    Video Playback Rate Interval: Vaizdo įrašų atkūrimo dažnio intervalas\n    Max Video Playback Rate: Maksimalus vaizdo įrašų atkūrimo dažnis\n    Enter Fullscreen on Display Rotate: Viso ekrano režimas pasukus ekraną\n    Skip by Scrolling Over Video Player: Praleiskite slinkdami per vaizdo grotuvą\n  External Player Settings:\n    External Player Settings: 'Išorinio grotuvo nustatymai'\n    External Player: 'Išorinis grotuvas'\n    Ignore Unsupported Action Warnings: 'Nepaisyti „nepalaikomas veiksmas” įspėjimų'\n    Custom External Player Executable: 'Pasirinktinis išorinio grotuvo vykdymas'\n    Custom External Player Arguments: 'Pasirinktiniai išorinio grotuvo argumentai'\n    Players:\n      None:\n        Name: Nėra\n  Privacy Settings:\n    Privacy Settings: 'Privatumo nustatymai'\n    Remember History: 'Įsiminti istoriją'\n    Save Watched Progress: 'Išsaugoti peržiūros progresą'\n    Clear Search Cache: 'Išvalyti paieškos talpyklą'\n    Are you sure you want to clear out your search cache?: 'Ar tikrai norite išvalyti paieškos talpyklą?'\n    Search cache has been cleared: 'Paieškos talpykla išvalyta'\n    Remove Watch History: 'Pašalinti žiūrėjimo istoriją'\n    Are you sure you want to remove your entire watch history?: 'Ar tikrai norite pašalinti visą žiūrėjimo istoriją?'\n    Watch history has been cleared: 'Žiūrėjimo istorija buvo išvalyta'\n    Remove All Subscriptions / Profiles: 'Pašalinti visas prenumeratas / profilius'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Ar tikrai norite pašalinti visas prenumeratas ir profilius? To nebus galima atšaukti.'\n    Save Watched Videos With Last Viewed Playlist: Išsaugokite Žiūrėtus Vaizdo Įrašus Naudodami Paskutinį Žiūrėtą Grojaraštį\n  Subscription Settings:\n    Subscription Settings: 'Prenumeratų nustatymai'\n    Fetch Feeds from RSS: 'Gauti kanalus iš RSS'\n    Fetch Automatically: Gauti sklaidos kanalą automatiškai\n  Distraction Free Settings:\n    Distraction Free Settings: 'Blaškančių elementų nustatymai'\n    Hide Video Views: 'Slėpti vaizdo įrašų peržiūrų skaičių'\n    Hide Video Likes And Dislikes: 'Slėpti vaizdo įrašų įvertinimus'\n    Hide Channel Subscribers: 'Slėpti kanalo prenumeratorių skaičių'\n    Hide Comment Likes: 'Slėpti komentarų įvertinimus'\n    Hide Recommended Videos: 'Slėpti rekomenduojamus vaizdo įrašus'\n    Hide Trending Videos: 'Slėpti „Dabar populiaru“ vaizdo įrašus'\n    Hide Popular Videos: 'Slėpti populiarius vaizdo įrašus'\n    Hide Playlists: 'Slėpti grojaraščius'\n    Hide Live Chat: 'Slėpti tiesioginę diskusiją'\n    Hide Active Subscriptions: 'Slėpti aktyvias prenumeratas'\n    Hide Video Description: Slėpti vaizdo įrašo aprašymą\n    Hide Comments: Slėpti komentarus\n    Hide Live Streams: Slėpti tiesiogines transliacijas\n    Hide Sharing Actions: Slėpti bendrinimo veiksmus\n    Hide Videos on Watch: 'Slėpti vaizdo įrašus po peržiūros'\n    Hide Chapters: Slėpti skirsnius\n    Hide Upcoming Premieres: Slėpti būsimas premjeras\n    Sections:\n      General: Generolas\n      Side Bar: Šoninė juosta\n      Channel Page: Kanalas Puslapis\n      Watch Page: Žiūrėti Puslapis\n    Display Titles Without Excessive Capitalisation: Rodyti Pavadinimus Be Per Daug Didžiųjų Raidžių\n    Hide Channels: Slėpti Vaizdo Įrašus Iš Kanalai\n    Hide Channels Placeholder: Kanalo pavadinimas arba ID\n    Hide Featured Channels: Slėpti Teminiai kanalai\n    Hide Channel Playlists: Slėpti Kanalo Grojaraščiai\n    Hide Channel Shorts: Slėpti Kanalo Šortus\n  Data Settings:\n    Data Settings: 'Duomenų nustatymai'\n    Select Export Type: 'Pasirinkti eksportavimo tipą'\n    Import Subscriptions: 'Importuoti prenumeratas'\n    Export Subscriptions: 'Eksportuoti prenumeratas'\n    Export FreeTube: 'Eksportuoti FreeTube'\n    Export YouTube: 'Eksportuoti YouTube'\n    Export NewPipe: 'Eksportuoti NewPipe'\n    Import History: 'Importuoti istoriją'\n    Export History: 'Eksportuoti istoriją'\n    Profile object has insufficient data, skipping item: 'Profilio objekte nėra pakankamai duomenų, elementas praleidžiamas'\n    All subscriptions and profiles have been successfully imported: 'Visos prenumeratos ir profiliai sėkmingai importuoti'\n    All subscriptions have been successfully imported: 'Visos prenumeratos sėkmingai importuotos'\n    Invalid subscriptions file: 'Netinkamas prenumeratų failas'\n    Invalid history file: 'Netinkamas žiūrėjimo istorijos failas'\n    Subscriptions have been successfully exported: 'Prenumeratos sėkmingai eksportuotos'\n    History object has insufficient data, skipping item: 'Žiūrėjimo istorijos objektas neturi pakankamai duomenų, elementas praleidžiamas'\n    All watched history has been successfully imported: 'Visa žiūrėjimo istorija buvo sėkmingai importuota'\n    All watched history has been successfully exported: 'Visa žiūrėjimo istorija buvo sėkmingai eksportuota'\n    Unable to read file: 'Nepavyksta nuskaityti failo'\n    Unable to write file: 'Nepavyksta rašyti failo'\n    Unknown data key: 'Nežinomas duomenų raktas'\n    How do I import my subscriptions?: 'Kaip aš galiu importuoti savo prenumeratas?'\n    Manage Subscriptions: 'Valdyti prenumeratas'\n    Playlist File: Grojaraščių failas\n    History File: Istorijos failas\n    All playlists has been successfully imported: Visi grojaraščiai sėkmingai importuoti\n    All playlists has been successfully exported: Visi grojaraščiai sėkmingai eksportuoti\n    Import Playlists: Importuoti grojaraščius\n    Export Playlists: Eksportuoti grojaraščius\n    Subscription File: Prenumeratų failas\n    Playlist insufficient data: Nepakankamai duomenų „{playlist}“ grojaraščiui, praleidžiamas elementas\n  Proxy Settings:\n    Proxy Settings: 'Įgaliotojo serverio nustatymai'\n    Enable Tor / Proxy: 'Įgalinti Tor / įgaliotąjį serverį'\n    Proxy Protocol: 'Įgaliotojo serverio protokolas'\n    Proxy Host: 'Įgaliotojo serverio adresas'\n    Proxy Port Number: 'Įgaliotojo serverio prievado numeris'\n    Clicking on Test Proxy will send a request to: 'Spustelėjus „Testuoti įgaliotąjį serverį“ bus išsiųsta užklausa į'\n    Test Proxy: 'Testuoti įgaliotąjį serverį'\n    Your Info: 'Tavo informacija'\n    Ip: 'IP'\n    Country: 'Šalis'\n    Region: 'Regionas'\n    City: 'Miestas'\n    Error getting network information. Is your proxy configured properly?: 'Gaunant tinklo informaciją įvyko klaida. Ar jūsų įgaliotasis serveris sukonfigūruotas tinkamai?'\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'SponsorBlock nustatymai'\n    Enable SponsorBlock: 'Įjungti SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'SponsorBlock API URL (numatytasis yra https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'Pranešti, kuomet praleidžiamas rėmėjų segmentas'\n    Skip Options:\n      Prompt To Skip: Pasiūlyti praleisti\n      Skip Option: Praleidimo parinktis\n      Auto Skip: Automatinis praleidimas\n      Do Nothing: Nieko nedaryti\n      Show In Seek Bar: Rodyti peržiūros progreso juostoje\n    Category Color: Kategorija spalva\n  Parental Control Settings:\n    Parental Control Settings: Tėvų kontrolės nustatymai\n    Hide Unsubscribe Button: Slėpti prenumeratos atšaukimo mygtuką\n    Hide Search Bar: Slėpti paieškos juostą\n    Show Family Friendly Only: Rodyti tik turinį tinkamą šeimai\n  Experimental Settings:\n    Replace HTTP Cache: Pakeisti HTTP talpyklą\n    Experimental Settings: Eksperimentiniai nustatymai\n    Warning: Šie nustatymus yra eksperimentiniai, juos įjungus gali būti sutrikimų. Labai rekomenduojama iš anksto pasidaryti atsargines kopijas. Naudokite savo rizika!\n  Password Dialog:\n    Password: Slaptažodis\n    Enter Password To Unlock: Įveskite slaptažodį į atrakintumėte nustatymus\nAbout:\n  #On About page\n  About: 'Apie'\n  Beta: 'Beta'\n  Source code: 'Pirminis kodas'\n  Downloads / Changelog: 'Atsisiuntimai / pakeitimų žurnalas'\n  GitHub releases: 'Versijos GitHub'\n  Help: 'Pagalba'\n  FreeTube Wiki: 'FreeTube Wiki'\n  FAQ: 'DUK'\n  Report a problem: 'Pranešti apie problemą'\n  GitHub issues: 'GitHub problemos'\n  Please check for duplicates before posting: 'Prieš pranešdami patikrinkite, ar užklausa nesidubliuos su jau esančia'\n  Website: 'Tinklalapis'\n  Blog: 'Tinklaraštis'\n  Email: 'El. paštas'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Pokalbis Matrix'\n  room rules: 'kambario taisykles'\n  Translate: 'Vertimai'\n  Credits: 'Projekto komanda'\n  these people and projects: 'šių žmonių ir projektų'\n  Donate: 'Paremti'\n\nProfile:\n  Profile Select: 'Profilio pasirinkimas'\n  Profile Filter: 'Profilio filtrai'\n  All Channels: 'Visi kanalai'\n  Profile Manager: 'Profilio valdymas'\n  Create New Profile: 'Sukurti naują profilį'\n  Edit Profile: 'Redaguoti profilį'\n  Color Picker: 'Spalvų rinkiklis'\n  Custom Color: 'Pasirinktinė spalva'\n  Profile Preview: 'Profilio peržiūra'\n  Create Profile: 'Sukurti profilį'\n  Update Profile: 'Atnaujinti profilį'\n  Make Default Profile: 'Padaryti kaip numatytąjį profilį'\n  Delete Profile: 'Ištrinti profilį'\n  Are you sure you want to delete this profile?: 'Ar tikrai norite ištrinti šį profilį?'\n  All subscriptions will also be deleted.: 'Taip pat bus ištrintos visos prenumeratos.'\n  Your profile name cannot be empty: 'Jūsų profilio vardas negali būti tuščias'\n  Profile has been created: 'Profilis sukurtas'\n  Profile has been updated: 'Profilis atnaujintas'\n  Your default profile has been set to {profile}: '{profile} buvo nustatytas kaip numatytasis profilis'\n  Removed {profile} from your profiles: '{profile} buvo pašalintas iš tavo profilių'\n  Your default profile has been changed to your primary profile: 'Numatytasis profilis buvo nustatytas kaip pagrindinis'\n  '{profile} is now the active profile': '{profile} yra dabar aktyvus profilis'\n  Subscription List: 'Prenumeratų sąrašas'\n  Other Channels: 'Kiti kanalai'\n  '{number} selected': '{number} pasirinktas'\n  Select All: 'Pasirinkti visus'\n  Select None: 'Nesirinkti nieko'\n  Delete Selected: 'Pašalinti pasirinktus'\n  Add Selected To Profile: 'Pridėti dabar pasirinktą prie profilio'\n  No channel(s) have been selected: 'Nepasirinktas nė vienas kanalas(-ai)'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Tai yra jūsų pagrindinis profilis. Ar tikrai norite ištrinti pasirinktus kanalus? Tie patys kanalai bus ištrinti bet kuriame profilyje, kuriame jie yra.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ar tikrai norite ištrinti pasirinktus kanalus? Tai kanalo neištrins iš kito profilio.'\n#On Channel Page\n  Profile Settings: Profilio nustatymai\nChannel:\n  Subscribe: 'Prenumeruoti'\n  Unsubscribe: 'Atšaukti prenumeratą'\n  Channel has been removed from your subscriptions: 'Kanalas pašalintas iš jūsų prenumeratų'\n  Removed subscription from {count} other channel(s): 'Prenumerata pašalinta iš {count} kito(-ų) kanalo(-ų)'\n  Added channel to your subscriptions: 'Prie jūsų prenumeratų pridėtas kanalas'\n  Search Channel: 'Ieškoti kanalų'\n  Your search results have returned 0 results: 'Paieškos rezultatai gražino 0 rezultatų'\n  Videos:\n    Videos: 'Vaizdo įrašai'\n    This channel does not currently have any videos: 'Šiuo metu šiame kanale nėra vaizdo įrašų'\n    Sort Types:\n      Newest: 'Naujausi'\n      Oldest: 'Seniausi'\n      Most Popular: 'Populiariausi'\n  Playlists:\n    Playlists: 'Grojaraščiai'\n    This channel does not currently have any playlists: 'Šiuo metu šiame kanale nėra grojaraščių'\n    Sort Types:\n      Last Video Added: 'Paskutinis pridėtas vaizdo įrašas'\n      Newest: 'Naujausias'\n      Oldest: 'Seniausias'\n  About:\n    About: 'Apie'\n    Channel Description: 'Kanalo aprašymas'\n    Featured Channels: 'Išskirti kanalai'\nVideo:\n  Mark As Watched: 'Pažymėti kaip peržiūrėtą'\n  Remove From History: 'Pašalinti iš žiūrėjimo istorijos'\n  Video has been marked as watched: 'Vaizdo įrašas pažymėtas kaip žiūrėtas'\n  Video has been removed from your history: 'Vaizdo įrašas pašalintas iš jūsų žiūrėjimo istorijos'\n  Save Video: 'Išsaugoti vaizdo įrašą'\n  Video has been saved: 'Vaizdo įrašas išsaugotas'\n  Video has been removed from your saved list: 'Vaizdo įrašas pašalintas iš jūsų išsaugotų įrašų sąrašo'\n  Open in YouTube: 'Atidaryti YouTube'\n  Copy YouTube Link: 'Kopijuoti YouTube nuorodą'\n  Open YouTube Embedded Player: 'Atidaryti YouTube įterptąjį grotuvą'\n  Copy YouTube Embedded Player Link: 'Kopijuoti YouTube įterptojo grotuvo nuorodą'\n  Open in Invidious: 'Atidaryti Invidious'\n  Copy Invidious Link: 'Kopijuoti Invidious nuorodą'\n  Open Channel in YouTube: 'Atidaryti kanalą YouTube'\n  Copy YouTube Channel Link: 'Kopijuoti YouTube kanalo nuorodą'\n  Open Channel in Invidious: 'Atidaryti kanalą Invidious'\n  Copy Invidious Channel Link: 'Kopijuoti Invidious kanalo nuorodą'\n  Views: 'Peržiūros'\n  Loop Playlist: 'Sukti grojaraštį ciklu'\n  Shuffle Playlist: 'Maišyti grojaraštį'\n  Reverse Playlist: 'Apsukti grojaraštį'\n  Previous: 'Iš naujo'\n  Next: 'Kitas'\n  Watched: 'Žiūrėta'\n  Autoplay: 'Paleisti automatiškai'\n  Starting soon, please refresh the page to check again: 'Greitai prasidės, atnaujinkite puslapį, kad galėtumėte patikrinti dar kartą'\n  # As in a Live Video\n  Live: 'Tiesiogiai'\n  Live Now: 'Tiesiogiai dabar'\n  Live Chat: 'Tiesioginė diskusija'\n  Enable Live Chat: 'Įgalinti tiesioginę diskusiją'\n  Live Chat is currently not supported in this build.: 'Šioje versijoje tiesioginė diskusija kol kas nepalaikoma.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Tiesioginė diskusija yra įgalinta.  Čia bus rodomi pokalbio pranešimai.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Tiesioginė diskusija šiuo metu nepalaikoma naudojant Invidious API. Būtinas tiesioginis ryšys su YouTube.'\n  Published:\n    In less than a minute: prieš mažiau nei minutę\n  Published on: 'Publikuota'\n  Streamed on: 'Transliuota'\n  Started streaming on: 'Transliaciją pradėjo'\n  Sponsor Block category:\n    sponsor: 'Rėmėjas'\n    intro: 'Įžanga'\n    outro: 'Pabaigos ekranas'\n    self-promotion: 'Savireklama'\n    interaction: 'Interakcija'\n    music offtopic: 'Nesusijusi muzika'\n    recap: Apibendrinimas\n    filler: Užpildas\n  External Player:\n    OpenInTemplate: 'Atidaryti {externalPlayer}'\n    video: 'vaizdo įrašas'\n    playlist: 'grojaraštis'\n    OpeningTemplate: 'Atidaroma {videoOrPlaylist} per {externalPlayer}...'\n    UnsupportedActionTemplate: '{externalPlayer} nepalaiko: {action}'\n    Unsupported Actions:\n      starting video at offset: 'Pradedant vaizdo įrašą kompensuojant'\n      setting a playback rate: 'nustatomas atkūrimo dažnis'\n      opening playlists: 'atidaromi grojaraščiai'\n      opening specific video in a playlist (falling back to opening the video): 'konkretaus vaizdo įrašo atidarymas grojaraštyje (grįžtant prie vaizdo įrašo atidarymo)'\n      reversing playlists: 'apsukami grojaraščiai'\n      shuffling playlists: 'maišomi grojaraščiai'\n      looping playlists: 'ciklu sukami grojaraščiai'\n#& Videos\n  Premieres: Premjera\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Peržiūrėti visą grojaraštį'\n  Last Updated On: 'Paskutinį kartą atnaujinta'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Grojaraštis\nChange Format:\n  Change Media Formats: 'Keisti vaizdo įrašo formatus'\n  Use Dash Formats: 'Naudoti DASH formatus'\n  Use Legacy Formats: 'Naudoti Legacy formatus'\n  Use Audio Formats: 'Naudoti audio formatus'\n  Dash formats are not available for this video: 'DASH formatai šiam vaizdo įrašui negalimi'\n  Audio formats are not available for this video: 'Šiam vaizdo įrašui garso formatai negalimi'\nShare:\n  Share Video: 'Dalintis vaizdo įrašu'\n  Share Playlist: 'Dalintis grojaraščiu'\n  Include Timestamp: 'Pridėti laiko žymą'\n  Copy Link: 'Kopijuoti nuorodą'\n  Open Link: 'Atidaryti nuorodą'\n  Copy Embed: 'Kopijuoti įterptąjį'\n  Open Embed: 'Atidaryti įterptąjį'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL nukopijuotas į iškarpinę'\n  Invidious Embed URL copied to clipboard: 'Invidious įterpinio URL nukopijuotas į iškarpinę'\n  Invidious Channel URL copied to clipboard: 'Invidious kanalo URL nukopijuotas į iškarpinę'\n  YouTube URL copied to clipboard: 'YouTube URL nukopijuotas į iškarpinę'\n  YouTube Embed URL copied to clipboard: 'YouTube įterpinio URL nukopijuotas į iškarpinę'\n  YouTube Channel URL copied to clipboard: 'YouTube kanalo URL nukopijuotas į iškarpinę'\n\n  Share Channel: Dalintis kanalu\nMini Player: 'Mini grotuvas'\nComments:\n  Comments: 'Komentarai'\n  Click to View Comments: 'Spustelėkite norėdami peržiūrėti komentarus'\n  Getting comment replies, please wait: 'Gaunami atsakymai į komentarus, palaukite'\n  There are no more comments for this video: 'Šiame vaizdo įraše nėra daugiau komentarų'\n  Hide Comments: 'Slėpti komentarus'\n  Top comments: 'Top komentarai'\n  Newest first: 'Naujausi viršuje'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Šiam vaizdo įrašui nėra parašytų komentarų'\n  Load More Comments: 'Įkelti daugiau komentarų'\n  Show More Replies: Rodyti daugiau atsakymų\n  Pinned by: Prisegė\n  Member: Narys\nUp Next: 'Sekantis'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Pasirinkite posistemę, kurią „FreeTube“ naudoja duomenims gauti. Vietinis API yra su integruota ištraukimo funkciją. Norint prisijungti prie „Invidious“ API reikalingas „Invidious“ serveris.'\n    Fallback to Non-Preferred Backend on Failure: 'Kai jūsų pageidaujamoje API kyla problemų, „FreeTube“ automatiškai bandys naudoti jūsų nepasirinktą API kaip atsarginį metodą, kai tai yra įgalinta.'\n    Thumbnail Preference: 'Visos FreeTube vaizdo įrašų miniatiūros vietoje numatytosios bus pakeistos atitinkamu vaizdo įrašo stop kardu.'\n    Invidious Instance: 'Invidious perdavimo šaltinis, prie kurio FreeTube prisijungs, kad gautų API pasikreipimus.'\n    Region for Trending: '„Dabar populiaru“ regionas leidžia pasirinkti, kurios šalies populiarius vaizdo įrašus norite rodyti.'\n    External Link Handling: \"Pasirinkite numatytąjį elgesį, kai spustelėjama nuoroda, kurios negalima atidaryti „FreeTube“.\\nPagal numatytuosius nustatymus „FreeTube“ atidarys spustelėtą nuorodą numatytojoje naršyklėje.\\n\"\n  Player Settings:\n    Proxy Videos Through Invidious: 'Bus prisijungęs prie „Invidious“, kad galėtų teikti vaizdo įrašus, užuot užmezgęs tiesioginį ryšį su „YouTube“.'\n    Default Video Format: 'Nustatykite vaizdo įrašo atkūrimo formatus. DASH formatai gali rodyti aukštesnes kokybės vaizdo įrašus. Senieji formatai (Legacy) gali būti ne daugiau kaip 720p kokybės, tačiau jie reikalauja mažesnių tinklo resursų. Garso formatai -tai tik garsas, vaizdo įrašas nėra rodomas ar siunčiamas.'\n    Scroll Playback Rate Over Video Player: Kai žymeklis yra virš vaizdo įrašo, paspauskite ir laikykite nuspaudę valdymo klavišą („Mac“ komandų klavišas) ir slinkite pelės ratuką pirmyn arba atgal, kad valdytumėte atkūrimo greitį. Paspauskite ir laikykite nuspaudę valdymo klavišą („Mac“ komandų klavišas) ir spustelėkite kairįjį pelės klavišą, kad greitai grįžtumėte į numatytąjį atkūrimo greitį (1 kartą, nebent jis buvo pakeistas nustatymuose).\n  External Player Settings:\n    External Player: 'Pasirinkus išorinį grotuvą, miniatiūroje bus rodoma piktograma, leidžianti atidaryti vaizdo įrašą (grojaraštį, jei palaikoma) išoriniame grotuve. Įspėjimas, Invidious nustatymai neturi įtakos išoriniams grotuvams.'\n    Custom External Player Executable: 'Pagal numatytuosius nustatymus „FreeTube“ manys, kad pasirinktą išorinį grotuvą galima rasti per PATH aplinkos kintamąjį. Jei reikia, čia galite nustatyti pasirinktinį kelią.'\n    Ignore Warnings: 'Neatvaizduoti įspėjimų, kai dabartinis išorinis grotuvas nepalaiko dabartinio veiksmo (pvz., grojaraščių atkūrimas ir kt.).'\n    Custom External Player Arguments: 'Bet kokius pasirinktinius komandinės eilutės argumentus, kuriuos norite perduoti išoriniam grotuvui.'\n    DefaultCustomArgumentsTemplate: '(Numatytasis: „{defaultCustomArguments}“)'\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Kai bus įgalinta, „FreeTube“ naudos RSS, o ne numatytąjį metodą, kad užpildytų jūsų prenumeratos kanalą. RSS yra greitesnė ir išvengia IP blokavimo, tačiau nepateikia tam tikros informacijos, pvz., vaizdo įrašo trukmės ar tiesioginės transliacijos būsenos'\n    Fetch Automatically: Kai ši funkcija įjungta, FreeTube automatiškai įkels naują turinį iš prenumeratų, kai atidaromas naujas langas ir perjungiamas profilis.\n\n# Toast Messages\n  Experimental Settings:\n    Replace HTTP Cache: Išjungiama Electron disko pagrindu veikianti HTTP talpykla ir įjungiama pasirinktinė atmintyje esanti vaizdų talpykla. Dėl to padidės operatyviosios atminties naudojimas.\nLocal API Error (Click to copy): 'Vietinė API klaida (spustelėkite, jei norite kopijuoti)'\nInvidious API Error (Click to copy): 'Invidious API klaida (spustelėkite, jei norite kopijuoti)'\nFalling back to Invidious API: 'Grįžtama prie Invidious API'\nFalling back to Local API: 'Grįžtama prie vietinio API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Šis vaizdo įrašas nepasiekiamas, nes trūksta formatų. Tai gali nutikti dėl to, kad šalis yra nepasiekiama.'\nUnknown YouTube url type, cannot be opened in app: 'Nežinomas YouTube URL tipas, nėra galimybės jo atidaryti programoje'\nLoop is now disabled: 'Sukimas ciklu išjungtas'\nLoop is now enabled: 'Sukimas ciklu dabar įjungtas'\nShuffle is now disabled: 'Maišymas dabar išjungtas'\nShuffle is now enabled: 'Maišymas dabar įjungtas'\nThe playlist has been reversed: 'Grojaraštis buvo apsuktas'\nPlaying Next Video: 'Leidžiamas sekantis vaizdo įrašas'\nPlaying Previous Video: 'Leidžiamas ankstesnis vaizdo įrašas'\nPlaying Next Video Interval: 'Greitai bus paleistas kitas vaizdo įrašas. Spustelėkite norėdami atšaukti. | Kitas vaizdo įrašas paleidžiamas po {nextVideoInterval} sek. Spustelėkite, jei norite atšaukti. | Kitas vaizdo įrašas bus paleidžiamas po {nextVideoInterval} sek. Spustelėkite norėdami atšaukti.'\nCanceled next video autoplay: 'Atšauktas sekančio vaizdo įrašo automatinis paleidimas'\n'The playlist has ended. Enable loop to continue playing': 'Grojaraštis baigėsi.  Įgalinkite grojimą ciklu, kad galėtumėte žiūrėti toliau'\n\nYes: 'Taip'\nNo: 'Ne'\nDefault Invidious instance has been cleared: Numatytasis Invidious perdavimo šaltinis išvalytas\nDefault Invidious instance has been set to {instance}: Numatytasis Invidious perdavimo šaltinis buvo nustatytas į {instance}\nSearch Bar:\n  Clear Input: Išvalyti įvestį\n  Remove: Pašalinkite\nExternal link opening has been disabled in the general settings: Išorinės nuorodos atidarymas buvo išjungtas bendruosiuose nustatymuose\nAre you sure you want to open this link?: Ar tikrai norite atidaryti šią nuorodą?\nNew Window: Naujas langas\nChannels:\n  Channels: Kanalai\n  Title: Kanalų sąrašas\n  Search bar placeholder: Ieškoti kanalų\n  Count: rastas (-i) {number} kanalas (-ai).\n  Empty: Jūsų kanalų sąrašas šiuo metu tuščias.\n  Unsubscribe Prompt: Ar tikrai norite atšaukti {channelName} prenumeratą?\nScreenshot Success: Ekrano kopija išsaugota kaip „{filePath}“\nScreenshot Error: Ekrano kopija nepavyko. {error}\nChapters:\n  Chapters: Skirsniai\nClipboard:\n  Copy failed: Nepavyko nukopijuoti į iškarpinę\n  Cannot access clipboard without a secure connection: Negalima pasiekti iškarpinės be saugaus ryšio\nPreferences: Nuostatos\nGo to page: Eiti į {page}\nClose Banner: Uždaryti baneris\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Įjungti kūrėjo įrankius\n  Zoom In: Pritraukti\n  Zoom Out: Atitolinti\n  Fullscreen: Viso ekrano rėžimas\nCompact side navigation: Kompaktiška šoninė navigacija\nExpand side navigation: Išplėskite šoninę navigaciją\nRight-click or hold to see history: Dešiniuoju pelės mygtuku spustelėkite arba palaikykite, kad pamatytumėte istoriją\nSearch character limit: Paieškos užklausa viršija {searchCharacterLimit} simbolių skaičiaus ribą\n"
  },
  {
    "path": "static/locales/lv.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Latviešu'\n\n# Webkit Menu Bar\nFile: 'Datne'\nNew Window: 'Jauns logs'\nPreferences: 'Iestatījumi'\nQuit: 'Iziet'\nEdit: 'Rediģēt'\nUndo: 'Atsaukt'\nRedo: 'Darīt vēlreiz'\nCut: 'Izgriezt'\nCopy: 'Kopēt'\nPaste: 'Ielīmēt'\nDelete: 'Dzēst'\nSelect all: 'Iezīmēt visu'\nToggle Developer Tools: 'Ieslēgt izstrādātāja rīkus'\nActual size: 'Patiesais izmērs'\nZoom in: 'Tuvināt'\nZoom out: 'Tālināt'\nToggle fullscreen: 'Pilnekrāns'\nWindow: 'Logs'\nMinimize: 'Samazināt'\nClose: 'Aizvērt'\nBack: 'Atpakaļ'\nForward: 'Uz priekšu'\nOpen New Window: 'Atvērt jaunu logu'\n\nVersion {versionNumber} is now available!  Click for more details: 'Versija {versionNumber} tagad ir pieejama!  Spied, lai skatītu detaļas'\nDownload From Site: 'Lejuplādēt no vietnes'\nA new blog is now available, {blogTitle}. Click to view more: 'Jauns emuāra ieraksts ir pieejams, {blogTitle}. Spied, lai skatītu vairāk'\nAre you sure you want to open this link?: 'Vai esi pārliecināts, ka vēlies atvērt šo saiti?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video'\n  Shorts: 'Īsie'\n  Live: 'Tiešraides'\n  Posts: 'Ziņas'\n  Sort By: Kārto pēc\n  Counts:\n    Video Count: '1 video | {count} video'\n    Channel Count: '1 kanāls | {count} kanāli'\n    Subscriber Count: '1 abonents | {count} abonenti'\n    View Count: '1 skatījums | {count} skatījumi'\n    Watching Count: '1 skatās | {count} skatās'\n\n# Search Bar\n    Like Count: 1 patikšana | {count} patikšanas\n    Comment Count: 1 komentārs | {count} komentāri\nSearch / Go to URL: 'Meklē / Dodies uz URL'\nSearch Bar:\n  Clear Input: 'Tīrīt ievadi'\n  # In Filter Button\n  Remove: Noņemt\nSearch Filters:\n  Search Filters: 'Meklēšanas atlase'\n  Sort By:\n    Most Relevant: 'Visatbilstošākie'\n    Rating: 'Vērtējuma'\n    Upload Date: 'Augšuplādes datums'\n    View Count: 'Skatījumi'\n  Time:\n    Time: 'Vecums'\n    Any Time: 'Jebkurā laikā'\n    Last Hour: 'Pēdējā stundā'\n    Today: 'Šodienas'\n    This Week: 'Šonedēļ'\n    This Month: 'Šomēnes'\n    This Year: 'Šogad'\n  Type:\n    Type: 'Veids'\n    All Types: 'Visi veidi'\n    Videos: 'Video'\n    Channels: 'Kanāli'\n    Movies: 'Filmas'\n    #& Playlists\n  Duration:\n    Duration: 'Ilgums'\n    All Durations: 'Visi ilgumi'\n    Short (< 4 minutes): 'Īss (<4 minūtēm)'\n    Medium (4 - 20 minutes): 'Vidējs (4 - 20 minūtes)'\n    Long (> 20 minutes): 'Ilgs (> 20 minūtes)'\n  # On Search Page\n  Search Results: 'Meklēšanas rezultāti'\n  Fetching results. Please wait: 'Iegūst rezultātus. Lūdzu gaidi'\n  Fetch more results: 'Iegūt vairāk rezultātu'\n  There are no more results for this search: 'Šim meklējumam nav vairāk rezultātu'\n# Sidebar\n  Features:\n    HD: HD\n    4K: 4K\n    360 Video: 360 Video\n    Location: Atrašanās vieta\n    Live: Tiešraide\n    3D: 3D\n    HDR: HDR\n    VR180: VR180\n    Features: Īpašības\n    Subtitles: Paraksti\n    Creative Commons: \"Creative Commons\\uFEFF\"\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonementi'\n  # channels that were likely deleted\n  Error Channels: 'Kanāli ar kļūdām'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Šim profilam ir daudz abonementu.  Piespiežu RSS, lai izvairītos no ierobežojumiem'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tavs abonementu saraksts ir tukšs. Ja vēlies ievest savus abonementus, dodies uz \"Datņu iestatījumiem\" un izvēlies \"Ievest abonementus\", vai arī vari meklēt kanālus un abonēt tos.'\n  Disabled Automatic Fetching: 'Tu esi izslēdzis automātisko abonementu iegūšanu. Atsvaidzini abonementus, lai redzētu tos šeit.'\n  Empty Channels: 'Taviem abonētajiem kanāliem pašreiz nav neviena video.'\n  Empty Posts: 'Taviem abonētajiem kanāliem pašreiz nav neviena ieraksta.'\n  Load More Videos: 'Ielādē vairāk video'\n  Load More Posts: 'Ielādēt vairāk ierakstus'\n  Subscriptions Tabs: 'Abonementu cilnes'\n  All Subscription Tabs Hidden: 'Visas abonementu cilnes ir paslēptas. Lai redzētu saturu šeit, lūdzu atslēp dažas cilnes \"{settingsSection}\" sadaļā \"{subsection}\".'\nMore: 'Vairāk'\nChannels:\n  Channels: 'Kanāli'\n  Title: 'Kanālu saraksts'\n  Search bar placeholder: 'Meklē kanālus'\n  Count: '{number} kanāls(-i) atrasti.'\n  Empty: 'Tavs kanālu saraksts pašreiz ir tukšs.'\n  Unsubscribe Prompt: 'Vai esi drošs, ka vēlies atcelt abonementu no \"{channelName}\"?'\nTrending:\n  Trending: 'Pašlaik topā'\n  Gaming: 'Spēles'\n  Trending Tabs: 'Tendenču cilnes'\nMost Popular: 'Vispopulārākie'\nPlaylists: 'Atskaņošanas saraksti'\nUser Playlists:\n  Your Playlists: 'Tavi atskaņošanas saraksti'\n  Empty Search Message: 'Šajā atskaņošanas sarakstā nav video, kas atbilst tavam meklējumam'\n  Search bar placeholder: 'Meklē atskaņošanas sarakstus'\n  Playlist Description: Atskaņošanas saraksta apraksts\n  Sort By:\n    NameDescending: Z-A\n    NameAscending: A-Z\n    EarliestUpdatedFirst: Atjaunināšanas datums (vecākos augšgalā)\n    LatestPlayedFirst: Atskaņošanas datums (jaunākos augšgalā)\n    LatestUpdatedFirst: Atjaunināšanas datums (jaunākos augšgalā)\n    LatestCreatedFirst: Izveidošanas datums (jaunākos augšgalā)\n    EarliestCreatedFirst: Izveidošanas datums (vecākos augšgalā)\n    EarliestPlayedFirst: Atskaņošanas datums (vecākos augšgalā)\n  Cannot delete the quick bookmark target playlist.: Nevar izdzēst ātrās grāmatzīmes mērķa atskaņošanas sarakstu.\n  Delete Playlist: Dzēs atskaņošanas sarakstu\n  Remove from Favorites: Noņem no {playlistName}\n  Move Video Up: Pārvieto video augšup\n  Save Changes: Saglabā izmaiņas\n  Edit Playlist Info: Rediģē atskaņošanas saraksta info\n  Copy Playlist: Kopē atskaņošanas sarakstu\n  Remove Watched Videos: Noņem skatītos video\n  SinglePlaylistView:\n    Toast:\n      This playlist is already being used for quick bookmark.: Šis atskaņošanas saraksts jau tiek lietots priekš ātrās grāmatzīmes.\n      This playlist is now used for quick bookmark: Šis atskaņošanas saraksts tagad tiek lietots priekš ātrās grāmatzīmes\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Šis atskaņošanas saraksts tagad tiek lietots priekš ātrās grāmatzīmes {oldPlaylistName} vietā. Spied šeit, lai atceltu\n      Playlist name cannot be empty. Please input a name.: Atskaņošanas saraksta nosaukums nevar būt tukšs. Lūdzu ievadi nosaukumu.\n      Playlist has been updated.: Atskaņošanas saraksts tika atjaunināts.\n      Video has been removed: Video tika noņemts\n      This video cannot be moved up.: Šo video nevar pārvietot augšup.\n      This video cannot be moved down.: Šo video nevar pārvietot lejup.\n      Reverted to use {oldPlaylistName} for quick bookmark: Atgriezts pie {oldPlaylistName} priekš ātrās grāmatzīmes\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Daži video atskaņošanas sarakstā vēl nav ielādēti. Spied šeit, lai kopētu tik un tā.\n      There was an issue with updating this playlist.: Radās problēma atjauninot šo atskaņošanas sarakstu.\n      There was a problem with removing this video: Radās problēma noņemot video\n      This playlist is protected and cannot be removed.: Šis atskaņošanas saraksts ir aizsargāts un nevar tikt noņemts.\n      There were no videos to remove.: Nebija video, ko noņemt.\n      Playlist {playlistName} has been deleted.: '{playlistName} atskaņošanas saraksts tika dzēsts.'\n      \"{videoCount} video(s) have been removed\": 1 video tika noņemts | {videoCount} video tika noņemti\n      This playlist does not exist: Šis atskaņošanas saraksts neeksistē\n    Search for Videos: Meklē video\n  You have no playlists. Click on the create new playlist button to create a new one.: Tev nav atskaņošanas sarakstu. Spied uz \"Izveido jaunu atskaņošanas sarakstu\", lai izveidotu jaunu.\n  This playlist currently has no videos.: Šajā atskaņošanas sarakstā pašreiz nav video.\n  Add to Favorites: Pievieno pie {playlistName}\n  Move Video Down: Pārvieto video lejup\n  Cancel: Atcel\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Vai esi drošs, ka vēlies noņemt 1 skatīto video no šī atskaņošanas saraksta? To nevar atcelt. | Vai esi drošs, ka vēlies noņemt {playlistItemCount} skatītos video no šī atskaņošanas saraksta? To nevar atcelt.\n  Are you sure you want to delete this playlist? This cannot be undone: Vai esi drošs, ka vēlies dzēst šo atskaņošanas sarakstu? To nevar atcelt.\n  Playlist Name: Atskaņošanas saraksta nosaukums\n  Create New Playlist: Izveido jaunu atskaņošanas sarakstu\n  Playlists with Matching Videos: Atskaņošanas saraksti ar atbilstošiem video\n  Remove Duplicate Videos: Noņem video dublikātus\n  Enable Quick Bookmark With This Playlist: Iespējo ātro grāmatzīmi ar šo atskaņošanas sarakstu\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Vai esi drošs, ka vēlies noņemt 1 video dublikātu no šī atskaņošanas saraksta? To nevar atcelt. | Vai esi drošs, ka vēlies noņemt {playlistItemCount} video dublikātus no šī atskaņošanas saraksta? To nevar atcelt.\n  Add to Playlist: Pievieno atskaņošanas sarakstam\n  Remove from Playlist: Noņem no atskaņošanas saraksta\n  Quick Bookmark Enabled: Atrā grāmatzīme iespējota\n  CreatePlaylistPrompt:\n    Toast:\n      There was an issue with creating the playlist.: Izveidojot atskaņošanas sarakstu radās kļūda.\n      Playlist {playlistName} has been successfully created.: '{playlistName} atskaņošanas saraksts veiksmīgi izveidots.'\n    Create: Izveidot\n    New Playlist Name: Jaunā atskaņošanas saraksta nosaukums\n  AddVideoPrompt:\n    Save: Saglabāt\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} video jau pievienoti'\n    N playlists selected: '{playlistCount} atlasīti'\n  Export Playlist: Eksportēt šo atskaņošanas sarakstu\n  The playlist has been successfully exported: Atskaņošanas saraksts ir veiksmīgi eksportēts\n  TotalTimePlaylist: 'Kopējais laiks: {duration}'\nHistory:\n  # On History Page\n  History: 'Vēsture'\n  Watch History: 'Skatīšanās vēsture'\n  Your history list is currently empty.: 'Tava skatīšanās vēsture pašreiz ir tukša.'\n  Empty Search Message: ''\n  Search bar placeholder: \"Meklē vēsturē\"\n  Case Sensitive Search: Reģistrjūtīga meklēšana\nSettings:\n  # On Settings Page\n  Settings: 'Iestatījumi'\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: 'Vispārīgie'\n    Check for Updates: 'Pārbaudīt atjauninājumus'\n    Check for Latest Blog Posts: 'Skatīt jaunākos bloga ierakstus'\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: 'Iespējo meklēšanas ieteikumus'\n    Default Landing Page: 'Noklusējuma sākumlapa'\n    Locale Preference: 'Vietas iestatījums'\n    System Default: 'Sistēmas noklusējums'\n    Preferred API Backend:\n      Preferred API Backend: 'Vēlamā API aizmugure'\n      Local API: 'Vietējais API'\n      Invidious API: \"Invidious API\\uFEFF\"\n    Video View Type:\n      Video View Type: 'Video skata veids'\n      Grid: 'Režģis'\n      List: 'Saraksts'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Sīktēlu iestatījums'\n      Default: 'Noklusējums'\n      Beginning: 'Sākums'\n      Middle: 'Vidus'\n      End: 'Beigas'\n      Hidden: 'Paslēpts'\n      Blur: Aizmiglo\n    Current Invidious Instance: 'Pašreizējais Invidious gadījums'\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: 'Pašreizējais gadījums tiks nejaušots sāknējot'\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: 'Skatīt visu Invidious gadījuma informāciju'\n    Region for Trending: 'Tendenču apgabals'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'Ārējo saišu vadība'\n      Open Link: 'Atvērt saiti'\n      Ask Before Opening Link: 'Jautāt pirms saites atvēršanas'\n      No Action: 'Nedarīt neko'\n    Auto Load Next Page:\n      Label: Autoielādē nākamo lapu\n      Tooltip: Automātiski ielādēt papildu lapas un komentārus.\n  Theme Settings:\n    Theme Settings: 'Izskata'\n    Match Top Bar with Main Color: 'Saskaņo augšmalu ar galveno krāsu'\n    Expand Side Bar by Default: 'Izvērs sānu malu pēc noklusējuma'\n    Disable Smooth Scrolling: 'Atspējot plūdeno ritināšanu'\n    UI Scale: 'Saskarnes izmērs'\n    Hide Side Bar Labels: 'Paslēpt sānu paneļa etiķetes'\n    Hide FreeTube Header Logo: 'Paslēpt FreeTube galvenes logo'\n    Base Theme:\n      Base Theme: 'Pamata izskats'\n      Black: 'Melns'\n      Dark: 'Tumšs'\n      System Default: 'Sistēmas noklusējums'\n      Light: 'Gaišs'\n      Dracula: 'Drakula'\n      Catppuccin Mocha: 'Kaķpučīn moka'\n      Pastel Pink: 'Pasteļu rozā'\n      Hot Pink: 'Karsti rozā'\n      Nordic: Ziemeļvalsts\n    Main Color Theme:\n      Main Color Theme: 'Galvenās krāsas izskats'\n      Red: 'Sarkans'\n      Pink: 'Rozā'\n      Purple: 'Violets'\n      Deep Purple: 'Dziļi violets'\n      Indigo: 'Indigo'\n      Blue: 'Zils'\n      Light Blue: 'Gaiši zils'\n      Cyan: 'Ciānzaļš, zilzaļš'\n      Teal: 'Tirkīza zaļš'\n      Green: 'Zaļš'\n      Light Green: 'Gaiši zaļš'\n      Lime: 'Laima zaļš, dzeltenzaļš'\n      Yellow: 'Dzeltens'\n      Amber: 'Dzintara (oranži) dzeltens'\n      Orange: 'Oranžs'\n      Deep Orange: 'Dziļi oranžs'\n      Dracula Cyan: ''\n      Dracula Green: 'Drakulas zaļš'\n      Dracula Orange: 'Drakulas oranžs'\n      Dracula Pink: 'Drakulas rozā'\n      Dracula Purple: 'Drakulas violets'\n      Dracula Red: 'Drakulas sarkans'\n      Dracula Yellow: 'Drakulas dzeltens'\n      Catppuccin Mocha Rosewater: 'Kaķpučīn moka rožūdens'\n      Catppuccin Mocha Flamingo: 'Kaķpučīn moka flamingo'\n      Catppuccin Mocha Pink: 'Kaķpučīn moka rozā'\n      Catppuccin Mocha Mauve: 'Kaķpučīn moka purpursarkans'\n      Catppuccin Mocha Red: 'Kaķpučīn moka sarkans'\n      Catppuccin Mocha Maroon: 'Kaķpučīn moka kastaņbrūns'\n      Catppuccin Mocha Peach: 'Kaķpučīn moka persiks'\n      Catppuccin Mocha Yellow: 'Kaķpučīn moka dzeltens'\n      Catppuccin Mocha Green: 'Kaķpučīn moka zaļš'\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: 'Kaķpučīn moka debess'\n      Catppuccin Mocha Sapphire: 'Kaķpučīn moka safīrs'\n      Catppuccin Mocha Blue: 'Kaķpučīn moka zils'\n      Catppuccin Mocha Lavender: 'Kaķpučīn moka lavanda'\n    Secondary Color Theme: 'Otrās krāsas izskats'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'Atskaņotāja'\n    Play Next Video: 'Automātiski atskaņot ieteicamos video'\n    Turn on Subtitles by Default: ''\n    Autoplay Videos: 'Automātiski atskaņot video'\n    Proxy Videos Through Invidious: 'Starpniekot video caur Invidious'\n    Autoplay Playlists: 'Automātiski atskaņot video no atskaņošanas saraksta'\n    Enable Theatre Mode by Default: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: 'Ritināt atskaņošanas ātrumu pāri video atskaņotājam'\n    Skip by Scrolling Over Video Player: 'Izlaist ritinot pāri video atskaņotājam'\n    Display Play Button In Video Player: 'Attēlot Atskaņošanas pogu video atskaņotājā'\n    Enter Fullscreen on Display Rotate: 'Pagriežot ekrānu pārslēgt uz pilnekrānu'\n    Next Video Interval: 'Automātiskās atskaņošanas atpakaļskaitīšanas intervāls'\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: 'Noklusējuma skaļums'\n    Default Playback Rate: 'Noklusējuma atskaņošanas ātrums'\n    Max Video Playback Rate: 'Maksimālais video atskaņošanas ātrums'\n    Video Playback Rate Interval: 'Video atskaņošanas ātruma intervāls'\n    Default Video Format:\n      Default Video Format: 'Noklusējuma video formāts'\n      Dash Formats: 'DASH formāti'\n      Legacy Formats: 'Mantojuma formāti'\n      Audio Formats: 'Audio formāti'\n    Default Quality:\n      Default Quality: 'Noklusējuma kvalitāte'\n      Auto: 'Automātiski atlasīt'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p (SD)'\n      720p: '720p (HD)'\n      1080p: '1080p (Full HD)'\n      1440p: '1440p (2.5K)'\n      4k: '2160p (4K)'\n      8k: '4320p (8K)'\n    Screenshot:\n      Enable: 'Iespējot ekrānšāviņu'\n      Format Label: 'Ekrānšāviņa formāti'\n      Quality Label: 'Ekrānšāviņa kvalitāte'\n      Ask Path: 'Jautāt saglabāšanas mapi'\n      Folder Label: 'Ekrānšāviņa mape'\n      Folder Button: 'Izvēlēties mapi'\n      File Name Label: 'Nosaukuma šablons'\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: 'Aizliegtās rakstzīmes'\n        Empty File Name: 'Tukšs datnes nosaukums'\n  External Player Settings:\n    External Player Settings: 'Ārējā atskaņotāja'\n    External Player: 'Ārējais atskaņotājs'\n    Ignore Unsupported Action Warnings: 'Ignorēt neatbalstītas darbības brīdinājumus'\n    Custom External Player Executable: 'Pielāgota ārējā atskaņotāja izpilddatne'\n    Custom External Player Arguments: 'Pielāgoti ārējā atskaņotāja mainīgie'\n    Players:\n      None:\n        Name: 'Nekas'\n    Ignore Default Arguments: Ignorēt noklusējuma argumentus\n  Privacy Settings:\n    Privacy Settings: 'Privātuma'\n    Remember History: 'Saglabāt skatīšanās vēsturi'\n    Save Watched Progress: 'Saglabāt skatīto attīstību'\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search Cache: 'Iztīri meklēšanas kešatmiņu'\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: 'Meklēšanas kešatmiņa tika iztīrīta'\n    Remove Watch History: 'Noņemt skatīšanās vēsturi'\n    Are you sure you want to remove your entire watch history?: 'Vai tu esi pārliecināts, ka vēlies noņemt visu skatīšanās vēsturi?'\n    Watch history has been cleared: 'Skatīšanās vēsture tika noņemta'\n    Remove All Subscriptions / Profiles: 'Noņemt visus abonementus / profilus'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    All playlists have been removed: Visi atskaņošanas saraksti tika noņemti\n    Remove All Playlists: Noņemt visus atskaņošanas sarakstus\n  Subscription Settings:\n    Subscription Settings: 'Abonementu'\n    Fetch Feeds from RSS: 'Iegūt plūsmu no RSS'\n    Fetch Automatically: 'Iegūt plūsmu automātiski'\n  Distraction Free Settings:\n    Distraction Free Settings: 'Beztraucēšanas'\n    Sections:\n      Side Bar: 'Sānu panelis'\n      Subscriptions Page: 'Abonementu lapa'\n      Channel Page: 'Kanāla lapa'\n      Watch Page: 'Skatīšanās lapa'\n      General: 'Vispārīgie'\n    Hide Video Views: 'Paslēpt video skatījumus'\n    Hide Video Likes And Dislikes: 'Paslēpt video novērtējuma atzīmes'\n    Hide Channel Subscribers: 'Paslēpt kanāla abonentus'\n    Hide Comment Likes: 'Paslēpt komentāru vērtējumus'\n    Hide Recommended Videos: 'Paslēpt ieteiktos video'\n    Hide Trending Videos: 'Paslēpt tendenču video'\n    Hide Popular Videos: 'Paslēpt populāros video'\n    Hide Playlists: 'Paslēpt sarakstus'\n    Hide Live Chat: 'Paslēpt dzīvo čatu'\n    Hide Active Subscriptions: 'Paslēp aktīvos abonementus'\n    Hide Video Description: 'Paslēpt video aprakstu'\n    Hide Comments: 'Paslēpt komentārus'\n    Hide Profile Pictures in Comments: 'Paslēpt profila attēlus komentāros'\n    Display Titles Without Excessive Capitalisation: 'Attēlot nosaukumus nepārspīlējot ar lielajiem burtiem un interpunkciju'\n    Hide Live Streams: 'Paslēpt dzīvās straumes'\n    Hide Upcoming Premieres: 'Paslēpt tuvojošās pirmizrādes'\n    Hide Sharing Actions: 'Paslēpt dalīšanās darbības'\n    Hide Videos on Watch: 'Paslēpt video pēc skatīšanas'\n    Hide Chapters: 'Paslēpt nodaļas'\n    Hide Channels: 'Kanālos paslēpt video'\n    Hide Channels Placeholder: 'Kanāla ID'\n    Hide Featured Channels: 'Paslēpt izceltos kanālus'\n    Hide Channel Playlists: 'Slēpt kanālā \"Atskaņošanas saraksti\" cilni'\n    Hide Channel Shorts: 'Slēpt kanālā \"Īsie video\" cilni'\n    Hide Channel Podcasts: 'Slēpt kanālā \"Podkāsti\" cilni'\n    Hide Channel Releases: 'Slēpt kanālā \"Relīzes\" cilni'\n    Hide Subscriptions Videos: 'Paslēp abonementu video'\n    Hide Subscriptions Shorts: 'Paslēp abonementu īsos video'\n    Hide Subscriptions Live: 'Paslēp abonementu tiešraides'\n    Hide Channels Already Exists: Kanāla ID jau eksistē\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Vārds, vārda daļa, vai frāze\n    Hide Channel Home: Slēpt kanālā \"Sākums\" cilni\n    Hide Channel Courses: Slēpt kanālā \"Kursi\" cilni\n  Data Settings:\n    Data Settings: 'Datu'\n    Select Export Type: 'Izvēlēties eksporta veidu'\n    Import Subscriptions: 'Ievest abonementus'\n    Subscription File: 'Aboenementu datne'\n    History File: 'Vēstures datne'\n    Playlist File: 'Atskaņošanas saraksta datne'\n    Export Subscriptions: 'Izvest abonementus'\n    Export FreeTube: 'Eksportēt FreeTube'\n    Export YouTube: 'Eksportēt YouTube'\n    Export NewPipe: 'Eksportēt NewPipe'\n    Import History: 'Importēt vēsturi'\n    Export History: 'Eksportēt vēsturi'\n    Import Playlists: 'Importēt sarakstus'\n    Export Playlists: 'Eksportēt sarakstus'\n    Profile object has insufficient data, skipping item: 'Profila objektam nav pietiekami datu, izlaiž vienumu'\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: 'Visi abonementi tika veiksmīgi ievesti'\n    Invalid subscriptions file: 'Nederīga abonementu datne'\n    Invalid history file: 'Nederīga vēstures datne'\n    Subscriptions have been successfully exported: 'Visi abonementi tika veiksmīgi izvesti'\n    History object has insufficient data, skipping item: 'Vēstures objektam nav pietiekami datu, izlaiž vienumu'\n    All watched history has been successfully imported: 'Visa skatīšanās vēstures tika veiksmīgi importēta'\n    All watched history has been successfully exported: 'Visa skatīšanās vēstures tika veiksmīgi eksportēta'\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: 'Visi saraksti tika veiksmīgi importēti'\n    All playlists has been successfully exported: 'Visi saraksti tika veiksmīgi eksportēti'\n    Unable to read file: 'Nespēj nolasīt datni'\n    Unable to write file: 'Nespēj ierakstīt datni'\n    Unknown data key: 'Nezināma datu atslēga'\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: 'Pārvaldīt abonementus'\n    Search history: Meklēšanas vēsture\n  Proxy Settings:\n    Proxy Settings: 'Starpniekservera'\n    Enable Tor / Proxy: 'Iespējot Tor / starpniekserveri'\n    Proxy Protocol: 'Starpniekservera protokols'\n    Proxy Host: 'Starpniekservera saimnieks'\n    Proxy Port Number: 'Starpniekservera porta numurs'\n    Clicking on Test Proxy will send a request to: 'Nospiežot \"Pārbaudīt starpniekserveri\" tiks nosūtīts pieprasījums uz'\n    Test Proxy: 'Pārbaudīt starpniekserveri'\n    Your Info: 'Tavs info'\n    Ip: 'IP'\n    Country: 'Valsts'\n    Region: 'Apgabals'\n    City: 'Pilsēta'\n    Error getting network information. Is your proxy configured properly?: 'Kļūda saņemot tīkla informāciju. Vai jūsu starpniekserveris ir uzstādīts pareizi?'\n    Proxy Username: Starpniekservera lietotājvārds\n    Proxy Password: Starpniekservera parole\n  SponsorBlock Settings:\n    SponsorBlock Settings: \"SponsorBlock\\uFEFF\"\n    Enable SponsorBlock: 'Iespējot SponsorBlock'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: 'Ziņot, kad sponsora gabals tiek izlaists'\n    UseDeArrowTitles: 'Izmantot DeArrow video nosaukumus'\n    Skip Options:\n      Skip Option: 'Izlaišanas iestatījums'\n      Auto Skip: 'Autoizlaist'\n      Show In Seek Bar: 'Rādīt tīšanas joslā'\n      Prompt To Skip: 'Jautāt, lai izlaistu'\n      Do Nothing: 'Neko nedarīt'\n    Category Color: 'Iedalījuma krāsa'\n    UseDeArrowThumbnails: Izmanto DeArrow priekš sīktēliem\n  Parental Control Settings:\n    Parental Control Settings: 'Vecāku vadības'\n    Hide Unsubscribe Button: 'Paslēpt Atabonēt pogu'\n    Show Family Friendly Only: 'Rādīt tikai ģimenei draudzīgi'\n    Hide Search Bar: 'Paslēp meklēšanas joslu'\n  Experimental Settings:\n    Experimental Settings: 'Izmēģinājuma'\n    Warning: ''\n    Replace HTTP Cache: 'Aizvietot HTTP kešatmiņu'\n  Password Dialog:\n    Password: 'Parole'\n    Enter Password To Unlock: 'Ievadi paroli, lai atslēgtu iestatījumus'\n  Password Settings:\n    Password Settings: 'Paroles'\n    Set Password To Prevent Access: 'Uzstādi paroli, lai neļautu piekļūt uzstādījumiem'\n    Set Password: 'Uzstādi paroli'\n    Remove Password: 'Noņem paroli'\n  Return to Settings Menu: Atgriezies iestatījumu izvēlnē\n  Sort Settings Sections (A-Z): Kārto iestatījumu sadaļas (A-Z)\nAbout:\n  #On About page\n  About: 'Par'\n  Beta: 'Beta'\n  Source code: 'Pirmkods'\n  Downloads / Changelog: 'Lejuplādes / izmaiņu žurnāls'\n  GitHub releases: 'GitHub laidieni'\n  Help: 'Palīdzība'\n  FreeTube Wiki: 'FreeTube Wiki'\n  FAQ: 'BUJ'\n  Discussions: 'Sarunas'\n  Report a problem: 'Ziņot par problēmu'\n  GitHub issues: 'GitHub problēmas'\n  Please check for duplicates before posting: 'Lūdzu pārbaudi dublikātus pirms publicēšanas'\n  Website: 'Vietne'\n  Blog: 'Emuārs'\n  Email: 'E-pasts'\n  Mastodon: \"Mastodon\\uFEFF\"\n  Chat on Matrix: 'Tērzēt Matrixā'\n  room rules: 'istabas noteikumi'\n  Translate: 'Tulkot'\n  Credits: 'Nopelni'\n  these people and projects: 'šie cilvēki un apvienības'\n  Donate: 'Ziedot'\n\n  AGPLv3: \"AGPLv3\\uFEFF\"\nProfile:\n  Profile Settings: 'Profila'\n  Toggle Profile List: 'Pārslēgt profilu sarakstu'\n  Profile Select: 'Izvēlēties profilu'\n  Profile Filter: 'Profilu filtrs'\n  All Channels: 'Visi kanāli'\n  Profile Manager: 'Profilu pārvaldnieks'\n  Create New Profile: 'Veidot jaunu profilu'\n  Edit Profile: 'Mainīt profilu'\n  Color Picker: 'Krāsu izvēlētājs'\n  Custom Color: 'Pielāgota krāsa'\n  Profile Preview: 'Profila priekšskatījums'\n  Create Profile: 'Veidot profilu'\n  Update Profile: 'Atjaunināt profilu'\n  Make Default Profile: 'Izveido noklusējuma profilu'\n  Delete Profile: 'Dzēst profilu'\n  Are you sure you want to delete this profile?: 'Vai tu esi drošs, ka gribi dzēst šo profilu?'\n  All subscriptions will also be deleted.: 'Arī visi abonementi tiks izdzēsti.'\n  Your profile name cannot be empty: 'Tavs profila vārds nevar būt tukšs'\n  Profile has been created: 'Profils tika izveidots'\n  Profile has been updated: 'Profils tika atjaunināts'\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': '{profile} tagad ir aktīvais profils'\n  Subscription List: 'Abonementu saraksts'\n  Other Channels: 'Citi kanāli'\n  '{number} selected': '{number} izvēlēts'\n  Select All: 'Izvēlēties visus'\n  Select None: 'Neizvēlēties nevienu'\n  Delete Selected: 'Dzēst izvēlētos'\n  Add Selected To Profile: 'Izvēlētos pievienot profilam'\n  No channel(s) have been selected: 'Neviens kanāls netika izvēlēts'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n#On Channel Page\n  Create Profile Name: Izveido profila vārdu\n  Profile Name: Profila vārds\n  Edit Profile Name: Rediģē profila vārdu\nChannel:\n  Subscribe: 'Abonēt'\n  Unsubscribe: 'Pārtraukt abonēt'\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: 'Šis kanāls nepastāv'\n  This channel does not allow searching: 'Šis kanāls neatļauj meklēšanu'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'Šim kanālam ir vecuma ierobežojums un pašlaik nevar tikt skatīts FreeTube.'\n  Channel Tabs: 'Kanāla cilnes'\n  Videos:\n    Videos: 'Video'\n    This channel does not currently have any videos: 'Šajā kanāla pašlaik nav video'\n    Sort Types:\n      Newest: 'Jaunākie augšgalā'\n      Oldest: 'Vecākie augšgalā'\n      Most Popular: 'Populārākie'\n  Shorts:\n    This channel does not currently have any shorts: 'Šajā kanālā pašlaik nav īso'\n  Live:\n    Live: 'Tiešraides'\n    This channel does not currently have any live streams: 'Šajā kanālā pašlaik nav tiešraižu'\n  Playlists:\n    Playlists: 'Saraksti'\n    This channel does not currently have any playlists: 'Šajā kanālā pašlaik nav sarakstu'\n    Sort Types:\n      Last Video Added: 'Pēdējais pievienotais video'\n      Newest: 'Jaunākie augšgalā'\n      Oldest: 'Vecākie augšgalā'\n  Podcasts:\n    Podcasts: 'Podkāsti'\n    This channel does not currently have any podcasts: 'Šajā kanālā pašlaik nav podkāstu'\n  Releases:\n    Releases: 'Laidieni'\n    This channel does not currently have any releases: 'Šajā kanālā pašlaik nav laidienu'\n  About:\n    About: 'Par'\n    Channel Description: 'Kanāla apraksts'\n    Tags:\n      Tags: 'Birkas'\n      Search for: ''\n    Details: 'Informācija'\n    Joined: 'Pievienojās'\n    Location: 'Atrašanās vieta'\n    Featured Channels: 'Izceltie kanāli'\n  Posts:\n    This channel currently does not have any posts: 'Šajā kanālā pašlaik nav ierakstu'\n    votes: ''\n    Reveal Answers: 'Atklāj atbildes'\n    Hide Answers: 'Paslēp atbildes'\n  Courses:\n    Courses: Kursi\nVideo:\n  Mark As Watched: 'Atzīmē kā skatītu'\n  Remove From History: 'Noņem no vēstures'\n  Video has been marked as watched: 'Video tika atzīmēts kā skatīts'\n  Video has been removed from your history: 'Video tika noņemts no tavas vēstures'\n  Save Video: 'Saglabā video'\n  Video has been saved: 'Video tika saglabāts'\n  Video has been removed from your saved list: 'Video tika noņemts no tava saglabāto saraksta'\n  Open in YouTube: 'Atver YouTube'\n  Copy YouTube Link: 'Kopē YouTube saiti'\n  Open YouTube Embedded Player: 'Atver YouTube iegulto atskaņotāju'\n  Copy YouTube Embedded Player Link: 'Kopē YouTube iegultā atskaņotāja saiti'\n  Open in Invidious: 'Atver Invidious'\n  Copy Invidious Link: 'Kopē Invidious saiti'\n  Open Channel in YouTube: 'Atver kanālu YouTube'\n  Copy YouTube Channel Link: 'Kopē YouTube kanāla saiti'\n  Open Channel in Invidious: 'Atver kanālu Invidious'\n  Copy Invidious Channel Link: 'Kopē Invidious kanāla saiti'\n  Views: 'Skatījumi'\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: 'Iepriekšējais'\n  Next: 'Nākamais'\n  Watched: 'Skatīts'\n  Autoplay: 'Autoatskaņošana'\n  Starting soon, please refresh the page to check again: 'Drīz sāksies, lūdzu atsvaidzini lapu, lai pārbaudītu vēlreiz'\n  # As in a Live Video\n  Premieres: 'Pirmizrādes'\n  Upcoming: 'Tuvojošās'\n  Live: 'Tiešraidē'\n  Live Now: 'Tiešraidē tagad'\n  Live Chat: 'Tiešraides čats'\n  Enable Live Chat: 'Iespējo tiešraides čatu'\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: 'Publicēts'\n  Streamed on: ''\n  Started streaming on: ''\n  Sponsor Block category:\n    sponsor: 'Sponsors'\n    intro: ''\n    outro: ''\n    self-promotion: 'Pašreklāma'\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: 'video'\n    playlist: 'atskaņošanas saraksts'\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n#& Playlists\n  Player:\n    Stats:\n      Stats: Statistika\nPlaylist:\n  #& About\n  Playlist: 'Atskaņošanas saraksts'\n  View Full Playlist: ''\n  Last Updated On: ''\n\n# On Video Watch Page\n#* Published\n#& Views\n  Sort By:\n    AuthorAscending: Autora (A-Z)\n    AuthorDescending: Autora (Z-A)\n    VideoTitleAscending: Nosaukuma (A-Z)\n    VideoTitleDescending: Nosaukuma (Z-A)\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\nShare:\n  Share Video: 'Kopīgot video'\n  Share Channel: 'Kopīgot kanālu'\n  Share Playlist: 'Kopīgot atskaņošanas sarakstu'\n  Include Timestamp: ''\n  Copy Link: 'Kopēt saiti'\n  Open Link: 'Atvērt saiti'\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: 'Nodaļas'\n\nMini Player: ''\nComments:\n  Comments: 'Komentāri'\n  Click to View Comments: 'Rādīt komentārus'\n  Getting comment replies, please wait: 'Notiek komentāra atbilžu ielāde, lūdzu, uzgaidiet'\n  There are no more comments for this video: 'Šim video nav vairāk komentāru'\n  Hide Comments: 'Paslēpt komentārus'\n  Top comments: 'Populārākos augšgalā'\n  Newest first: 'Jaunākos augšgalā'\n  View {replyCount} replies: 'Rādīt 1 atbildi | Rādīt {replyCount} atbildes'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'Rādīt vairāk atbilžu'\n  There are no comments available for this video: 'Šim video nav komentāru'\n  Load More Comments: 'Ielādēt vairāk komentāru'\n  Pinned by: ''\n  Member: 'Biedrs'\n  Subscribed: ''\n  Hearted: ''\n  Hide {replyCount} replies: Paslēpt 1 atbildi | Paslēpt {replyCount} atbildes\n  View 1 reply from {channelName}: Rādīt 1 atbildi no {channelName}\n  View {replyCount} replies from {channelName} and others: Rādīt {replyCount} atbildes no {channelName} un citiem\n  There are no comments available for this post: Šai ziņai nav komentāru\nUp Next: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\n\nHashtag:\n  Hashtag: 'Mirkļbirka, tēmturis'\n  This hashtag does not currently have any videos: ''\nYes: 'Jā'\nNo: 'Nē'\nOk: 'Labi'\nSearch character limit: Meklējamā frāze pārsniedz {searchCharacterLimit} simbolu ierobežojumu\nFeed:\n  Refresh Feed: Atsvaidzini {subscriptionName}\n  Feed Last Updated: '{feedName} barotne pēdējoreiz atjaunināta: {date}'\nGo to page: Iet uz {page}\nClose Banner: Aizvērt karogu\nSearch Listing:\n  Label:\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Jauns\n    3D: 3D\n    Subtitles: Paraksti\n    Closed Captions: Slēgtie paraksti\n    4K: 4K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Ieslēgt izstrādātāja rīkus\n  Zoom In: Tuvināt\n  Zoom Out: Tālināt\n  Fullscreen: Pilnekrāns\n  Volume Up: Palielināt skaļumu\n  Volume Down: Samazināt skaļumu\ncheckmark: ✓\nCancel: Atcelt\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\nshortcutLabelSeparator: ｜\nDisplay Label: '{label}: {value}'\n"
  },
  {
    "path": "static/locales/ms.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Bahasa Melayu'\n\n# Webkit Menu Bar\nFile: 'Fail'\nNew Window: 'Tetingkap baru'\nPreferences: 'Pilihan'\nQuit: 'Keluar'\nEdit: 'Edit'\nUndo: ''\nRedo: ''\nCut: ''\nCopy: ''\nPaste: ''\nDelete: ''\nSelect all: ''\nToggle Developer Tools: ''\nActual size: ''\nZoom in: ''\nZoom out: ''\nToggle fullscreen: ''\nWindow: ''\nMinimize: ''\nClose: ''\nCompact side navigation: ''\nExpand side navigation: ''\nBack: ''\nForward: ''\nRight-click or hold to see history: ''\nOpen New Window: ''\nGo to page: ''\nClose Banner: ''\n\nVersion {versionNumber} is now available!  Click for more details: ''\nDownload From Site: ''\nA new blog is now available, {blogTitle}. Click to view more: ''\nAre you sure you want to open this link?: ''\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: ''\n  Shorts: ''\n  Live: ''\n  Posts: ''\n  Sort By: ''\n  Counts:\n    Video Count: ''\n    Channel Count: ''\n    Subscriber Count: ''\n    View Count: ''\n    Like Count: ''\n    Comment Count: ''\n    Watching Count: ''\n\n# Search Bar\nSearch / Go to URL: ''\nSearch Bar:\n  Clear Input: ''\n  Remove: ''\nSearch character limit: ''\nSearch Listing:\n  Label:\n    4K: ''\n    8K: ''\n    VR180: ''\n    360 Video: ''\n    Subtitles: ''\n    New: ''\n    3D: ''\n    # Aria labels\n    Closed Captions: ''\n  # In Filter Button\nSearch Filters:\n  Search Filters: ''\n  Sort By:\n    Most Relevant: ''\n    Rating: ''\n    Upload Date: ''\n    View Count: ''\n  Time:\n    Time: ''\n    Any Time: ''\n    Last Hour: ''\n    Today: ''\n    This Week: ''\n    This Month: ''\n    This Year: ''\n  Type:\n    Type: ''\n    All Types: ''\n    Videos: ''\n    Channels: ''\n    Movies: ''\n    #& Playlists\n  Duration:\n    Duration: ''\n    All Durations: ''\n    Short (< 4 minutes): ''\n    Medium (4 - 20 minutes): ''\n    Long (> 20 minutes): ''\n  Features:\n    Features: ''\n    HD: ''\n    Subtitles: ''\n    Creative Commons: ''\n    3D: ''\n    Live: ''\n    4K: ''\n    360 Video: ''\n    Location: ''\n    HDR: ''\n    VR180: ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n  Clear Filters: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Sports: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Export Playlist: ''\n  Export list of URLs: ''\n  The playlist has been successfully exported: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  TotalTimePlaylist: \"\"\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      Video has been removed. Click here to undo.: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n\n      This playlist has a video with a duration error: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\n  DateOldestHistory: ''\n  DateNewestHistory: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Minimize to system tray: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Latte: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n      Everforest Dark Hard: ''\n      Everforest Dark Medium: ''\n      Everforest Dark Low: ''\n      Everforest Light Hard: ''\n      Everforest Light Medium: ''\n      Everforest Light Low: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Latte Mauve: ''\n      Catppuccin Latte Red: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n      Everforest Dark Red: ''\n      Everforest Dark Orange: ''\n      Everforest Dark Yellow: ''\n      Everforest Dark Green: ''\n      Everforest Dark Aqua: ''\n      Everforest Dark Blue: ''\n      Everforest Dark Purple: ''\n      Everforest Light Red: ''\n      Everforest Light Orange: ''\n      Everforest Light Yellow: ''\n      Everforest Light Green: ''\n      Everforest Light Aqua: ''\n      Everforest Light Blue: ''\n      Everforest Light Purple: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Autoplay Playlists: ''\n    Autoplay Videos: ''\n    Turn on Subtitles by Default: ''\n    Proxy Videos Through Invidious: ''\n    Default Viewing Mode:\n      Theater: ''\n      Default Viewing Mode: ''\n      Full Screen: ''\n      Picture in Picture: ''\n      External Player: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Remember Search History: ''\n    Save Watched Progress: ''\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: ''\n        Semi-auto: ''\n        Never: ''\n      Tooltip: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search History and Cache: ''\n    Are you sure you want to clear out your search history and cache?: ''\n    Search history and cache have been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Videos on Watch: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Posts: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Channel Courses: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Hide Subscriptions Posts: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Search history file: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Search history: ''\n    Import search history: ''\n    Export search history: ''\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    All search history has been successfully imported: ''\n    All search history has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Proxy Username: ''\n    Proxy Password: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Hide Uploader on Watch page: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: ''\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  Courses:\n    Courses: ''\n    This channel does not currently have any courses: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Watched Progress: ''\n  Watched Progress Saved: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Autoplay is off: ''\n    Autoplay is on: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Post: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  Hide {replyCount} replies: ''\n  View 1 reply from {channelName}: ''\n  View {replyCount} replies from {channelName} and others: ''\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos on Watch: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nshortcutLabelSeparator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: ''\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: ''\n  Reset Zoom: ''\n  Zoom In: ''\n  Zoom Out: ''\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n  Home: ''\n  End: ''\n  Skip to Next Video: ''\n  Skip to Previous Video: ''\n"
  },
  {
    "path": "static/locales/my.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'မြန်မာ'\n\n# Webkit Menu Bar\nFile: 'ဖိုင်'\nNew Window: 'ဝင်းဒိုး အသစ်'\nPreferences: 'စိတ်ကြိုက်ဦးစားပေးများ'\nQuit: ''\nEdit: 'ပြင်ရန်'\nUndo: 'လုပ်ဆောင်ချက် ဖျက်သိမ်းရန်'\nRedo: 'ပြန်လုပ်ရန်'\nCut: 'ဖြတ်ရန်'\nCopy: 'ကူးသည်'\nPaste: 'ကူးထည့်ရန်'\nDelete: 'ဖျက်ရန်'\nSelect all: 'အားလုံးကိုရွေးချယ်ပါ'\nToggle Developer Tools: ''\nActual size: 'ပုံမှန် အရွယ်အစား'\nZoom in: 'ဇူးမ်ချဲ့ရန်'\nZoom out: 'ဇူးမ်ချုံ့ရန်'\nToggle fullscreen: 'စခရင်အပြည့် ပြောင်းရန်'\nWindow: 'ဝင်းဒိုး'\nMinimize: 'ချုံ့ရန်'\nClose: 'ပိတ်ပါ'\nBack: ''\nForward: ''\nRight-click or hold to see history: ''\nOpen New Window: ''\nGo to page: ''\nClose Banner: ''\n\nVersion {versionNumber} is now available!  Click for more details: ''\nDownload From Site: ''\nA new blog is now available, {blogTitle}. Click to view more: ''\nAre you sure you want to open this link?: ''\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'ဗီဒီယိုများ'\n  Shorts: ''\n  Live: 'တိုက်ရိုက်လွှင့်နေသော'\n  Posts: 'ို့စ်'\n  Counts:\n    Video Count: ''\n    Channel Count: ''\n    Subscriber Count: ''\n    View Count: ''\n    Like Count: ''\n    Comment Count: ''\n    Watching Count: ''\n\n# Search Bar\nSearch / Go to URL: ''\nSearch Bar:\n  Clear Input: ''\nSearch character limit: ''\nSearch Listing:\n  Label:\n    4K: ''\n    8K: ''\n    VR180: ''\n    360 Video: ''\n    Subtitles: ''\n    New: ''\n    3D: ''\n    # Aria labels\n    Closed Captions: ''\n  # In Filter Button\nSearch Filters:\n  Search Filters: ''\n  Sort By:\n    Most Relevant: ''\n    Rating: ''\n    Upload Date: ''\n    View Count: ''\n  Time:\n    Time: ''\n    Any Time: ''\n    Last Hour: ''\n    Today: ''\n    This Week: ''\n    This Month: ''\n    This Year: ''\n  Type:\n    Type: ''\n    All Types: ''\n    Videos: ''\n    Channels: ''\n    Movies: ''\n    #& Playlists\n  Duration:\n    Duration: ''\n    All Durations: ''\n    Short (< 4 minutes): ''\n    Medium (4 - 20 minutes): ''\n    Long (> 20 minutes): ''\n  Features:\n    Features: ''\n    HD: ''\n    Subtitles: ''\n    Creative Commons: ''\n    3D: ''\n    Live: ''\n    4K: ''\n    360 Video: ''\n    Location: ''\n    HDR: ''\n    VR180: ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Export Playlist: ''\n  The playlist has been successfully exported: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n\n      This playlist has a video with a duration error: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Turn on Subtitles by Default: ''\n    Autoplay Videos: ''\n    Proxy Videos Through Invidious: ''\n    Autoplay Playlists: ''\n    Enable Theatre Mode by Default: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Save Watched Progress: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search Cache: ''\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Export Playlists For Older FreeTube Versions:\n      Label: ''\n      # |- = Keep newlines, No newline at end\n      Tooltip: |\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: 'အားလုံးကိုရွေးချယ်ပါ'\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\n    Viewing Posts Only Supported By Invidious: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: 'ယခင်'\n  Next: 'ရှေ့သို့'\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: 'စခရင်အပြည့် ပြောင်းရန်'\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: ''\n  Reset Zoom: ''\n  Zoom In: 'ဇူးမ်ချဲ့ရန်'\n  Zoom Out: 'ဇူးမ်ချုံ့ရန်'\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n"
  },
  {
    "path": "static/locales/nb-NO.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Norsk bokmål'\n\n# Webkit Menu Bar\nFile: 'Fil'\nQuit: 'Avslutt'\nEdit: 'Rediger'\nUndo: 'Angre'\nRedo: 'Gjenta'\nCut: 'Klipp ut'\nCopy: 'Kopier'\nPaste: 'Lim inn'\nDelete: 'Slett'\nSelect all: 'Velg alt'\nToggle Developer Tools: 'Utviklerverktøy'\nActual size: 'Faktisk størrelse'\nZoom in: 'Zoom inn'\nZoom out: 'Zoom ut'\nToggle fullscreen: 'Fullskjermsvisning'\nWindow: 'Vindu'\nMinimize: 'Minimer'\nClose: 'Lukk'\nBack: 'Tilbake'\nForward: 'Framover'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videoer'\n  Shorts: Shorts-videoer\n  Live: Direktesendinger\n  Posts: Innlegg\n  Sort By: Sorter etter\n\n# Search Bar\n  Counts:\n    Subscriber Count: 1 abonnent | {count} abonnenter\n    Watching Count: 1 seer | {count} seere\n    Channel Count: 1 kanal | {count} kanaler\n    Comment Count: 1 kommentar | {count} kommentarer\n    Video Count: 1 video | {count} videoer\n    View Count: 1 visning | {count} visninger\n    Like Count: 1 liker | {count} liker\nSearch / Go to URL: 'Søk / gå til nettadresse'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Søkefiltre'\n  Sort By:\n    Most Relevant: 'Mest relevant'\n    Rating: 'Vurdering'\n    Upload Date: 'Opplastingsdato'\n    View Count: 'Visninger'\n  Time:\n    Time: 'Tid'\n    Any Time: 'Når som helst'\n    Last Hour: 'Den siste timen'\n    Today: 'I dag'\n    This Week: 'Denne uken'\n    This Month: 'Denne måneden'\n    This Year: 'Dette året'\n  Type:\n    Type: 'Type'\n    All Types: 'Alle typer'\n    Videos: 'Videoer'\n    Channels: 'Kanaler'\n    #& Playlists\n    Movies: Filmer\n  Duration:\n    Duration: 'Varighet'\n    All Durations: 'Alle varigheter'\n    Short (< 4 minutes): 'Kort (< 4 minutter)'\n    Long (> 20 minutes): 'Lang (> 20 minutter)'\n  # On Search Page\n    Medium (4 - 20 minutes): Middels (4–20 minutter)\n  Search Results: 'Søkeresultater'\n  Fetching results. Please wait: 'Henter resultater. Vennligst vent'\n  Fetch more results: 'Hent flere resultater'\n# Sidebar\n  There are no more results for this search: Søket ga ingen flere resultater\n  Features:\n    HD: HD\n    VR180: VR180\n    Subtitles: Underskrifter\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Direktesendt\n    4K: 4K\n    Location: Sted\n    HDR: HDR\n    Features: Funksjoner\n    360 Video: 360 Video\n  Clear Filters: Tilbakestill filtere\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnementer'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Du har ikke lagt til noen abonnementer i listen din. Hvis du vil importere abonnementene dine, kan du gå til «Datainnstillinger» og velge «Importer abonnementer», eller så kan du søke etter en kanal og abonnere på dem.'\n  Load More Videos: Last inn flere videoer\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Denne profilen har mange abonnementer. Tvinger bruk av RSS for å unngå adgangsbegrensning\n  Error Channels: Kanaler med feil\n  Disabled Automatic Fetching: Du har skrudd av automatisk innhenting av abonnementer. Gjenoppfrisk abonnementer for å se dem her.\n  Empty Channels: De kanalene du abonnerer på har for øyeblikket ingen videoer.\n  Subscriptions Tabs: Abonnementsfaner\n  All Subscription Tabs Hidden: Alle abonnementsfaner er skjult. For å vise innhold her, opphev skjuling av noen faner i «{subsection}»-delen av «{settingsSection}».\n  Empty Posts: Kanalene du abonnerer på, har ikke noen innlegg for øyeblikket.\n  Load More Posts: Last inn flere poster\nTrending:\n  Trending: 'På vei opp'\n  Trending Tabs: På vei opp-faner\n  Gaming: Videospill\n  Sports: Sport\nMost Popular: 'Mest populære'\nPlaylists: 'Spillelister'\nUser Playlists:\n  Your Playlists: 'Dine spillelister'\n  Empty Search Message: Ingen videoer i denne spillelisten samsvarer med søket ditt\n  Search bar placeholder: Søk etter spillelister\n  SinglePlaylistView:\n    Toast:\n      This playlist does not exist: Denne spillelisten finnes ikke\n      This video cannot be moved down.: Denne videoen kan ikke bli flyttet ned.\n      Video has been removed: Videoen har blitt fjernet\n      There were no videos to remove.: Det var ingen videoer å fjerne.\n      There was an issue with updating this playlist.: Det oppstod et problem ved oppdateringen av denne spillelisten.\n      \"{videoCount} video(s) have been removed\": 1 video har blitt fjernet | {videoCount} videoer har blitt fjernet\n      Playlist has been updated.: Spillelisten har blitt endret.\n      There was a problem with removing this video: Det oppstod et problem ved fjerningen av denne videoen\n      This video cannot be moved up.: Denne videoen kan ikke bli flyttet opp.\n      Playlist {playlistName} has been deleted.: Spillelisten {playlistName} har blitt slettet.\n      This playlist is protected and cannot be removed.: Denne spillelisten er beskyttet og kan derfor ikke fjernes.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Noen av videoene i spillelisten har ikke blitt lastet inn skikkelig, enda. Trykk her for å kopiere alikevel.\n      Playlist name cannot be empty. Please input a name.: Spillelisten må ha et navn. Vennligst gi den et navn.\n      This playlist is now used for quick bookmark: Denne spillelisten blir nå brukt for hurtigbokmerket\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Denne spillelisten blir nå brukt for hurtigbokmerket istedenfor {oldPlaylistName}. Klikk her for å angre\n      Reverted to use {oldPlaylistName} for quick bookmark: Satt tilbake til å bruke {oldPlaylistName} for hurtigbokmerket\n      This playlist has a video with a duration error: Denne spillelisten inneholder minst en video som ikke har en lengde. Den blir sortert som om lengden dens er null.\n      Video has been removed. Click here to undo.: Videoen har blitt fjernet. Klikk her for å angre.\n      This playlist is already being used for quick bookmark.: Denne spillelisten er allerede i bruk for hurtigbokmerket.\n    Search for Videos: Søk etter videoer\n  AddVideoPrompt:\n    Allow Adding Duplicate Video(s): Tillat å legge til dupliserte videoer\n    Search in Playlists: Søk i spillelister\n    Save: Lagre\n    N playlists selected: '{playlistCount} valgt'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} videoer vil bli lagt til'\n    Toast:\n      You haven't selected any playlist yet.: Du har ikke valgt noen spillelister enda.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(er) lagt til 1 spilleliste | Video(er) lagt til {playlistCount} spillelister\"\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} videoer allerede lagt til'\n    Added {count} Times: Allerede lagt til | Lagt til {count} ganger\n    Select a playlist to add your N videos to: Velg en spilleliste å legge videoen til | Velg en spilleliste å legge dine {videoCount} videoer til\n  Cancel: Avbryt\n  Add to Playlist: Legg til i spilleliste\n  This playlist currently has no videos.: Denne spillelisten har ingen videoer for øyeblikket.\n  Export Playlist: Eksporter denne spillelisten\n  Sort By:\n    EarliestCreatedFirst: Opprettelsesdato (eldste)\n    EarliestUpdatedFirst: Oppdateringsdato (eldste)\n    LatestPlayedFirst: Dato spilt av (nyeste)\n    EarliestPlayedFirst: Dato spilt av (eldste)\n    LatestUpdatedFirst: Oppdateringsdato (nyeste)\n    NameAscending: A-Å\n    NameDescending: Å-A\n    LatestCreatedFirst: Opprettelsesdato (nyeste)\n  Add to Favorites: Legg til {playlistName}\n  Move Video Up: Flytt video opp\n  Move Video Down: Flytt video ned\n  Playlist Description: Beskrivelse på spilleliste\n  Save Changes: Lagre endringer\n  Copy Playlist: Kopier spilleliste\n  Playlist Name: Spillelistenavn\n  Remove Watched Videos: Fjern sette videoer\n  Playlists with Matching Videos: Spillelister med videoer som matcher\n  Create New Playlist: Opprett ny spilleliste\n  Remove from Favorites: Fjern fra {playlistName}\n  The playlist has been successfully exported: Spillelisten ble eksportert\n  Delete Playlist: Slett spilleliste\n  CreatePlaylistPrompt:\n    Create: Opprett\n    New Playlist Name: Nytt navn på spilleliste\n    Toast:\n      There was an issue with creating the playlist.: Det oppstod et problem ved opprettelsen av spillelisten.\n      There is already a playlist with this name. Please pick a different name.: Det finnes allerede en spilleliste med det navnet. Vennligst velg et annet navn.\n      Playlist {playlistName} has been successfully created.: Spillelisten {playlistName} har blitt opprettet.\n  Edit Playlist Info: Endre spillelisteinfo\n  Remove Duplicate Videos: Fjern duplikatvideoer\n  Remove from Playlist: Fjern fra spilleliste\n  You have no playlists. Click on the create new playlist button to create a new one.: Du har ingen spillelister. Trykk på knappen for å lage en ny.\n  Are you sure you want to delete this playlist? This cannot be undone: Er du sikker på at du vil fjerne denne spillelisten? Dette kan ikke bli omgjort.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Er du sikker på at du vil fjerne en duplikatvideo fra denne spillelisten? Dette kan ikke bli omgjort. | Er du sikker på at du vil fjerne {playlistItemCount} duplikate videoer fra denne spillelisten? Denne kan ikke bli omgjort.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Er du sikker på at du vil fjerne 1 sett video fra denne spillelisten? Dette kan ikke bli omgjort. | Er du sikker på at du vil fjerne {playlistItemCount} sette videoer fra denne spillelisten? Dette kan ikke bli omgjort.\n  Cannot delete the quick bookmark target playlist.: Kan ikke slette spillelisten til hurtigbokmerket.\n  Enable Quick Bookmark With This Playlist: Slå på hurtigbokmerket med denne spillelisten\n  Quick Bookmark Enabled: Hurtigbokmerket aktivert\n  TotalTimePlaylist: 'Total tid: {duration}'\n  Export list of URLs: Eksporter liste over URL-er\nHistory:\n  # On History Page\n  History: 'Historikk'\n  Watch History: 'Visningshistorikk'\n  Your history list is currently empty.: 'Din historikk er for øyeblikket tom.'\n  Empty Search Message: Ingen videoer i historikken din samsvarer med søket ditt\n  Search bar placeholder: Søk i historikken\n  Case Sensitive Search: Søket skiller mellom store og små bokstaver\n  DateOldestHistory: Dato sett (eldste)\n  DateNewestHistory: Dato sett (nyeste)\nSettings:\n  # On Settings Page\n  Settings: 'Innstillinger'\n  General Settings:\n    General Settings: 'Generelle'\n    Fallback to Non-Preferred Backend on Failure: 'Tilbakefall til alternativ bakende ved feil'\n    Enable Search Suggestions: 'Slå på søkeforslag'\n    Default Landing Page: 'Standard landingsside'\n    Locale Preference: 'Språkinnstillinger'\n    Preferred API Backend:\n      Preferred API Backend: 'Foretrukket API-bakende'\n      Local API: 'Lokalt API'\n      Invidious API: 'Invidious-API'\n    Video View Type:\n      Video View Type: 'Videovisningstype'\n      Grid: 'Rutenett'\n      List: 'Liste'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Innstillinger for miniatyrbilder'\n      Default: 'Standard'\n      Beginning: 'Begynnelsen'\n      Middle: 'Midten'\n      End: 'Slutten'\n      Hidden: Skjult\n      Blur: Uskarpt\n    Region for Trending: 'Region for «På vei opp»'\n        #! List countries\n    Check for Updates: Se etter oppdateringer\n    View all Invidious instance information: Vis informasjon om alle Invidious-instanser\n    Check for Latest Blog Posts: Vis nye blogginnlegg\n    System Default: Standardinnstillinger\n    Clear Default Instance: Fjern standardinstans\n    Set Current Instance as Default: Bruk den gjeldende instansen som standard\n    Current instance will be randomized on startup: Den valgte instansen vil bli valgt tilfeldig ved oppstart\n    No default instance has been set: Ingen standard instans har blitt valgt\n    The currently set default instance is {instance}: Valgt instans er {instance}\n    Current Invidious Instance: Gjeldende Invidious-instans\n    External Link Handling:\n      No Action: Ingen handling\n      Ask Before Opening Link: Spør før lenker åpnes\n      Open Link: Åpne lenke\n      External Link Handling: Håndtering av eksterne lenker\n    Auto Load Next Page:\n      Label: Last inn den neste siden automatisk\n      Tooltip: Last inn flere sider og kommentarer automatisk.\n    Open Deep Links In New Window: Åpne linker sendt til FreeTube i et nytt vindu\n    Minimize to system tray: Minimer til systemkurven\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Tilpass topplinjen slik at den har samme farge som hovedfargen'\n    Base Theme:\n      Base Theme: 'Hovedtema'\n      Black: 'Svart'\n      Dark: 'Mørk'\n      Light: 'Lys'\n      Dracula: 'Dracula'\n      System Default: Systemstandard\n      Catppuccin Mocha: Catppuccin-mokka\n      Pastel Pink: Pastellrosa\n      Nordic: Nordisk\n      Gruvbox Light: Gruvbox lys\n      Gruvbox Dark: Gruvbox mørk\n      Solarized Dark: Solarisert mørk\n      Catppuccin Frappe: Catppuccin-frappe\n      Solarized Light: Solarisert lys\n      Hot Pink: Varm rosa\n      Everforest Light Hard: Everforest hard og lys\n      Everforest Dark Low: Everforest lav og mørk\n      Everforest Dark Hard: Everforest hard og mørk\n      Everforest Dark Medium: Everforest medium og mørk\n      Everforest Light Medium: Everforest medium og lys\n      Everforest Light Low: Everforest lav og lys\n      Catppuccin Latte: Catppuccin-latte\n    Main Color Theme:\n      Main Color Theme: 'Hovedfarge'\n      Red: 'Rød'\n      Pink: 'Rosa'\n      Purple: 'Lilla'\n      Deep Purple: 'Mørkelilla'\n      Indigo: 'Indigo'\n      Blue: 'Blå'\n      Light Blue: 'Lyseblå'\n      Cyan: 'Cyanblå'\n      Teal: 'Blågrønn'\n      Green: 'Grønn'\n      Light Green: 'Lysegrønn'\n      Lime: 'Lime'\n      Yellow: 'Gul'\n      Amber: 'Ravgul'\n      Orange: 'Oransje'\n      Deep Orange: 'Dyp oransje'\n      Dracula Cyan: 'Dracula Cyanblå'\n      Dracula Green: 'Dracula Grønn'\n      Dracula Orange: 'Dracula Oransje'\n      Dracula Pink: 'Dracula Rosa'\n      Dracula Purple: 'Dracula Lilla'\n      Dracula Red: 'Dracula Rød'\n      Dracula Yellow: 'Dracula Gul'\n      Catppuccin Mocha Flamingo: Catppuccin-mokka-flamingo\n      Catppuccin Mocha Pink: Catppuccin-mokka-rosa\n      Catppuccin Mocha Mauve: Catppuccin-mokka-blålilla\n      Catppuccin Mocha Red: Catppuccin-mokka-rød\n      Catppuccin Mocha Maroon: Catppuccin-mokka-kastanjebrun\n      Catppuccin Mocha Peach: Catppuccin-mokka-fersken\n      Catppuccin Mocha Yellow: Catppuccin-mokka-gul\n      Catppuccin Mocha Lavender: Catppuccin-mokka-lavendel\n      Catppuccin Mocha Sapphire: Catppuccin-mokka-saffir\n      Catppuccin Mocha Blue: Catppuccin-mokka-blå\n      Catppuccin Mocha Sky: Catppuccin-mokka-himmelblå\n      Catppuccin Mocha Green: Catppuccin-mokka-grønn\n      Catppuccin Mocha Teal: Catppuccin-mokka-blågrønn\n      Catppuccin Mocha Rosewater: Catppuccin-mokka-rosévann\n      Solarized Yellow: Solarisert gul\n      Solarized Orange: Solarisert oransje\n      Solarized Red: Solarisert rød\n      Solarized Magenta: Solarisert magenta\n      Solarized Cyan: Solarisert cyan\n      Solarized Blue: Solarisert blå\n      Solarized Green: Solarisert grønn\n      Solarized Violet: Solarisert fiolett\n      Catppuccin Frappe Red: Catppuccin-frappe-rød\n      Catppuccin Frappe Maroon: Catppuccin-frappe-rødbrun\n      Catppuccin Frappe Teal: Catppuccin-frappe-blågrønn\n      Catppuccin Frappe Sky: Catppuccin-frappe-himmelblå\n      Catppuccin Frappe Sapphire: Catppuccin-frappe-safirblå\n      Gruvbox Dark Yellow: Gruvbox-mørkegul\n      Gruvbox Light Red: Gruvbox-lyserød\n      Gruvbox Light Blue: Gruvbox-lyseblå\n      Gruvbox Light Purple: Gruvbox-lyselilla\n      Catppuccin Frappe Yellow: Catppuccin-frappe-gul\n      Gruvbox Dark Green: Gruvbox-mørkegrønn\n      Gruvbox Light Orange: Gruvbox-lyseoransje\n      Gruvbox Dark Orange: Gruvbox-mørkeoransje\n      Catppuccin Frappe Pink: Catppuccin-frappe-rosa\n      Catppuccin Frappe Flamingo: Catppuccin-frappe Flamingo\n      Catppuccin Frappe Mauve: Catppuccin-frappe-fiolett\n      Catppuccin Frappe Peach: Catppuccin-frappe-fersken\n      Catppuccin Frappe Green: Catppuccin-frappe-grønn\n      Catppuccin Frappe Blue: Catppuccin-frappe-blå\n      Catppuccin Frappe Lavender: Catppuccin-frappe-lavendel\n      Everforest Dark Yellow: Everforest-mørkegul\n      Everforest Dark Green: Everforest-mørkegrønn\n      Everforest Dark Aqua: Everforest-mørkaqua\n      Everforest Dark Blue: Everforest-mørkeblå\n      Everforest Dark Purple: Everforest-mørkelilla\n      Everforest Light Red: Everforest-lyserød\n      Everforest Light Orange: Everforest-lyseoransje\n      Everforest Light Yellow: Everforest-lysegul\n      Everforest Light Green: Everforest-lysegrønn\n      Catppuccin Frappe Rosewater: Catppuccin-frappe-rosevann\n      Gruvbox Dark Blue: Gruvbox-mørkeblå\n      Gruvbox Dark Purple: Gruvbox-mørkelilla\n      Gruvbox Dark Aqua: Gruvbox-mørkaqua\n      Everforest Dark Red: Everforest-mørkerød\n      Everforest Dark Orange: Everforest-mørkeoransje\n      Everforest Light Aqua: Everforest-lysaqua\n      Everforest Light Blue: Everforest-lyseblå\n      Everforest Light Purple: Everforest-lyselilla\n      Catppuccin Latte Mauve: Catppuccin-latte-fiolett\n      Catppuccin Latte Red: Catppuccin-latte-rød\n    Secondary Color Theme: 'Sekundærfarge'\n        #* Main Color Theme\n    UI Scale: Grensesnittskalering\n    Disable Smooth Scrolling: Slå av jevn skrolling\n    Expand Side Bar by Default: Utvidet sidefelt som standard\n    Hide Side Bar Labels: Skjul etiketter i sidefeiltet\n    Hide FreeTube Header Logo: Skjul FreeTubes tittel og logo\n  Player Settings:\n    Player Settings: 'Videoavspiller'\n    Play Next Video: 'Spill av neste anbefalte video automatisk'\n    Turn on Subtitles by Default: 'Skru på undertekster som standard'\n    Autoplay Videos: 'Start videoer automatisk'\n    Proxy Videos Through Invidious: 'Hent videoer gjennom Invidious-proxy'\n    Autoplay Playlists: 'Spill av videoer i spillelister automatisk'\n    Enable Theatre Mode by Default: 'Kinomodus som forvalg'\n    Default Volume: 'Standardvolum'\n    Default Playback Rate: 'Standard avspillingshastighet'\n    Default Video Format:\n      Default Video Format: 'Standard videoformat'\n      Dash Formats: 'DASH-formater'\n      Legacy Formats: 'Gamle formater'\n      Audio Formats: 'Lydformater'\n    Default Quality:\n      Default Quality: 'Standardkvalitet'\n      Auto: 'Automatisk'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Nedtelling mellom videoer\n    Scroll Volume Over Video Player: Juster volum ved å rulle over videospilleren\n    Display Play Button In Video Player: Vis avspillingsknappen i videoavspilleren\n    Fast-Forward / Rewind Interval: Intervall for spoling frem og tilbake\n    Screenshot:\n      File Name Label: Filnavnsmønster\n      Error:\n        Forbidden Characters: Forbudte tegn\n        Empty File Name: Tomt filnavn\n      Enable: Aktiver skjermbilde\n      Folder Label: Skjermbildemappe\n      Folder Button: Velg mappe\n      Format Label: Skjermbildeformat\n      Quality Label: Skjermbildekvalitet\n      Ask Path: Spør om hvor ting skal lagres\n      File Name Tooltip: Du kan bruke variablene nedenfor. %Y år, i 4 siffer. %M måned, i 2 siffer. %D dag, i to siffer. %H time, i to siffer. %N minutt, i to siffer. %s sekund, i to siffer. %T millisekunder, i tre siffer. %s videosekund. %t videomillisekunder, i tre siffer. %i video-ID.\n    Max Video Playback Rate: Maksimal hastighet for videoavspilling\n    Scroll Playback Rate Over Video Player: Juster avspillingshastighet ved rulling over videoavspiller\n    Video Playback Rate Interval: Intervall for videoavspillingshastighet\n    Enter Fullscreen on Display Rotate: Bytt til fullskjermsvisning når skjermen roteres\n    Skip by Scrolling Over Video Player: Hopp over ved å rulle over videoavspiller\n    Default Viewing Mode:\n      Default Viewing Mode: Standard visningsmodus\n      Full Screen: Fullskjerm\n      Theater: Teater\n      Picture in Picture: Bilde-i-bilde\n      External Player: Ekstern avspiller ({externalPlayerName})\n    Autoplay Interruption Timer: Automatisk avspilling avbruddstidtaker\n  Privacy Settings:\n    Privacy Settings: 'Personvern'\n    Remember History: 'Husk visningshistorikk'\n    Save Watched Progress: 'Husk avspillingsposisjon'\n    Clear Search Cache: 'Tøm hurtiglager for søk'\n    Are you sure you want to clear out your search cache?: 'Er du sikker på at du vil tømme hurtiglageret for søk?'\n    Search cache has been cleared: 'Hurtiglageret for søk har blitt tømt'\n    Remove Watch History: 'Fjern visningshistorikk'\n    Are you sure you want to remove your entire watch history?: 'Er du sikker på at du vil tømme hele visningshistorikken din?'\n    Watch history has been cleared: 'Visningshistorikken har blitt tømt'\n    Remove All Subscriptions / Profiles: Fjern alle abonnementer/profiler\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Er du sikker på at du vil fjerne alle abonnementer og profiler? Dette kan ikke bli omgjort.\n    Save Watched Videos With Last Viewed Playlist: Lagre sette videoer med sist sette spilleliste\n    Remove All Playlists: Fjern alle spillelister\n    Are you sure you want to remove all your playlists?: Er du sikker på at du vil fjerne alle spillelistene dine?\n    All playlists have been removed: Alle spillelister har blitt fjernet\n    Remember Search History: Husk søkshistorikk\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automatisk\n        Semi-auto: Halvautomatisk\n        Never: Aldri\n      Tooltip: Automatisk = Lagre for hver enkelt video når den lukkes, avsluttes og når en feil oppstår (f.eks ved tilgangsbegrensning eller sesjonen din utløper). Halvautomatisk = Som automatisk utenom at det ikke skjer når en video lukkes som vanlig, og man kan lagre det manuelt med en egen knapp under videoavspilleren.\n    Clear Search History and Cache: Tøm søkshistorikken og mellomlageret\n    Are you sure you want to clear out your search history and cache?: Er du sikker på at du vil tømme søkshistorikken og mellomlageret?\n    Search history and cache have been cleared: Søkshistorikken og mellomlageret har blitt tømt\n  Subscription Settings:\n    Subscription Settings: 'Abonnementer'\n    Fetch Feeds from RSS: Hent informasjonskanaler via RSS\n    Fetch Automatically: Hent informasjonskanaler automatisk\n\n    Confirm Before Unsubscribing: Bekreft avslutning av abonnement\n    'Limit the number of videos displayed for each channel': Begrens antallet videoer vist for hver kanal\n    To: Til\n  Data Settings:\n    How do I import my subscriptions?: Hvordan importerer jeg abonnementene mine?\n    Unknown data key: Ukjent datanøkkel\n    Unable to write file: Kunne ikke skrive fil\n    Invalid history file: Ugyldig historikkfil\n    All watched history has been successfully exported: All visningshistorikk har blitt eksportert\n    All watched history has been successfully imported: All visningshistorikk har blitt importert\n    History object has insufficient data, skipping item: Hopper over historikkobjekt siden det har utilstrekkelig data\n    All subscriptions have been successfully imported: Alle abonnementer har blitt importert\n    All subscriptions and profiles have been successfully imported: Alle abonnementer og profiler har blitt importert\n    Manage Subscriptions: Behandle abonnementer\n    Unable to read file: Kunne ikke lese fil\n    Invalid subscriptions file: Ugyldig abonnementsfil\n    Profile object has insufficient data, skipping item: Hopper over profilobjektet siden det har utilstrekkelig data\n    Subscriptions have been successfully exported: Alle abonnementer har blitt eksportert\n    Export History: Eksporter historikk\n    Import History: Importer historikk\n    Export NewPipe: Eksporter NewPipe\n    Export YouTube: Eksporter YouTube\n    Export FreeTube: Eksporter FreeTube\n    Export Subscriptions: Eksporter abonnementer\n    Import Subscriptions: Importer abonnementer\n    Select Export Type: Velg eksporttype\n    Data Settings: Data\n    All playlists has been successfully imported: Alle spillelister har blitt importert\n    Subscription File: Abonnementsfil\n    History File: Historikkfil\n    Playlist File: Spillelistefil\n    Export Playlists: Eksporter spillelister\n    Import Playlists: Importer spillelister\n    All playlists has been successfully exported: Alle spillelister har blitt eksportert\n    Playlist insufficient data: Utilstrekkelig data i «{playlist}»-spillelisten. Hopper over elementet\n    Export Playlists For Older FreeTube Versions:\n      Label: Eksporter spillelister for eldre FreeTube-versjoner\n      Tooltip: \"Denne funksjonen eksporterer videoer fra alle spillelister inn i en spilleliste med navnet «Favoritter».\\nFor å eksportere og importere videoer i spillelister i eldre versjoner av FreeTube:\\n1.) Eksporter spillelistene dine med denne funksjonen skrudd på.\\n2.) Slett alle spillelistene dine med «Fjern alle spillelister» under «Personvern».\\n3.) Start opp den eldre versjonen av FreeTube og importer de eksporterte spillelistene dine.\"\n    Search history file: Søkshistorikkfil\n    Search history: Søkshistorikk\n    Import search history: Importer søkshistorikk\n    Export search history: Eksporter søkshistorikk\n    All search history has been successfully imported: Søkshistorikken har blitt importert\n    All search history has been successfully exported: Søkshistorikken har blitt eksportert\n  Proxy Settings:\n    Region: Region\n    Clicking on Test Proxy will send a request to: Klikk på «Test mellomtjener» for å sende en forespørsel til\n    Error getting network information. Is your proxy configured properly?: Kunne ikke hente nettverksinformasjon. Er mellomtjeneren din satt opp riktig?\n    Test Proxy: Test mellomtjener\n    City: By\n    Country: Land\n    Ip: IP-adresse\n    Your Info: Din informasjon\n    Proxy Port Number: Mellomtjener-portnummer\n    Proxy Host: Mellomtjenervert\n    Proxy Protocol: Mellomtjenerprotokoll\n    Enable Tor / Proxy: Skru på Tor / mellomtjener\n    Proxy Settings: Mellomtjener (proxy)\n    Proxy Warning: FreeTube har ikke en innebygd mellomtjener (proxy), men det kan koble til en ekstern en, for eksempel en som kjører på din egen maskin, som Tor, eller en ekstern mellomtjener som SOCKS5 som tilbys av enkelte VPN-er. Hvis dette skrus på, pass på at mellomtjeneren din er konfigurert riktig; hvis ikke kommer ikke FreeTube til å klare å hente noen data.\n    Proxy Username: Mellomtjener-brukernavn\n    Proxy Password: Mellomtjener-passord\n  Distraction Free Settings:\n    Hide Trending Videos: Skjul «På vei opp»\n    Hide Video Likes And Dislikes: Skjul antall liker/ikke liker på videoer\n    Distraction Free Settings: Distraksjonsfri modus\n    Hide Active Subscriptions: Skjul aktive abonnementer\n    Hide Recommended Videos: Skjul anbefalte videoer\n    Hide Comment Likes: Skjul antall liker på kommentarer\n    Hide Channel Subscribers: Skjul kanalabonnementer\n    Hide Popular Videos: Skjul «Mest populære»\n    Hide Video Views: Skjul videovisninger\n    Hide Live Chat: Skjul direktechat\n    Hide Playlists: Skjul spillelister\n    Hide Comments: Skjul kommentarer\n    Hide Live Streams: \"Skjul direktesendinger\"\n    Hide Chapters: Skjul kapitler\n    Hide Channels Placeholder: Kanal-ID\n    Hide Channels: Skjul videoer fra kanaler\n    Hide Sharing Actions: Skjul delingshandlinger\n    Hide Videos on Watch: 'Skjul sette videoer'\n    Hide Upcoming Premieres: Skjul kommende premièrer\n    Hide Video Description: Skjul videobeskrivelse\n    Display Titles Without Excessive Capitalisation: Vis titler uten overdreven bruk av store bokstaver\n    Hide Featured Channels: Skjul fremhevede kanaler\n    Hide Channel Shorts: Skjul «Shorts»-fanen i kanaler\n    Sections:\n      Side Bar: Sidefelt\n      Channel Page: Kanalside\n      General: Generelt\n      Watch Page: Seerlogg\n      Subscriptions Page: Abonnementsside\n    Hide Channel Playlists: Skjul «Spillelister»-fanen i kanaler\n    Hide Channel Releases: Skjul «Utgivelser»-fanen i kanaler\n    Hide Channel Podcasts: Skjul «Podcaster»-fanen i kanaler\n    Hide Subscriptions Videos: Skjul abonnementsvideoer\n    Hide Subscriptions Shorts: Skjul Shorts\n    Hide Subscriptions Live: Skjul abonnements direktesendinger\n    Hide Profile Pictures in Comments: Skjul profilbilder i kommentarfeltet\n    Hide Channel Home: Skjule «Start»-fanen i kanaler\n    Hide Videos, Playlists and Channels Containing Text: Skjul videoer og spillelister som inneholder tekst\n    Hide Channels Already Exists: Kanal-ID-en finnes allerede\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Ord, del av ord eller setning\n    Hide Channels Invalid: Kanal-ID-en var ugyldig\n    Hide Channels Disabled Message: Noen kanaler ble blokkert med ID og ble ikke prosessert. Funksjonen er blokkert mens disse ID-ene blir oppdatert\n    Show Added Items: Vis videoer lagt til\n    Hide Channels API Error: En feil oppsto ved henting av brukeren med den oppgitte ID-en. Vennligst sjekk om ID-en er riktig.\n    Hide Channel Courses: Skjul «Kurs»-fanen i kanaler\n    Hide Subscriptions Posts: Skjul innlegg fra abonnementer\n    Hide Channel Posts: Skjul «Innlegg»-fanen i kanaler\n  The app needs to restart for changes to take effect. Restart and apply change?: Start programmet på nytt for å ta i bruk endringene?\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Gi beskjed når sponsordelen blir hoppet over\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock-API-nettadresse (standard er https://sponsor.ajay.app)\n    Enable SponsorBlock: Skru på SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Do Nothing: Ikke gjør noe\n      Prompt To Skip: Spør om å hoppe over\n      Skip Option: Alternativ for å hoppe over\n      Auto Skip: Hopp over automatisk\n      Show In Seek Bar: Vis i tidslinjen\n    Category Color: Kategorifarge\n    UseDeArrowTitles: Bruk DeArrow-videotitler\n    UseDeArrowThumbnails: Bruk DeArrow for miniatyrbilder\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow miniatyrbildegenerator API-adresse (standard er https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Egendefinerte argumenter for ekstern avspiller\n    Custom External Player Executable: Egendefinert kjørbar fil for ekstern avspiller\n    Ignore Unsupported Action Warnings: Ignorer advarsler om handlinger som ikke er støttet\n    External Player Settings: Ekstern avspiller\n    External Player: Ekstern avspiller\n    Players:\n      None:\n        Name: Ingen\n    Ignore Default Arguments: Ignorer standardargumenter\n  Parental Control Settings:\n    Parental Control Settings: Foreldrekontroll\n    Hide Search Bar: Skjul søkefeltet\n    Show Family Friendly Only: Vis kun familievennlig innhold\n    Hide Unsubscribe Button: Skjul knapp for opphevelse av abonnement\n    Hide Uploader on Watch page: Skjul opplasteren på visningssiden\n  Experimental Settings:\n    Experimental Settings: Eksperimentelt\n    Replace HTTP Cache: Erstatt HTTP-hurtiglager\n    Warning: Disse innstillingene er eksperimentelle, og kan gjøre at programmet krasjer. Det anbefales at du tar kopi av dataene dine. Bruk på egen risiko!\n  Password Settings:\n    Remove Password: Fjern passord\n    Password Settings: Passord\n    Set Password To Prevent Access: Sett et passord for å låse tilgang til innstillingene\n    Set Password: Sett passord\n  Password Dialog:\n    Enter Password To Unlock: Skriv inn passord for å låse opp innstillingene\n    Password: Passord\n  Return to Settings Menu: Gå tilbake til menyen med innstillinger\n  Sort Settings Sections (A-Z): Sorter innstillingsseksjonene (A-Å)\nAbout:\n  #On About page\n  About: 'Om'\n  #& About\n\n  FAQ: OSS\n  Downloads / Changelog: Nedlastninger / Endringslogg\n  Help: Hjelp\n  Donate: Doner\n  Website: Nettsted\n  Report a problem: Rapporter et problem\n  Source code: Kildekode\n  Mastodon: Mastodon\n  Email: E-post\n  Blog: Blogg\n  Translate: Oversett\n  Please check for duplicates before posting: Vennligst sjekk om problemet ditt allerede har blitt sendt inn før du sender inn en melding\n  these people and projects: disse folkene og prosjektene\n  Credits: Bidragsytere\n  room rules: rommreglene\n  GitHub issues: GitHub-problemsporer\n  FreeTube Wiki: FreeTube-wiki\n  GitHub releases: GitHub-utgivelser\n  Beta: Beta\n  Chat on Matrix: Snakk med oss på Matrix\n  Discussions: Diskusjoner\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Lisensiert under {licenseLink}\n  Please read the {roomRulesLink}: Les {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube blir til takket være {creditsPageLink}\nChannel:\n  Subscribe: 'Abonner'\n  Unsubscribe: 'Opphev abonnement'\n  Search Channel: 'Søk i kanal'\n  Your search results have returned 0 results: 'Søktet ditt ga 0 resultater'\n  Videos:\n    Videos: 'Videoer'\n    This channel does not currently have any videos: 'Kanalen har ingen videoer enda'\n    Sort Types:\n      Newest: 'Nyeste'\n      Oldest: 'Eldste'\n      Most Popular: 'Mest populære'\n  Playlists:\n    Playlists: 'Spillelister'\n    This channel does not currently have any playlists: 'Kanalen har ingen spillelister'\n    Sort Types:\n      Last Video Added: 'Siste video lagt til'\n      Newest: 'Nyeste'\n      Oldest: 'Eldste'\n  About:\n    About: 'Om'\n    Channel Description: 'Kanalbeskrivelse'\n    Featured Channels: 'Framhevede kanaler'\n    Tags:\n      Tags: Etiketter\n      Search for: Søk etter «{tag}»\n    Details: Detaljer\n    Joined: Registrert\n    Location: Posisjon\n  Added channel to your subscriptions: Lagt kanal til i dine abonnenter\n  Removed subscription from {count} other channel(s): Fjernet abonnement fra {count} andre kanal(er)\n  Channel has been removed from your subscriptions: Kanalen har blitt fjernet fra dine abonnement\n  This channel does not exist: Denne kanalen finnes ikke\n  This channel does not allow searching: Denne kanalen tillater ikke søk\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Denne kanalen er aldersbegrenset og kan derfor ikke vises i FreeTube.\n  Channel Tabs: Kanalfaner\n  Posts:\n    This channel currently does not have any posts: Denne kanalen har ingen oppføringer\n    Hide Answers: Skjul svar\n    votes: '{votes} stemmer'\n    View Full Post: Se hele innlegget\n    Video hidden by FreeTube: Video skjult av FreeTube\n    Viewing Posts Only Supported By Invidious: Innlegg kan bare vises gjennom Invidious. Gå til kanalens fellesskapside for å se innholdet der uten Invidious.\n    Reveal Answers: Vis svar\n  Shorts:\n    This channel does not currently have any shorts: Denne kanalen har ingen Shorts-videoer\n  Live:\n    Live: Direkte\n    This channel does not currently have any live streams: Denne kanalen har ingen direktesendinger\n  Podcasts:\n    Podcasts: Podcaster\n    This channel does not currently have any podcasts: Denne kanalen har ingen podcaster\n  Releases:\n    Releases: Utgivelser\n    This channel does not currently have any releases: Denne kanalen har ingen utgivelser\n  Home:\n    Home: Hjem\n    View Playlist: Vis spilleliste\n  Courses:\n    Courses: Kurs\n    This channel does not currently have any courses: Denne kanalen har ingen kurs\nVideo:\n  Mark As Watched: 'Marker som sett'\n  Remove From History: 'Fjern fra historikk'\n  Video has been marked as watched: 'Videoen har blitt markert som sett'\n  Video has been removed from your history: 'Videoen har blitt fjernet fra historikken din'\n  Open in YouTube: 'Åpne i YouTube'\n  Copy YouTube Link: 'Kopier YouTube-lenke'\n  Open YouTube Embedded Player: 'Åpne innebygd YouTube-avspiller'\n  Copy YouTube Embedded Player Link: 'Kopier lenke til innebygd YouTube-avspiller'\n  Open in Invidious: 'Åpne i Invidious'\n  Copy Invidious Link: 'Kopier Invidious-lenke'\n  Views: 'Visninger'\n  Watched: 'Sett'\n  # As in a Live Video\n  Live: 'Direkte'\n  Live Now: 'Direkte'\n  Live Chat: 'Direktechat'\n  Enable Live Chat: 'Slå på direktechat'\n  Live Chat is currently not supported in this build.: 'Direktechat støttes ikke i denne versjonen.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Direktechat er påslått.  Meldinger vil vises her når de er sendt.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Direktechat støttes for tiden ikke med Invidious-API-et. Direkte tilkobling til YouTube kreves.'\n  Published:\n    In less than a minute: Om mindre enn ett minutt\n  Published on: 'Publisert'\n#& Videos\n  Video has been saved: Videoen har blitt lagret\n  Save Video: Lagre video\n  Copy Invidious Channel Link: Kopier Invidious-kanallenke\n  Reverse Playlist: Snu spillelisten\n  Started streaming on: Startet strømming\n  Streamed on: Strømmet\n  Starting soon, please refresh the page to check again: Starter snart. Oppdater siden for å sjekke igjen\n  Autoplay: Automatisk avspilling\n  Shuffle Playlist: Spill av spillelisten i tilfeldig rekkefølge\n  Loop Playlist: Gjenta spilleliste\n  Open Channel in Invidious: Åpne kanal i Invidious\n  Copy YouTube Channel Link: Kopier YouTube-kanallenke\n  Video has been removed from your saved list: Videoen har blitt fjernet fra din liste over lagrede videoer\n  Open Channel in YouTube: Åpne kanal i YouTube\n  Previous: 'Forrige'\n  Next: 'Neste'\n  Sponsor Block category:\n    interaction: Samhandling\n    outro: Outro\n    intro: Intro\n    sponsor: Sponsor\n    music offtopic: Musikkfritt segment\n    self-promotion: Egenpromotering\n    recap: Oppsummering\n    filler: Fyllstoff\n  External Player:\n    Unsupported Actions:\n      shuffling playlists: spiller av spillelister i tilfeldig rekkefølge\n      opening specific video in a playlist (falling back to opening the video): åpner spesifikk video i en spilleliste (faller tilbake til å åpne videoen)\n      opening playlists: åpner spillelister\n      setting a playback rate: setting av avspillingshastighet\n      starting video at offset: starter video ved forskyvning\n      looping playlists: gjentakelse av spillelister\n      reversing playlists: spiller av spilleliste baklengs\n    UnsupportedActionTemplate: '{externalPlayer} støtter ikke: {action}'\n    OpeningTemplate: Åpner {videoOrPlaylist} i {externalPlayer} …\n    playlist: spilleliste\n    video: video\n    OpenInTemplate: Åpne i {externalPlayer}\n  Show Super Chat Comment: Vis superchatkommentar\n  Scroll to Bottom: Rull til bunnen\n  Premieres: Première\n  Upcoming: Kommende\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Direktechat er ikke tilgjengelig for denne strømmen. Opplasteren kan ha skrudd det av.\n#& Playlists\n  Player:\n    Take Screenshot: Ta et skjermbilde\n    Stats:\n      Video ID: 'Video-ID: {videoId}'\n      Media Formats: 'Medieformater: {formats}'\n      Buffered: 'Bufret: {bufferedPercentage}%'\n      Volume: 'Lydstyrke: {volumePercentage}%'\n      Resolution: 'Oppløsning: {width}x{height}{''@''}{frameRate}'\n      Stats: Statistikk\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Kodeker: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Player Dimensions: 'Avspillerdimensjoner: {width}x{height}'\n      CodecsVideoAudioNoItags: 'Kodeker: {videoCodec} / {audioCodec}'\n      Bandwidth: 'Båndbredde: {bandwidth} kbps'\n      Dropped Frames / Total Frames: 'Tapte bilder: {droppedFrames} / Totale antall bilder: {totalFrames}'\n      Bitrate: 'Bitrate: {bitrate} kbps'\n    Audio Tracks: Lydspor\n    Show Stats: Vis statistikk\n    Theatre Mode: Teatermodus\n    Hide Stats: Skjul statistikk\n    Full Window: Fullt vindu\n    TranslatedCaptionTemplate: '{language} (Oversatt fra \"{originalLanguage}\")'\n    Skipped segment: Hoppet over {segmentCategory}-segment\n    Autoplay is on: Automatisk avspilling er slått på\n    Exit Full Window: Avslutt fullskjerm\n    Autoplay is off: Automatisk avspilling er slått av\n    Exit Theatre Mode: Avslutt teatermodus\n    Playback will resume automatically when your connection comes back: Avspilling vil fortsette automatisk når din tilkobling kommer tilbake.\n    You appear to be offline: Du ser ut til å være frakoblet.\n  Unlisted: Ikke oppført\n  Unhide Channel: Vis kanal\n  More Options: Flere valg\n  Hide Channel: Skjul kanal\n  AgeRestricted: Videoer med aldersbegrensning kan ikke bli sett med FreeTube ettersom det kreves en Google-pålogging og at man bruker en YouTube-bruker med verifisert alder.\n  MembersOnly: Videoer kun for medlemmer kan ikke bli sett med FreeTube ettersom de krever en Google-pålogging og et betalt medlemsskap i opplasterens kanal.\n  IP block: YouTube har blokkert din IP adresse fra å se videoer. Prøv å bytte til en annen VPN eller mellomtjener.\n  DRMProtected: Kopibeskyttede videoer kan ikke bli avspilt i FreeTube, ettersom det krever proprietære komponenter med lukket kildekode. Gå til den offisielle YouTube-nettsiden i en støttet nettleser for å spille av denne videoen.\n  Save Watched Progress: Lagre sted i videoen\n  Watched Progress Saved: Sted i videoen lagret\n  DeArrow:\n    Show Modified Details: Vis endrede detaljer\n    Show Original Details: Vis originaldetaljer\n  Popout Live Chat: Chat i eget vindu\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Tid før reklamen før videoen kan hoppes over: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Tid før en SABR-strømmen blir tilgjengelig: {remindingTimeSeconds}s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Vis full spilleliste'\n  Last Updated On: 'Sist oppdatert'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Spilleliste\n  Sort By:\n    PublishedNewest: Dato lagt ut (nyeste)\n    AuthorAscending: Forfatter (A-Å)\n    VideoDurationDescending: Varighet (lengste)\n    PublishedOldest: Dato lagt ut (eldste)\n    DateAddedNewest: Dato lagt til (nyeste)\n    VideoTitleAscending: Tittel (A-Å)\n    DateAddedOldest: Dato lagt til (eldst)\n    AuthorDescending: Forfatter (Å-A)\n    VideoTitleDescending: Tittel (Å-A)\n    Custom: Tilpasset\n    VideoDurationAscending: Varighet (korteste)\nChange Format:\n  Change Media Formats: 'Endre videoformater'\n  Use Dash Formats: 'Bruk DASH-formater'\n  Use Legacy Formats: 'Bruk foreldede formater'\n  Use Audio Formats: 'Bruk lydformater'\n  Audio formats are not available for this video: Lydformater er ikke tilgjengelig for denne videoen\n  Dash formats are not available for this video: DASH-formater er ikke tilgjengelig for denne videoen\n  Legacy formats are not available for this video: Eldre formater er ikke tilgjengelig for denne videoen\nShare:\n  Share Video: 'Del video'\n  Share Playlist: 'Del spilleliste'\n  Copy Link: 'Kopier lenke'\n  Open Link: 'Åpne lenke'\n  Copy Embed: 'Kopier innebyggingslenke'\n  Open Embed: 'Åpne innebyggingslenke'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-nettadresse kopiert til utklippstavle'\n  Invidious Embed URL copied to clipboard: 'Innebyggingslenke til Invidious kopiert til utklippstavle'\n  YouTube URL copied to clipboard: 'YouTube-nettadresse kopiert til utklippstavle'\n  YouTube Embed URL copied to clipboard: 'Innebygd YouTube-nettadresse kopiert til utklippstavle'\n  YouTube Channel URL copied to clipboard: YouTube-kanalnettadresse kopiert til utklippstavle\n  Include Timestamp: Inkluder tidsstempel\n  Invidious Channel URL copied to clipboard: Invidious-kanalnettadresse kopiert til utklippstavle\n  Share Channel: Del kanal\n  Share Post: Del innlegg\nMini Player: 'Miniavspiller'\nComments:\n  Comments: 'Kommentarer'\n  Click to View Comments: 'Klikk her for å vise kommentarer'\n  Getting comment replies, please wait: 'Henter kommentarsvar...'\n  Hide Comments: 'Skjul kommentarer'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Det er ingen kommentarer tilgjengelig på denne videoen'\n  Load More Comments: 'Last inn flere kommentarer'\n  Newest first: Nyeste først\n  There are no more comments for this video: Ingen flere kommentarer på denne videoen\n  Top comments: Toppkommentarer\n  Show More Replies: Vis flere svar\n  Pinned by: Festet av\n  Member: Medlem\n  View {replyCount} replies: Vis 1 svar | Vis {replyCount} svar\n  Hearted: Hjertemerket\n  Subscribed: Abonnert\n  There are no comments available for this post: Det er ingen kommentarer tilgjengelig på denne posten\n  Hide {replyCount} replies: Skjul 1 svar | Skjul {replyCount} svar\n  View 1 reply from {channelName}: Vis 1 svar fra {channelName}\n  View {replyCount} replies from {channelName} and others: Vis {replyCount} svar fra {channelName} og andre\nUp Next: 'Neste'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Lokal API-feil (Klikk her for å kopiere)'\nInvidious API Error (Click to copy): 'Invidious-API-feil (Klikk her for å kopiere)'\nFalling back to Invidious API: 'Faller tilbake til Invidious-API-et'\nFalling back to Local API: 'Faller tilbake til det lokale API-et'\nLoop is now disabled: 'Gjenta er nå deaktivert'\nLoop is now enabled: 'Gjenta er nå aktivert'\nShuffle is now disabled: 'Tilfeldig avspilling er nå deaktivert'\nShuffle is now enabled: 'Tilfeldig avspilling er nå aktivert'\nPlaying Next Video: 'Spiller av neste video'\nPlaying Previous Video: 'Spiller av forrige video'\nCanceled next video autoplay: 'Avbryter automatisk avspilling av neste video'\n'The playlist has ended. Enable loop to continue playing': 'Spillelisten har nådd slutten. Klikk på «Gjenta» for å fortsette avspillingen'\n\nYes: 'Ja'\nNo: 'Nei'\nProfile:\n  '{profile} is now the active profile': '{profile} er nå den aktive profilen'\n  Your default profile has been changed to your primary profile: Standardprofilen din har blitt endret til din hovedprofil\n  Removed {profile} from your profiles: Fjernet {profile} fra dine profiler\n  Your default profile has been set to {profile}: 'Standardprofilen din har blitt satt som {profile}'\n  Profile has been updated: Profilen har blitt oppdatert\n  Profile has been created: Profilen har blitt opprettet\n  Your profile name cannot be empty: Profilnavnet ditt kan ikke være tomt\n  All subscriptions will also be deleted.: Alle abonnementer vil også bli slettet.\n  Are you sure you want to delete this profile?: Er du sikker på at du vil slette denne profilen?\n  Delete Profile: Slett profil\n  Make Default Profile: Angi som standardprofil\n  Update Profile: Oppdater profil\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Er du sikker på at du vil fjerne de valgte kanalene?  Disse vil ikke bli slettet fra noen andre profiler.\n  No channel(s) have been selected: Ingen kanal(er) har blitt valgt\n  Select All: Velg alle\n  '{number} selected': '{number} valgt'\n  Other Channels: Andre kanaler\n  Color Picker: Fargevelger\n  Profile Select: Velg profil\n  Create Profile: Lag profil\n  Edit Profile: Rediger profil\n  Create New Profile: Lag ny profil\n  Profile Manager: Profilbehandler\n  All Channels: Alle kanaler\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Dette er din hovedprofil.  Er du sikker på at du vil slette de valgte kanalene?  De samme kanalene vil bli slettet i enhver profil de finnes i.\n  Select None: Velg ingen\n  Delete Selected: Slett valgte\n  Add Selected To Profile: Legg de valgte kanalene til profilen\n  Subscription List: Abonnementsliste\n  Profile Preview: Profilforhåndsvisning\n  Custom Color: Egendefinert farge\n  Profile Filter: Profilfilter\n  Profile Settings: Profil\n  Toggle Profile List: Slå av/på profilliste\n  Profile Name: Profilnavn\n  Create Profile Name: Lag profilnavn\n  Edit Profile Name: Endre profilnavn\n  Close Profile Dropdown: Lukk profilrullgardinmenyen\n  Open Profile Dropdown: Åpne profilrullgardinmenyen\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Denne videoen er utilgjengelig på grunn av manglende formater. Dette kan skyldes tilgangbegrensninger i landet ditt.\nTooltips:\n  General Settings:\n    Invidious Instance: Invidious-forekomsten FreeTube kobler til for API-kall.\n    Thumbnail Preference: Alle miniatyrbilder i FreeTube vil bli erstattet av et enkeltbilde fra videoen som har blitt skjult eller blurret, i stedet for standard miniatyrbildet.\n    Fallback to Non-Preferred Backend on Failure: Når ditt foretrukne API har et problem, vil FreeTube automatisk prøve å bruke ditt ikke-foretrukne API som en reservemetode dersom det er aktivert.\n    Region for Trending: Trendregionen lar deg enkelt velge hvilket lands populære videoer du ønsker å se.\n    Preferred API Backend: Velg metoden FreeTube bruker til å hente data. Det lokale API-et er en innebygd utpakker. Invidious-API-et krever en Invidious-tjener å koble til.\n    External Link Handling: \"Velg hva som skjer når en link som ikke kan åpnes i FreeTube klikkes.\\nSom standard vil FreeTube åpne lenken i nettleseren din.\\n\"\n    Open Deep Links In New Window: Lenker sent til FreeTube, som for eksempel via omdirigeringer fra nettleseren eller via terminalprosesser, åpnes i et nytt vindu.\n  Subscription Settings:\n    Fetch Feeds from RSS: Bruk RSS istedenfor FreeTube sin standardmetode for innhenting av abonnementsstrømmen din. RSS er raskere og forhindrer IP-blokkering, men mangler noe informasjon som videovarighet, sanntidsstatus og innlegg\n    Fetch Automatically: Hent abonnementer når programmet starter og når et nytt vindu åpnes.\n  Player Settings:\n    Default Video Format: Velg formater som blir brukt når en video spilles. DASH-formater kan spilles i høyere kvalitet. Foreldede formater er begrenset opptil 360p, men bruker mindre båndbredde. Lydformater er kun lydstrømmer.\n    Proxy Videos Through Invidious: Kobler til Invidious for å servere videoer istedenfor å koble direkte til YouTube.\n    Skip by Scrolling Over Video Player: Bruk rullehjulet for å hoppe rundt gjennom videoen i MPV-stil.\n    Scroll Playback Rate Over Video Player: Når pekeren er over videoen kan du trykke og holde Ctrl-tasten (⌘ på Mac) og rulle musehjulet forover eller bakover for å kontrollere avspillingshastigheten. Trykk og hold Ctrl-tasten (⌘ på Mac) og venstreklikk på musen for å gå tilbake til den vanlige avspillingshastighet (1x med mindre det har blitt endret i innstillingene).\n  External Player Settings:\n    Custom External Player Arguments: Alle egendefinerte kommandolinjeargumenter du ønsker å sende til den eksterne avspilleren.\n    Ignore Warnings: Skjuler advarsler når nåværende eksterne avspiller ikke støtter den gjeldende handlingen (f.eks. reversering av spillelister, osv.).\n    Custom External Player Executable: Som standard vil FreeTube anta at den valgte eksterne avspilleren er tilgjengelig via PATH-miljøvariabelen. Hvis det trengs kan en egendefinert sti settes her.\n    External Player: Hvis en velger å bruke ekstern avspiller, vises et ikon for åpning av video (eller spilleliste hvis det støttes) i den eksterne avspilleren, i miniatyrbildet. Invidious-innstillinger gjelder ikke for eksterne avspillere.\n    DefaultCustomArgumentsTemplate: \"(Standard: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Ikke send noen standardargumenter til den eksterne spilleren utenom videolenken (f.eks avspillingshastighet, spillelistelenke, osv.). Egenvalgte argumenter vil fortsatt bli videresendt.\n  Experimental Settings:\n    Replace HTTP Cache: Skrur av Electrons diskbaserte HTTP-hurtiglager og skrur på bildehurtiglager i minne. Medfører økt minnebruk.\n  Distraction Free Settings:\n    Hide Channels: Skiv inn en kanal-ID for å skjule alle videoer, spillelister og selve kanalen fra å vises i søk eller andre steder. Kanal-ID-en må være et nøyaktig treff, og skiller mellom små og store bokstaver.\n    Hide Subscriptions Live: Innstillingen overstyres av «{appWideSetting}» for hele programmet, i «{subsection}»-delen av «{settingsSection}»\n    Hide Videos, Playlists and Channels Containing Text: Tast inn et ord, en del av et ord eller en frase (det skilles ikke mellom store og små bokstaver) for å gjemme alle videoer og spillelister med det i seg, med unntak av i historikken din, og videoer inne i spillelister.\n    Hide Videos on Watch: Skjul sette videoer fra Videoer, Shorts og Live-fanene på abonnementsider og kanalsider. Dette påvirker ikke Hjemme-fanen på kanalsider.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Erstatt videonavn med brukerinnsendte navn fra DeArrow.\n    UseDeArrowThumbnails: Erstatt miniatyrbilder på videoer med bilder fra DeArrow.\nA new blog is now available, {blogTitle}. Click to view more: Et nytt blogginnlegg er tilgjengelig, {blogTitle}. Klikk her for å se mer\nThe playlist has been reversed: Spillelisten har blitt snudd\nDownload From Site: Last ned fra nettside\nVersion {versionNumber} is now available!  Click for more details: Versjon {versionNumber} er nå tilgjengelig! Klikk her for detaljer\nPlaying Next Video Interval: Spiller av neste video nå. Klikk her for å avbryte. | Spiller av neste video om {nextVideoInterval} sekund. Klikk her for å avbryte. | Spiller av neste video om {nextVideoInterval} sekunder. Klikk her for å avbryte.\nMore: Mer\nUnknown YouTube url type, cannot be opened in app: Ukjent YouTube-nettadressetype, kan ikke åpnes i programmet\nOpen New Window: Åpne et nytt vindu\nDefault Invidious instance has been cleared: Fjernet standard Invidious-instans\nDefault Invidious instance has been set to {instance}: Standard Invidious-instans satt til {instance}\nExternal link opening has been disabled in the general settings: Åpning av eksterne lenker er skrudd av i de generelle innstillingene\nSearch Bar:\n  Clear Input: Tøm inndata\n  Remove: Fjern\nAre you sure you want to open this link?: Er du sikker på at du vil åpne denne lenken?\nNew Window: Nytt vindu\nChannels:\n  Channels: Kanaler\n  Title: Kanalliste\n  Search bar placeholder: Søk i kanaler\n  Count: Fant {number} kanal(er).\n  Empty: Kanallisten din er tom.\n  Unsubscribe Prompt: Er du sikker på at du ikke lenger vil abonnere på «{channelName}»?\nChapters:\n  Chapters: Kapitler\n  Key Moments: Høydepunkter\nScreenshot Success: Lagret skjermbilde\nScreenshot Error: Skjermavbildning mislyktes. {error}\nOk: OK\nPreferences: Innstillinger\nClipboard:\n  Cannot access clipboard without a secure connection: Får ikke tilgang til utklippstavlen uten sikker forbindelse\n  Copy failed: Kunne ikke kopiere til utklippstavlen\nHashtag:\n  Hashtag: Emneknagg\n  This hashtag does not currently have any videos: Denne emneknaggen har ingen videoer enda\ncheckmark: ✓\nCancel: Avbryt\nYes, Restart: Ja, start på nytt\nSearch Listing:\n  Label:\n    Subtitles: Undertekster\n    4K: 4K\n    Closed Captions: Undertekster\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Ny\n    3D: 3D\nFeed:\n  Refresh Feed: Oppdater {subscriptionName}\n  Feed Last Updated: '{feedName} sist oppdatert: {date}'\nYes, Delete: Ja, slett\nKeys:\n  alt: Alt\n  arrowup: Piltast opp\n  arrowleft: Venstre piltast\n  arrowright: Høyre piltast\n  ctrl: Ctrl\n  arrowdown: Piltast ned\n  enter: Enter\n  plus: Pluss\n  shift: Skift\nRight-click or hold to see history: Høyreklikk eller hold musepekeren over for å se historikk\nClose Banner: Lukk banner\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nYes, Open Link: Ja, åpne lenke\nDisplay Label: '{label}: {value}'\nGo to page: Gå til {page}\nSearch character limit: Søket ditt har for mange tegn. Grensen er på {searchCharacterLimit} tegn\nKeyboardShortcutPrompt:\n  Last Chapter: Forrige kapittel\n  Next Chapter: Neste kapittel\n  Navigate to History: Naviger til historikk\n  Fullscreen: Fullskjermsvisning\n  Sections:\n    Video:\n      General: Video: Generelt\n      Playback: Video: Avspilling\n    App:\n      Situational: 'App: Situasjonsmessig'\n      General: App: Generelt\n  Show Keyboard Shortcuts: Vis tastatursnarveier\n  Large Rewind: Spol tilbake 10 sekunder / Spol tilbake video basert på gjeldende videoavspillingshastighet\n  Play: Spill av/pause\n  Refresh: Oppdater feed med siste innhold\n  Focus Secondary Search: Fokuser på det sekundære søkefeltet (hvis synlig)\n  Captions: Slå bildetekst PÅ/AV\n  Stats: Vis videostatistikk\n  Picture in Picture: Veksle Bilde-i-bilde modus\n  Large Fast Forward: Spol fremover 10 sekunder / spol video basert på gjeldende videoavspillingshastighet\n  Increase Video Speed: Øk videohastighet basert på gjeldende avspillingshastighetsintervallet\n  Full Window: Fullt vindu av/på\n  Close Window: Lukk vinduet\n  Volume Down: Senk volumet\n  Zoom In: Zoom inn\n  Zoom Out: Zoom ut\n  Next Frame: Neste bilde (pauset)\n  Volume Up: Øk volumet\n  Focus Search: Fokuser på søkefeltet\n  Search in New Window: Søk i et nytt vindu\n  Last Frame: Forrige bilde (pauset)\n  Reset Zoom: Tilbakestill zoom nivå / UI-skala\n  Skip by Tenths: Hopp gjennom videoen basert på prosent (3 hopp for 30% av varigheten)\n  Small Rewind: Spol tilbake X sekunder basert på spoleintervallet og gjeldende avspillingshastighet\n  Small Fast Forward: Spol fremover X sekunder basert på spoleintervallet og gjeldende avspillingshastighet\n  Decrease Video Speed: Senk videohastighet basert på gjeldende avspillingshastighetsintervallet\n  Take Screenshot: Ta et skjermbilde\n  Mute: Slå lyd av/på\n  History Backward: Gå tilbake en side\n  New Window: Opprett nytt vindu\n  Navigate to Settings: Naviger til innstillinger\n  Keyboard Shortcuts: Tastatursnarveier\n  History Forward: Gå fremover en side\n  Toggle Developer Tools: Utviklerverktøy\n  Minimize Window: Minimer vinduet\n  Theatre Mode: Skru teatermodus av/på\n  End: Gå til slutten av videoen\n  Home: Gå til starten av videoen\n  Skip to Next Video: Hopp til neste video i en spilleliste eller neste anbefalte video\n  Skip to Previous Video: Hopp til forrige video i en spilleliste\nMoments Ago: for et øyeblikk siden\nshortcutLabelSeparator: ｜\nDescription:\n  Expand Description: '...mer'\n  Collapse Description: Vis mindre\nAutoplay Interruption Timer: Automatisk avspilling stoppet på grunn av {autoplayInterruptionIntervalHours} timer med inaktivitet\nAge Restricted:\n  This video is age restricted: Denne videoen er aldersbegrenset\n  This channel is age restricted: Denne kanalen er aldersbegrenset\nChannel Hidden: '{channel} lagt til i kanalfilteret'\nChannel Unhidden: '{channel} fjernet fra kanalfilteret'\nTag already exists: «{tagName}»-taggen eksisterer allerede\nTrimmed input must be at least N characters long: Trimmet input må være minst ett tegn langt | Trimmet input må være minst {length} tegn langt\nCompact side navigation: Kompakt sidenavigasjon\nExpand side navigation: Utvid sidenavigasjon\n"
  },
  {
    "path": "static/locales/ne.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'नेपाली'\n\n# Webkit Menu Bar\nFile: 'फाइल'\nQuit: 'अन्त्य गर्नुहोस्'\nEdit: 'सम्पादन गर्नुहोस्'\nUndo: 'पूर्ववत् गर्नुहोस्'\nRedo: 'फेरि गर्नुहोस्'\nCut: 'कट गर्नुहोस्'\nCopy: 'सार्नुहोस्'\nPaste: 'पेस्ट गर्नुहोस्'\nDelete: 'मेटाउनुहोस्'\nSelect all: 'सबै रोज्नुहोस्'\nToggle Developer Tools: 'Developer Tools टगल गर्नुहोस्'\nActual size: 'वास्तविक आकार'\nZoom in: 'अझ ठुलो बनाउनुहोस्'\nZoom out: 'अझ सानो बनाउनुहोस्'\nToggle fullscreen: 'फुलस्क्रिन टगल गर्नुहोस्'\nWindow: 'विन्डो'\nMinimize: 'न्युनतम बनाउहोस्'\nClose: 'बन्द गर्नुहोस्'\nBack: 'पछाडि'\nForward: 'अगाडि'\nOpen New Window: 'नयाँ विन्डो खोल्नुहोस्'\n\nVersion {versionNumber} is now available!  Click for more details: 'भर्जन {versionNumber} उपलब्ध छ! थप बुझ्न यहाँ थिच्नुहोस्'\nDownload From Site: 'साइटबाट डाउनलोड गर्नुहोस्'\nA new blog is now available, {blogTitle}. Click to view more: 'एउटा नयाँ ब्लग उपलब्ध छ, {blogTitle}। थप बुझ्न यहाँ थिच्नुहोस्'\n\nGlobal:\n  Sort By: 'क्रमबद्ध गर्नुहोस्'\n\n# Search Bar\n  Videos: भिडियोहरू\n  Live: लाइभ\nSearch / Go to URL: 'खोज्नुहोस् / URL मा जानुहोस्'\nSearch Bar:\n  Clear Input: 'इन्पुट खाली गर्नुहोस्'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'खोजी फिल्टरहरू'\n  Sort By:\n    Most Relevant: 'सबैभन्दा प्रासङ्गिक'\n    Rating: 'रेटिङ्ग'\n    Upload Date: 'प्रकाशित मिति'\n    View Count: 'हेरिएको सङ्ख्या'\n  Time:\n    Time: 'समय'\n    Any Time: 'जुनसुकै समय'\n    Last Hour: 'पछिल्लो घण्टा'\n    Today: 'आज'\n    This Week: 'यो हप्ता'\n    This Month: 'यो महिना'\n    This Year: 'यो वर्ष'\n  Type:\n    Type: 'प्रकार'\n    All Types: 'सबै प्रकार'\n    Videos: 'भिडियोहरू'\n    Channels: 'च्यानलहरू'\n    #& Playlists\n  Duration:\n    Duration: 'अवधि'\n    All Durations: 'सबै अवधि'\n    Short (< 4 minutes): 'छोटो (< ४ मिनट)'\n    Long (> 20 minutes): 'लामो (> २० मिनट)'\n  # On Search Page\n  Search Results: 'खोजी परिणामहरू'\n  Fetching results. Please wait: 'परिणामहरू खोजिँदै छ। कृपया पर्खनुहोस्'\n  Fetch more results: 'थप परिणामहरू खोज्नुहोस्'\n  There are no more results for this search: 'यस खोजीका लागि थप परिणामहरू छैनन्'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'सदस्यताहरु'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'यो प्रोफाइलमा ठुलो सङ्ख्यामा सदस्यताहरू छन्। दर सिमित हुनबाट बच्न RSS लाई बल गरिँदै'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'तपाईँको सदस्यता सूची अहिले खाली छ। तिनीहरूलाई यहाँ हेर्न सदस्यताहरू थप्न सुरु गर्नुहोस्।'\n  Load More Videos: 'थप भिडियोहरू लोड गर्नुहोस्'\nMore: 'थप'\nTrending:\n  Trending: 'प्रचलित'\n  Gaming: 'गेमिङ्ग'\n  Trending Tabs: 'प्रचलित ट्याबहरू'\n  Sports: खेलकुद\nMost Popular: 'सबैभन्दा लोकप्रिय'\nPlaylists: 'प्लेसूचीहरू'\nUser Playlists:\n  Your Playlists: 'तपाईंका प्लेसूचीहरू'\nSettings:\n  # On Settings Page\n  Theme Settings: {}\nChannel:\n  Videos:\n    Videos: भिडियोहरू\nTooltips: {}\nClose Banner: ब्यानर बन्द गर्नुहोस्\nPreferences: प्राथमिकताहरू\nAre you sure you want to open this link?: के तपाईं यो लिङ्क खोल्न निश्चित हुनुहुन्छ?\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Developer Tools टगल गर्नुहोस्\n  Zoom Out: अझ सानो बनाउनुहोस्\n  Zoom In: अझ ठुलो बनाउनुहोस्\n  Fullscreen: फुलस्क्रिन टगल गर्नुहोस्\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\nNew Window: नयाँ सञ्झ्याल\nProfile:\n  Select All: सबै रोज्नुहोस्\n"
  },
  {
    "path": "static/locales/nl.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Nederlands'\n\n# Webkit Menu Bar\nFile: 'Bestand'\nQuit: 'Afsluiten'\nEdit: 'Bewerken'\nUndo: 'Ongedaan maken'\nRedo: 'Opnieuw'\nCut: 'Knippen'\nCopy: 'Kopiëren'\nPaste: 'Plakken'\nDelete: 'Verwĳderen'\nSelect all: 'Alles selecteren'\nToggle Developer Tools: 'Ontwikkelgereedschap aan/uit'\nActual size: 'Werkelĳke grootte'\nZoom in: 'Inzoomen'\nZoom out: 'Uitzoomen'\nToggle fullscreen: 'Volledig scherm aan/uit'\nWindow: 'Venster'\nMinimize: 'Minimaliseren'\nClose: 'Sluiten'\nBack: 'Terug'\nForward: 'Vooruit'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video''s'\n\n# Search Bar\n  Shorts: Shorts\n  Live: Live\n  Sort By: Sorteren op\n  Counts:\n    Video Count: 1 video | {count} video's\n    Subscriber Count: 1 abonnee | {count} abonnees\n    View Count: 1 weergave | {count} weergaven\n    Watching Count: 1 aan het kĳken | {count} aan het kĳken\n    Channel Count: 1 kanaal | {count} kanalen\n    Like Count: 1 vind ik leuk | {count} vind ik leuks\n    Comment Count: 1 commentaar | {count} commentaren\n  Posts: Posts\nSearch / Go to URL: 'Zoeken / Ga naar URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Zoekfilters'\n  Sort By:\n    Most Relevant: 'Relevantie'\n    Rating: 'Beoordeling'\n    Upload Date: 'Uploaddatum'\n    View Count: 'Aantal weergaven'\n  Time:\n    Time: 'Lengte'\n    Any Time: 'Altĳd'\n    Last Hour: 'Afgelopen uur'\n    Today: 'Vandaag'\n    This Week: 'Deze week'\n    This Month: 'Deze maand'\n    This Year: 'Dit jaar'\n  Type:\n    Type: 'Soort'\n    All Types: 'Alle soorten'\n    Videos: 'Video''s'\n    Channels: 'Kanalen'\n    #& Playlists\n    Movies: Films\n  Duration:\n    Duration: 'Lengte'\n    All Durations: 'Alle lengtes'\n    Short (< 4 minutes): 'Kort (< 4 minuten)'\n    Long (> 20 minutes): 'Lang (> 20 minuten)'\n  # On Search Page\n    Medium (4 - 20 minutes): Gemiddeld (4 - 20 minuten)\n  Search Results: 'Zoekresultaten'\n  Fetching results. Please wait: 'Resultaten ophalen, even geduld...'\n  Fetch more results: 'Meer resultaten ophalen'\n# Sidebar\n  There are no more results for this search: Er zĳn geen resultaten meer voor deze zoek­opdracht\n  Features:\n    Features: Functies\n    4K: 4K\n    HD: HD\n    3D: 3D\n    Subtitles: Ondertiteling\n    Live: Live\n    Creative Commons: Creative Commons\n    HDR: HDR\n    360 Video: 360° Video\n    Location: Locatie\n    VR180: VR180\n  Clear Filters: Filters wissen\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnementen'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Je abonnementenlĳst is momenteel leeg. Ga naar instellingen en selecteer \"importeer abonnementen\" als je jouw abonnementen wilt importeren. Je kunt ook zoeken naar een kanaal en hierop abonneren.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Dit profiel heeft een groot aantal abonnees. RSS wordt geforceerd om rate-limiting te vermĳden\n  Load More Videos: Meer video's laden\n  Error Channels: Kanalen met fouten\n  Disabled Automatic Fetching: U heeft het automatisch ophalen van abonnementen uitgeschakeld. Ververs abonnementen om ze hier te zien.\n  Empty Channels: Er zĳn geen video's beschikbaar in de kanalen waarop je bent geabonneerd.\n  Subscriptions Tabs: Abonnement tabbladen\n  All Subscription Tabs Hidden: Alle abonnement­tabbladen zĳn verborgen. Om de inhoud hier te kunnen zien moet u de tabbladen zichtbaar maken in de sectie ‘{subsection}’ onder ‘{settingsSection}’.\n  Load More Posts: Meer berichten laden\n  Empty Posts: De kanalen waarop u geabonneerd bent hebben momenteel geen berichten.\nTrending:\n  Trending: 'Trending'\n  Trending Tabs: Trending\n  Gaming: Gaming\n  Sports: Sport\nMost Popular: 'Populairste'\nPlaylists: 'Afspeellĳsten'\nUser Playlists:\n  Your Playlists: 'Jouw afspeellĳsten'\n  Search bar placeholder: Zoeken naar afspeellĳsten\n  Empty Search Message: Deze afspeellĳst bevat geen video's die overeenkomen met je zoekopdracht\n  Cancel: Annuleren\n  Playlist Name: Afspeellijst naam\n  Playlist Description: Afspeellijst omschrijving\n  Delete Playlist: Afspeellijst verwijderen\n  Sort By:\n    LatestCreatedFirst: Datum aangemaakt (nieuwste)\n    NameDescending: Z - A\n    NameAscending: A - Z\n    EarliestPlayedFirst: Datum afgespeeld (oudste)\n    EarliestCreatedFirst: Datum aangemaakt (oudste)\n    LatestUpdatedFirst: Datum bĳgewerkt (nieuwste)\n    EarliestUpdatedFirst: Datum bĳgewerkt (oudste)\n    LatestPlayedFirst: Datum afgespeeld (nieuwste)\n  CreatePlaylistPrompt:\n    Create: Aanmaken\n    New Playlist Name: Naam voor nieuwe afspeellijst\n    Toast:\n      Playlist {playlistName} has been successfully created.: Afspeellijst ‘{playlistName}’ is succesvol aangemaakt.\n      There was an issue with creating the playlist.: Er is een probleem opgetreden bij het maken van de afspeellijst.\n      There is already a playlist with this name. Please pick a different name.: Er is al een afspeellijst met deze naam. Kies een andere naam.\n  AddVideoPrompt:\n    Save: Opslaan\n    N playlists selected: '{playlistCount} geselecteerd'\n    Search in Playlists: Zoeken in afspeellijsten\n    Toast:\n      You haven't selected any playlist yet.: U heeft nog geen afspeellijst geselecteerd.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(s) toegevoegd aan 1 afspeellijst | Video(s) toegevoegd aan {playlistCount} afspeellijsten\"\n    Select a playlist to add your N videos to: Selecteer een afspeellijst om je video aan toe te voegen | Selecteer een afspeellijst om je {videoCount} video's aan toe te voegen\n    Added {count} Times: 'Video is al toegevoegd | {count} keer toegevoegd'\n    Allow Adding Duplicate Video(s): Toevoegen van dubbele video's toestaan\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": \"{videoCount}/{totalVideoCount} video's zullen worden toegevoegd\"\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": \"{videoCount}/{totalVideoCount} video's zijn al toegevoegd\"\n  Save Changes: Wijzigingen opslaan\n  Copy Playlist: Afspeellijst kopiëren\n  Create New Playlist: Maak nieuwe afspeellijst\n  Add to Playlist: Toevoegen aan afspeellijst\n  Move Video Up: Video omhoog verplaatsen\n  Move Video Down: Video omlaag verplaatsen\n  Remove from Playlist: Verwijderen uit afspeellijst\n  Edit Playlist Info: Afspeellijst informatie bewerken\n  Remove Watched Videos: Bekeken video's verwijderen\n  Add to Favorites: Toevoegen aan {playlistName}\n  Remove from Favorites: Verwijderen uit {playlistName}\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: Video is verwijderd\n      Playlist has been updated.: De afspeellijst is bijgewerkt.\n      This video cannot be moved up.: Deze video kan niet omhoog verplaatst worden.\n      This video cannot be moved down.: Deze video kan niet omlaag verplaatst worden.\n      Playlist {playlistName} has been deleted.: Afspeellijst ‘{playlistName}’ is verwijderd.\n      This playlist does not exist: Deze afspeellijst bestaat niet\n      There were no videos to remove.: Er zijn geen video's om te verwijderen.\n      There was a problem with removing this video: Er is een probleem met het verwijderen van deze video\n      This playlist is now used for quick bookmark: Deze afspeellijst wordt nu gebruikt met snelle bladwijzers\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Deze afspeellijst wordt nu gebruikt voor snelle bladwijzers in plaats van {oldPlaylistName}. Klik hier om ongedaan te maken\n      Reverted to use {oldPlaylistName} for quick bookmark: Teruggekeerd naar het gebruik van {oldPlaylistName} voor snelle bladwijzers\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Sommige video's in de afspeellijst zijn nog niet geladen. Klik hier om toch te kopiëren.\n      \"{videoCount} video(s) have been removed\": 1 video verwijderd | {videoCount} video's verwijderd\n      This playlist is protected and cannot be removed.: Deze afspeellijst is beveiligd en kan niet worden verwijderd.\n      Playlist name cannot be empty. Please input a name.: De naam van de afspeellijst mag niet leeg zijn. Voer een naam in alstjeblieft.\n      There was an issue with updating this playlist.: Er is een probleem opgetreden bij het bijwerken van deze afspeellijst.\n      This playlist is already being used for quick bookmark.: Deze afspeellĳst wordt al gebruikt met snelle bladwijzer.\n      Video has been removed. Click here to undo.: De video is verwijderd. Klik hier om ongedaan te maken.\n      This playlist has a video with a duration error: Deze afspeellijst heeft minimaal 1 video zonder tijdsduur en zal worden gesorteerd alsof de tijdsduur nul is.\n    Search for Videos: Zoeken naar video's\n  You have no playlists. Click on the create new playlist button to create a new one.: U heeft geen afspeel­lĳsten. Druk op ‘Nieuwe afspeel­lĳst maken’ om er een te maken.\n  This playlist currently has no videos.: Deze afspeellijst bevat momenteel geen video's.\n  Enable Quick Bookmark With This Playlist: Snelle Bladwijzers inschakelen voor deze afspeellijst\n  Are you sure you want to delete this playlist? This cannot be undone: Weet u zeker dat u deze afspeellijst wilt verwijderen? Dit kan niet ongedaan worden gemaakt.\n  Playlists with Matching Videos: Afspeellĳsten met overeenkomende video's\n  Quick Bookmark Enabled: Snel opslaan ingeschakeld\n  Cannot delete the quick bookmark target playlist.: Kan afspeellĳst voor snel opslaan niet verwĳderen.\n  Remove Duplicate Videos: Dubbele video's verwĳderen\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Weet je zeker dat je 1 dubbele video uit deze afspeellĳst wilt verwijderen? Dit kan niet ongedaan worden gemaakt. | Weet je zeker dat je {playlistItemCount} dubbele video's uit deze afspeellĳst wilt verwijderen? Dit kan niet ongedaan worden gemaakt.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Weet je zeker dat je 1 bekeken video uit deze afspeellĳst wilt verwijderen? Dit kan niet ongedaan worden gemaakt. | Weet je zeker dat je {playlistItemCount} bekeken video's uit deze afspeellĳst wilt verwijderen? Dit kan niet ongedaan worden gemaakt.\n  Export Playlist: Deze afspeel­lĳst exporteren\n  The playlist has been successfully exported: De afspeel­lĳst is succesvol geëxporteerd\n  TotalTimePlaylist: 'Totale tĳd: {duration}'\n  Export list of URLs: Lĳst met url's exporteren\nHistory:\n  # On History Page\n  History: 'Geschiedenis'\n  Watch History: 'Kijkgeschiedenis'\n  Your history list is currently empty.: 'Er is momenteel geen geschiedenis.'\n  Search bar placeholder: In geschiedenis zoeken\n  Empty Search Message: Geschiedenis bevat geen video's die overeenkomen met de zoekopdracht\n  Case Sensitive Search: Hoofdlettergevoelige zoekopdracht\n  DateOldestHistory: Datum bekeken (oudste)\n  DateNewestHistory: Datum bekeken (nieuwste)\nSettings:\n  # On Settings Page\n  Settings: 'Instellingen'\n  General Settings:\n    General Settings: 'Algemeen'\n    Fallback to Non-Preferred Backend on Failure: 'Terugvallen op alternatieve backend bij problemen'\n    Enable Search Suggestions: 'Zoeksuggesties inschakelen'\n    Default Landing Page: 'Standaard startscherm'\n    Locale Preference: 'Regiovoorkeur'\n    Preferred API Backend:\n      Preferred API Backend: 'Voorkeurs-API-back-end'\n      Local API: 'Lokale API'\n      Invidious API: 'Invidious-API'\n    Video View Type:\n      Video View Type: 'Type videoweergave'\n      Grid: 'Raster'\n      List: 'Lijst'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatuurvoorkeur'\n      Default: 'Standaard'\n      Beginning: 'Begin'\n      Middle: 'Midden'\n      End: 'Einde'\n      Hidden: Verborgen\n      Blur: Vervagen\n    Region for Trending: 'Regio voor trending'\n        #! List countries\n    Check for Latest Blog Posts: Op nieuwe blogpost controleren\n    Check for Updates: Controleer op updates\n    View all Invidious instance information: Bekijk alle Invidious-instantiegegevens\n    System Default: Systeemstandaard\n    Current Invidious Instance: Huidige Invidious-instantie\n    Clear Default Instance: Standaardinstantie wissen\n    Set Current Instance as Default: Huidige instantie instellen als standaard\n    Current instance will be randomized on startup: Instantie zal willekeurig worden gekozen bij het starten\n    No default instance has been set: Er is geen standaardinstantie ingesteld\n    The currently set default instance is {instance}: '{instance} is momenteel de standaard instantie'\n    External Link Handling:\n      Ask Before Opening Link: Vragen bij het openen van koppelingen\n      No Action: Geen actie\n      External Link Handling: Externe links openen\n      Open Link: Koppeling openen\n    Auto Load Next Page:\n      Tooltip: Extra pagina's en opmerkingen automatisch laden.\n      Label: Volgende pagina automatisch laden\n    Open Deep Links In New Window: Open URL's in een nieuw venster\n    Minimize to system tray: Minimaliseren naar achtergrond-apps\n  Theme Settings:\n    Theme Settings: 'Thema'\n    Match Top Bar with Main Color: 'Primaire themakleur gebruiken voor bovenste balk'\n    Base Theme:\n      Base Theme: 'Basisthema'\n      Black: 'Zwart'\n      Dark: 'Donker'\n      Light: 'Licht'\n      Dracula: 'Dracula'\n      System Default: Systeemstandaard\n      Catppuccin Mocha: Catppuccin-mokka\n      Pastel Pink: Pastelroze\n      Hot Pink: Hot Pink\n      Nordic: Noors\n      Solarized Dark: Gesolariseerd donker\n      Solarized Light: Gesolariseerd licht\n      Gruvbox Light: Gruvbox licht\n      Gruvbox Dark: Gruvbox donker\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Medium: Everforest Donker Middel\n      Everforest Dark Hard: Everforest Donker Hoog\n      Everforest Dark Low: Everforest Donker Laag\n      Everforest Light Hard: Everforest Licht Hoog\n      Everforest Light Medium: Everforest Licht Middel\n      Everforest Light Low: Everforest Licht Laag\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Primaire themakleur'\n      Red: 'Rood'\n      Pink: 'Roze'\n      Purple: 'Paars'\n      Deep Purple: 'Donkerpaars'\n      Indigo: 'Indigo'\n      Blue: 'Blauw'\n      Light Blue: 'Lichtblauw'\n      Cyan: 'Cyaan'\n      Teal: 'Groenblauw'\n      Green: 'Groen'\n      Light Green: 'Lichtgroen'\n      Lime: 'Limoen'\n      Yellow: 'Geel'\n      Amber: 'Amber'\n      Orange: 'Oranje'\n      Deep Orange: 'Donker oranje'\n      Dracula Cyan: 'Dracula-cyaan'\n      Dracula Green: 'Dracula-groen'\n      Dracula Orange: 'Dracula-oranje'\n      Dracula Pink: 'Dracula-roze'\n      Dracula Purple: 'Dracula-paars'\n      Dracula Red: 'Dracula-rood'\n      Dracula Yellow: 'Dracula-geel'\n      Catppuccin Mocha Green: Catppuccin Mokka Groen\n      Catppuccin Mocha Maroon: Catppuccin mokka kastanjebruin\n      Catppuccin Mocha Blue: Catppuccin Mokka Blauw\n      Catppuccin Mocha Lavender: Catppuccin Mokka Lavendel\n      Catppuccin Mocha Rosewater: Catppuccin Mokka Rozenwater\n      Catppuccin Mocha Flamingo: Catppuccin Mokka Flamingo\n      Catppuccin Mocha Pink: Catppuccin Mokka Roze\n      Catppuccin Mocha Mauve: Catppuccin Mokka Mauve\n      Catppuccin Mocha Red: Catppuccin Mokka Rood\n      Catppuccin Mocha Peach: Catppuccin Mokka Perzik\n      Catppuccin Mocha Yellow: Catppuccin Mokka Geel\n      Catppuccin Mocha Sapphire: Catppuccin Mokka Saffier\n      Catppuccin Mocha Teal: Catppuccin Mokka blauwgroen\n      Catppuccin Mocha Sky: Catppuccin Mokka Hemel\n      Solarized Yellow: Gesolariseerd geel\n      Solarized Orange: Gesolariseerd oranje\n      Solarized Red: Gesolariseerd rood\n      Solarized Magenta: Gesolariseerd magenta\n      Solarized Violet: Gesolariseerd violet\n      Solarized Blue: Gesolariseerd blauw\n      Solarized Cyan: Gesolariseerd cyaan\n      Solarized Green: Gesolariseerd groen\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe roze\n      Catppuccin Frappe Mauve: Catppuccin Frappe lila\n      Catppuccin Frappe Red: Catppuccin Frappe Rood\n      Catppuccin Frappe Peach: Catppuccin Frappe Perzik\n      Catppuccin Frappe Yellow: Catppuccin Frappe Geel\n      Catppuccin Frappe Green: Catppuccin Frappe Groen\n      Catppuccin Frappe Teal: Catppuccin Frappe groenblauw\n      Catppuccin Frappe Sky: Catppuccin Frappe lichtblauw\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Saffier\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavendel\n      Gruvbox Dark Yellow: Gruvbox donkergeel\n      Gruvbox Dark Orange: Gruvbox donkeroranje\n      Gruvbox Light Red: Gruvbox lichtrood\n      Gruvbox Light Purple: Gruvbox lichtpaars\n      Gruvbox Light Orange: Gruvbox lichtoranje\n      Catppuccin Frappe Blue: Catppuccin Frappe Blauw\n      Gruvbox Dark Blue: Gruvbox donkerblauw\n      Gruvbox Dark Aqua: Gruvbox donker aqua\n      Gruvbox Dark Purple: Gruvbox donkerroze\n      Gruvbox Light Blue: Gruvbox lichtblauw\n      Catppuccin Frappe Maroon: Catppuccin Frappe kastanjebruin\n      Gruvbox Dark Green: Gruvbox Donkergroen\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Everforest Dark Red: Everforest Donker Rood\n      Everforest Dark Orange: Everforest Donker Oranje\n      Everforest Dark Yellow: Everforest Donker Geel\n      Everforest Dark Green: Everforest Donker Groen\n      Everforest Dark Aqua: Everforest Donker Aqua\n      Everforest Dark Blue: Everforest Donker Blauw\n      Everforest Dark Purple: Everforest Donker Paars\n      Everforest Light Red: Everforest Licht Rood\n      Everforest Light Aqua: Everforest Licht Aqua\n      Everforest Light Green: Everforest Licht Groen\n      Everforest Light Yellow: Everforest Licht Geel\n      Everforest Light Orange: Everforest Licht Oranje\n      Everforest Light Blue: Everforest Licht Blauw\n      Everforest Light Purple: Everforest Licht Paars\n      Catppuccin Latte Red: Catppuccin Latte Rood\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n    Secondary Color Theme: 'Secundaire themakleur'\n        #* Main Color Theme\n    UI Scale: Interface schaal\n    Expand Side Bar by Default: Zijbalk standaard uitklappen\n    Disable Smooth Scrolling: Vloeiend scrollen uitschakelen\n    Hide Side Bar Labels: Labels in zĳbalk verbergen\n    Hide FreeTube Header Logo: FreeTube headerlogo verbergen\n  Player Settings:\n    Player Settings: 'Speler'\n    Play Next Video: 'Aanbevolen video''s automatisch afspelen'\n    Turn on Subtitles by Default: 'Ondertiteling Standaard Inschakelen'\n    Autoplay Videos: 'Video''s Automatisch Afspelen'\n    Proxy Videos Through Invidious: 'Video''s via Invidious-proxy afspelen'\n    Autoplay Playlists: 'Afspeellijsten Automatisch Afspelen'\n    Enable Theatre Mode by Default: 'Theater­modus standaard inschakelen'\n    Default Volume: 'Standaardvolume'\n    Default Playback Rate: 'Standaard­afspeel­snelheid'\n    Default Video Format:\n      Default Video Format: 'Standaard­video­formaat'\n      Dash Formats: 'DASH-formaten'\n      Legacy Formats: 'Legacy formaten'\n      Audio Formats: 'Audioformaten'\n    Default Quality:\n      Default Quality: 'Standaard­kwaliteit'\n      Auto: 'Automatisch'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '2160p (4K)'\n      8k: '4320p (8K)'\n    Next Video Interval: Pauze voor volgende video\n    Display Play Button In Video Player: Afspeelknop in videospeler weergeven\n    Scroll Volume Over Video Player: Volume aanpassen door op de video te scrollen\n    Fast-Forward / Rewind Interval: Snelheid van doorspoelen/terugspoelen\n    Scroll Playback Rate Over Video Player: Afspeelsnelheid aanpassen door op de video te scrollen\n    Max Video Playback Rate: Maximale afspeelsnelheid\n    Video Playback Rate Interval: Interval video-afspeelsnelheid\n    Screenshot:\n      Enable: Schermafdruk inschakelen\n      Format Label: Schermafdruk­formaat\n      Quality Label: Schermafdruk­kwaliteit\n      Ask Path: Vragen in welke map op te slaan\n      Folder Label: Schermafdruk­map\n      Folder Button: Map selecteren\n      Error:\n        Forbidden Characters: Niet-toegestane tekens\n        Empty File Name: Lege bestandsnaam\n      File Name Label: Bestandsnaam­patroon\n      File Name Tooltip: 'U kunt de volgende variabelen gebruiken: %Y viercijferig jaartal; %M tweecijferige maand; %D tweecijferige dagstelling; %H tweecijferig uur; %N tweecijferige minuut; %S tweecijferige seconde; %T driecijferige milliseconde; %s tweecijferige seconde in de video; %t driecijferige milliseconde in de video; %i ID van de video.'\n    Skip by Scrolling Over Video Player: Overslaan door op de video te scrollen\n    Enter Fullscreen on Display Rotate: Volledig scherm bij draaien van scherm\n    Default Viewing Mode:\n      Theater: Theater\n      Default Viewing Mode: Standaard afspeelmode\n      Full Screen: Volledig scherm\n      Picture in Picture: Beeld in beeld\n      External Player: Externe speler\n    Autoplay Interruption Timer: Timer voor Automatisch Afspelen Onderbreken\n  Privacy Settings:\n    Privacy Settings: 'Privacy'\n    Remember History: 'Kijkgeschiedenis onthouden'\n    Save Watched Progress: 'Videovoortgang bewaren'\n    Clear Search Cache: 'Zoek-cache wissen'\n    Are you sure you want to clear out your search cache?: 'Weet u zeker dat u de zoekbuffer wil verwijderen?'\n    Search cache has been cleared: 'De zoekbuffer is verwijderd'\n    Remove Watch History: 'Kijkgeschiedenis verwijderen'\n    Are you sure you want to remove your entire watch history?: 'Weet u zeker dat u uw volledige kijkgeschiedenis wil verwijderen?'\n    Watch history has been cleared: 'Kijkgeschiedenis is verwijderd'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Weet u zeker dat u alle abonnementen en profielen wil verwijderen? Dit kan niet ongedaan worden gemaakt.\n    Remove All Subscriptions / Profiles: Verwijder alle abonnementen / profielen\n    Save Watched Videos With Last Viewed Playlist: Houd bekeken video's bij met de afspeellijst ‘Laatst bekeken’\n    Remove All Playlists: Alle afspeel­lijsten verwijderen\n    All playlists have been removed: Alle afspeel­lijsten zijn verwijderd\n    Are you sure you want to remove all your playlists?: Weet u zeker dat u al uw afspeel­lijsten wilt verwijderen?\n    Remember Search History: Zoekgeschiedenis Bijhouden\n    Search history and cache have been cleared: Cache en zoekgeschiedenis zijn verwijderd\n    Are you sure you want to clear out your search history and cache?: Weet u zeker dat u uw cache en zoekgeschiedenis wilt verwijderen?\n    Clear Search History and Cache: Cache en Zoekgeschiedenis Verwijderen\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automatisch\n        Semi-auto: Semi­automatisch\n        Never: Nooit\n      Tooltip: Auto = Opslaan bij het verlaten van elke videopagina, wanneer de video is afgelopen of wanneer er een fout optreedt (bijv. rate-limiet bereikt of kijkersessie verlopen).Semi-auto = Net als Auto, behalve bij het verlaten van de videopagina. Voortgang kan handmatig worden opgeslagen via een knop genaamd 'Voortgang Opslaan', die zich onder de videospeler bevindt.\n  Subscription Settings:\n    Subscription Settings: 'Abonnement­'\n    Fetch Feeds from RSS: Feeds ophalen via RSS\n    Fetch Automatically: Feed automatisch ophalen\n    Confirm Before Unsubscribing: Onbedoeld deabonneren voor­komen\n\n    'Limit the number of videos displayed for each channel': Limiteer de hoeveelheid getoonde videos per kanaal\n    To: Naar\n  Data Settings:\n    History object has insufficient data, skipping item: Geschiedenis object heeft niet genoeg data, item wordt overgeslagen\n    Subscriptions have been successfully exported: Abonnementen zijn met succes geïmporteerd\n    Invalid history file: Ongeldig geschiedenisbestand\n    Invalid subscriptions file: Ongeldig abonnementenbestand\n    All subscriptions have been successfully imported: Alle abonnementen zijn met succes geïmporteerd\n    All subscriptions and profiles have been successfully imported: Alle abonnementen en profielen zijn succesvol geïmporteerd\n    Profile object has insufficient data, skipping item: Profiel heeft niet genoeg data, item wordt overgeslagen\n    Export History: Geschiedenis exporteren\n    Import History: Geschiedenis importeren\n    Export NewPipe: NewPipe exporteren\n    Export YouTube: YouTube exporteren\n    Export FreeTube: FreeTube exporteren\n    Export Subscriptions: Abonnementen exporteren\n    Import Subscriptions: Abonnementen importeren\n    Select Export Type: Exporteertype selecteren\n    Data Settings: Gegevens\n    How do I import my subscriptions?: Hoe importeer ik mijn abonnementen?\n    Unknown data key: Onbekende datasleutel\n    Unable to write file: Bestand kan niet worden geschreven\n    Unable to read file: Bestand kan niet worden gelezen\n    All watched history has been successfully exported: De bekeken geschiedenis is met succes geëxporteerd\n    All watched history has been successfully imported: De bekeken geschiedenis is met succes geïmporteerd\n    Manage Subscriptions: Abonnementen beheren\n    Export Playlists: Afspeellijsten exporteren\n    All playlists has been successfully imported: Alle afspeel­lĳsten zĳn succesvol geïmporteerd\n    Import Playlists: Afspeellijsten importeren\n    Playlist insufficient data: Onvoldoende gegevens voor afspeel­lĳst ‘{playlist}’, item wordt over­geslagen\n    All playlists has been successfully exported: Alle speel­lĳsten zĳn succesvol geëxporteerd\n    Subscription File: Abonnementen­bestand\n    History File: Geschiedenis­bestand\n    Playlist File: Afspeellĳst­bestand\n    Export Playlists For Older FreeTube Versions:\n      Label: Afspeel­lijsten exporteren voor oudere FreeTube-versies\n      Tooltip: \"Deze optie exporteert video's van alle afspeel­lijsten naar één afspeel­lijst met de naam ‘Favorieten’.\\nVideo's exporteren en importeren in afspeel­lijsten voor een oudere versie van FreeTube:\\n1. Exporteer uw afspeel­lijsten met deze optie ingeschakeld.\\n2. Verwijder al uw bestaande afspeel­lijsten met de optie ‘Alle afspeel­lijsten verwijderen’ onder ‘Privacy­instellingen’.\\n 3. Start de oudere versie van FreeTube en importeer de geëxporteerde afspeel­lijsten.\"\n    Search history file: Zoekgeschiedenisbestand\n    Search history: Zoekgeschiedenis\n    Import search history: Zoekgeschiedenis importeren\n    Export search history: Zoekgeschiedenis exporteren\n    All search history has been successfully imported: De gehele zoekgeschiedenis is succesvol geïmporteerd\n    All search history has been successfully exported: De gehele zoekgeschiedenis is succesvol geëxporteerd\n  Distraction Free Settings:\n    Hide Live Chat: Live­chat verbergen\n    Hide Popular Videos: Populaire video's verbergen\n    Hide Trending Videos: Trending video's verbergen\n    Hide Recommended Videos: Aanbevolen video's verbergen\n    Hide Comment Likes: Likes op opmerkingen verbergen\n    Hide Channel Subscribers: Aantal abonnees verbergen\n    Hide Video Likes And Dislikes: Likes en dislikes verbergen\n    Hide Video Views: Aantal video­weergaven verbergen\n    Distraction Free Settings: Afleidingsvrij Kijken\n    Hide Active Subscriptions: Actieve abonnementen verbergen\n    Hide Playlists: Afspeel­lĳsten verbergen\n    Hide Sharing Actions: Deel­acties verbergen\n    Hide Videos on Watch: 'Bekeken video''s verbergen'\n    Hide Video Description: Video-omschrijving verbergen\n    Hide Comments: Opmerkingen verbergen\n    Hide Live Streams: Live­streams verbergen\n    Display Titles Without Excessive Capitalisation: Titels tonen zonder overmatig hoofdletter­gebruik en inter­punctie\n    Sections:\n      Side Bar: Zijbalk\n      General: Algemeen\n      Subscriptions Page: Abonnementen-pagina\n      Channel Page: Kanaal­pagina\n      Watch Page: Kijken-pagina\n    Hide Chapters: Hoofdstukken verbergen\n    Hide Upcoming Premieres: Aankomende premières verbergen\n    Hide Featured Channels: Uitgelichte kanalen verbergen\n    Hide Channel Playlists: 'Kanaal­tabblad ‘Afspeel­lĳsten’ verbergen'\n    Hide Channels: Video's van kanalen verbergen\n    Hide Channels Placeholder: Kanaal-ID\n    Hide Channel Podcasts: Kanaal­tabblad ‘Podcasts’ verbergen\n    Hide Channel Releases: Kanaal­tabblad ‘Uitgaven’ verbergen\n    Hide Subscriptions Videos: Abonnement­video's verbergen\n    Hide Subscriptions Live: Abonnement-live-videos verbergen\n    Hide Channel Shorts: Kanaal­tabblad ‘Shorts’ verbergen\n    Hide Subscriptions Shorts: Abonnement-Shorts verbergen\n    Hide Profile Pictures in Comments: Profielfoto's in opmerkingen verbergen\n    Hide Channels Already Exists: Kanaal-id bestaat al\n    Hide Channels Invalid: Opgegeven kanaal-id is ongeldig\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Woord, woord­fragment of zin\n    Hide Videos, Playlists and Channels Containing Text: Video's en afspeel­lijsten die tekst bevatten verbergen\n    Hide Channels API Error: Fout bij het ophalen van de gebruiker met de opgegeven id. Controleer nog­maals of de id correct is.\n    Hide Channels Disabled Message: Sommige kanalen zijn geblokkeerd met behulp van ID en zijn niet verwerkt. De functie is geblokkeerd terwijl deze ID's worden bij­gewerkt\n    Show Added Items: Toegevoegde Items Weergeven\n    Hide Channel Home: Kanaal­tabblad ‘Thuis’ verbergen\n    Hide Channel Courses: Kanaal­tabblad ‘Cursussen’ verbergen\n    Hide Channel Posts: Kanaal­tabblad ‘Berichten’ verbergen\n    Hide Subscriptions Posts: Verberg berichten van abonnementen\n  The app needs to restart for changes to take effect. Restart and apply change?: Het programma moet opnieuw worden gestart voordat de veranderingen effect hebben. Wilt u het programma nu opnieuw starten en de veranderingen toepassen?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Fout bij het opvragen van netwerkinformatie. Is uw proxy correct geconfigureerd?\n    City: Stad\n    Region: Regio\n    Country: Land\n    Ip: IP\n    Your Info: Uw informatie\n    Test Proxy: Proxy testen\n    Clicking on Test Proxy will send a request to: Door op Test Proxy te klikken zal er een verzoek worden verstuurd naar\n    Proxy Port Number: Poortnummer proxy\n    Proxy Host: Proxyhost\n    Proxy Protocol: Proxyprotocol\n    Enable Tor / Proxy: Tor / proxy inschakelen\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube heeft geen ingeboude proxy maar kan verbinden via een externe proxy zoals een proxy op dit apparaat (Bijvoorbeeld Tor) of een externe proxy zoals een SOCKS5 proxy verstrekt door sommige VPNs. Wanneer ingeschakeld, zorg ervoor dat de proxy of Tor correct ingesteld is anders lan FreeTube geen data verkrijgen.\n    Proxy Username: Proxy-gebruikers­naam\n    Proxy Password: Proxy-wacht­woord\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Mij informeren wanneer een gesponsord segment wordt overgeslagen\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL naar API van SponsorBlock (Standaard is https://sponsor.ajay.app)\n    Enable SponsorBlock: SponsorBlock inschakelen\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Show In Seek Bar: Weergeven in zoekbalk\n      Skip Option: Overslaan-optie\n      Auto Skip: Automatisch overslaan\n      Prompt To Skip: Vragen om over te slaan\n      Do Nothing: Niets doen\n    Category Color: Categorie­kleur\n    UseDeArrowTitles: DeArrow-videotitels gebruiken\n    UseDeArrowThumbnails: DeArrow gebruiken voor miniaturen\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': API-URL van DeArrow-miniatuur­generator (standaard is https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Aangepaste argumenten voor externe videospeler\n    Custom External Player Executable: Uitvoerbaar bestand van externe videospeler instellen\n    Ignore Unsupported Action Warnings: Waarschuwingen voor niet-ondersteunde acties negeren\n    External Player: Externe videospeler\n    External Player Settings: Externe Mediaspeler\n    Players:\n      None:\n        Name: Geen\n    Ignore Default Arguments: Standaard­argumenten negeren\n  Parental Control Settings:\n    Hide Unsubscribe Button: Deabonneer­knop verbergen\n    Parental Control Settings: Ouderlijk toezicht\n    Show Family Friendly Only: Enkel familievriendelijke inhoud tonen\n    Hide Search Bar: Zoek­balk verbergen\n    Hide Uploader on Watch page: Uploader verbergen op pagina ‘Bekĳken’\n  Experimental Settings:\n    Warning: Dit zijn experimentele instellingen, die een crash kunnen veroorzaken. Het is raadzaam backups te maken. Gebruiken op eigen risico!\n    Experimental Settings: Experimentele Instellingen\n    Replace HTTP Cache: HTTP-cache vervangen\n  Password Settings:\n    Set Password: Wachtwoord instellen\n    Remove Password: Wachtwoord verwijderen\n    Password Settings: Wachtwoord­en\n    Set Password To Prevent Access: Stel een wachtwoord in om toegang tot instellingen te beperken\n  Password Dialog:\n    Password: Wachtwoord\n    Enter Password To Unlock: Voer wachtwoord in om instellingen te ontgrendelen\n  Sort Settings Sections (A-Z): Instellingen secties sorteren (A-Z)\n  Return to Settings Menu: Terugkeren naar instellingen menu\nAbout:\n  #On About page\n  About: 'Over'\n  #& About\n#On Channel Page\n  Donate: Doneren\n  these people and projects: deze mensen en projecten\n  Credits: Met dank aan\n  Translate: Vertalen\n  room rules: kamerregels\n  Chat on Matrix: Chat op Matrix\n  Mastodon: Mastodon\n  Email: E-mail\n  Blog: Blog\n  Website: Website\n  Please check for duplicates before posting: Controleer eerst of een probleem al gerapporteerd is\n  GitHub issues: GitHub-issues\n  Report a problem: Probleem melden\n  FAQ: Veelgestelde vragen\n  FreeTube Wiki: FreeTube-wiki\n  Help: Hulp\n  GitHub releases: GitHub-uitgaven\n  Downloads / Changelog: Downloads en wijzigings­logboek\n  Source code: Broncode\n  Beta: Bèta\n  Discussions: Discussies\n  AGPLv3: AGPLv3\nChannel:\n  Subscribe: 'Abonneren'\n  Unsubscribe: 'Deabonneren'\n  Search Channel: 'Kanaal zoeken'\n  Your search results have returned 0 results: 'Uw zoekactie heeft 0 resultaten opgeleverd'\n  Videos:\n    Videos: 'Video''s'\n    This channel does not currently have any videos: 'Dit kanaal heeft op dit moment nog geen video''s'\n    Sort Types:\n      Newest: 'Nieuwste'\n      Oldest: 'Oudste'\n      Most Popular: 'Populairst'\n  Playlists:\n    Playlists: 'Afspeellijsten'\n    This channel does not currently have any playlists: 'Dit kanaal heeft momenteel nog geen afspeellijsten'\n    Sort Types:\n      Last Video Added: 'Laatst toegevoegde video'\n      Newest: 'Nieuwste'\n      Oldest: 'Oudste'\n  About:\n    About: 'Over'\n    Channel Description: 'Kanaalbeschrijving'\n    Featured Channels: 'Uitgelichte kanalen'\n    Tags:\n      Search for: Zoek naar ‘{tag}’\n      Tags: Tags\n    Location: Locatie\n    Details: Details\n    Joined: Lid sinds\n  Added channel to your subscriptions: Kanaal is toegevoegd aan uw abonnementen\n  Removed subscription from {count} other channel(s): Abonnementen van {count} andere kanalen zijn verwijderd\n  Channel has been removed from your subscriptions: Kanaal is verwijderd uit uw abonnementen\n  Channel Tabs: Kanaal­tabbladen\n  Live:\n    Live: Live\n    This channel does not currently have any live streams: Dit kanaal heeft momenteel geen livestreams\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Dit kanaal heeft momenteel geen podcasts\n  Posts:\n    Posts: Posts\n    Reveal Answers: Antwoorden onthullen\n    Hide Answers: Antwoorden verbergen\n    votes: '{votes} stemmen'\n    This channel currently does not have any posts: Dit kanaal heeft momenteel geen posts\n    Video hidden by FreeTube: Video verborgen door FreeTube\n    Viewing Posts Only Supported By Invidious: Posts bekijken wordt alleen ondersteund door Invidious. Ga naar het community-tabblad van een kanaal om content te bekijken zonder Invidious.\n    View Full Post: Volledige Post Weergeven\n  Releases:\n    Releases: Uitgaven\n    This channel does not currently have any releases: Dit kanaal heeft momenteel geen uitgaven\n  This channel does not exist: Dit kanaal bestaat niet\n  This channel does not allow searching: Dit kanaal staat zoeken niet toe\n  Shorts:\n    This channel does not currently have any shorts: Dit kanaal heeft momenteel geen Shorts\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Dit kanaal heeft een leeftijdsbeperking en kan momenteel niet worden bekeken in FreeTube.\n  Home:\n    View Playlist: Afspeel­lĳst tonen\n    Home: Thuis\n  Courses:\n    Courses: Cursussen\n    This channel does not currently have any courses: Dit kanaal heeft momenteel geen cursussen\nVideo:\n  Mark As Watched: 'Markeren als bekeken'\n  Remove From History: 'Uit geschiedenis verwijderen'\n  Video has been marked as watched: 'Video is gemarkeerd als bekeken'\n  Video has been removed from your history: 'Video is verwijderd uit uw geschiedenis'\n  Open in YouTube: 'In YouTube openen'\n  Copy YouTube Link: 'YouTube-link kopiëren'\n  Open YouTube Embedded Player: 'Embedded YouTube videospeler openen'\n  Copy YouTube Embedded Player Link: 'YouTube videospeler-insluitlink kopiëren'\n  Open in Invidious: 'In Invidious openen'\n  Copy Invidious Link: 'Invidious-link kopiëren'\n  Views: 'Weergaven'\n  Watched: 'Bekeken'\n  # As in a Live Video\n  Live: 'Live'\n  Live Now: 'Nu live'\n  Live Chat: 'Livechat'\n  Enable Live Chat: 'Livechat inschakelen'\n  Live Chat is currently not supported in this build.: 'Livechat wordt in deze versie nog niet ondersteund.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Livechat is ingeschakeld. Chats zullen hier verschijnen.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Livechat wordt momenteel niet ondersteund door de Invidious API. Een directe verbinding met YouTube is nodig.'\n  Published:\n    In less than a minute: In minder dan één minuut\n  Published on: 'Gepubliceerd op'\n#& Videos\n  Autoplay: Automatisch afspelen\n  Previous: Vorige\n  Next: Volgende\n  Reverse Playlist: Afspeellijst omkeren\n  Shuffle Playlist: Afspeellijst in willekeurige volgorde afspelen\n  Loop Playlist: Playlist herhalen\n  Starting soon, please refresh the page to check again: Start binnenkort, vernieuw de pagina om opnieuw te controleren\n  Copy Invidious Channel Link: Kopieer Invidious-kanaallink\n  Open Channel in Invidious: Open Kanaal op Invidious\n  Copy YouTube Channel Link: Link naar YouTubekanaal kopiëren\n  Open Channel in YouTube: YouTube-kanaal openen\n  Started streaming on: Gestart met streamen op\n  Streamed on: Gestreamd op\n  Video has been removed from your saved list: Video is verwijderd uit uw lijst van opgeslagen video's\n  Video has been saved: Video is opgeslagen\n  Save Video: Video opslaan\n  Sponsor Block category:\n    music offtopic: Niet-muziek\n    interaction: Interactie\n    self-promotion: Zelfpromotie\n    outro: Outro\n    intro: Intro\n    sponsor: Sponsor\n    recap: Samenvatting\n    filler: Opvulling\n  External Player:\n    Unsupported Actions:\n      shuffling playlists: afspeellijsten shufflen\n      reversing playlists: afspeellijsten omkeren\n      opening specific video in a playlist (falling back to opening the video): specifieke video in een afspeellijst openen (terugvallen tot het openen van de video)\n      opening playlists: afspeellijsten openen\n      setting a playback rate: afspeelsnelheid instellen\n      looping playlists: afspeellijsten herhalen\n      starting video at offset: begin afspelen video bij offset\n    UnsupportedActionTemplate: '{externalPlayer} ondersteund niet: {action}'\n    OpeningTemplate: '{videoOrPlaylist} Openen in {externalPlayer}...'\n    playlist: afspeellijst\n    video: video\n    OpenInTemplate: Openen in {externalPlayer}\n  Premieres: Premières\n  Scroll to Bottom: Helemaal naar onderen scrollen\n  Upcoming: Aankomend\n  Show Super Chat Comment: Superchat-opmerking tonen\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Live-chat is niet beschikbaar voor deze stream. Mogelijk is deze uitgeschakeld door de uploader.\n  Hide Channel: Kanaal verbergen\n  Unhide Channel: Kanaal tonen\n  More Options: Meer opties\n#& Playlists\n  Player:\n    Show Stats: Statistieken Weergeven\n    Take Screenshot: Schermopname Maken\n    Stats:\n      Resolution: 'Resolutie: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Speler Groote: {width}x{height}'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n      Bitrate: 'Bitrate: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Bandwidth: 'Bandbreedte: {bandwidth} kbps'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      Media Formats: 'Media Formaten: {formats}'\n      Buffered: 'Gebufferd: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Vervallen Aantal Frames: {droppedFrames} / Totaal Aantal Frames: {totalFrames}'\n      Video ID: 'Video ID: {videoId}'\n      Stats: Statistieken\n    Audio Tracks: Audiosporen\n    TranslatedCaptionTemplate: '{language} (vertaald vanuit \"{originalLanguage}\")'\n    Playback will resume automatically when your connection comes back: Het afspelen hervat automatisch wanneer u weer verbonden bent.\n    Skipped segment: '{segmentCategory} segment overgeslagen'\n    Full Window: Volledig Venster\n    Exit Full Window: Volledig Venster Sluiten\n    You appear to be offline: Het lijkt erop dat u offline bent.\n    Autoplay is off: Automatisch afspelen staat uit\n    Autoplay is on: Automatisch afspelen staat aan\n    Exit Theatre Mode: Theater Modus Verlaten\n    Theatre Mode: Theater modus\n    Hide Stats: Statistieken Verbergen\n  IP block: Youtube heeft uw IP adres geblokkeerd. Hierdoor kan u geen videos meer kijken. Probeer om naar een andere VPN of proxy te wisselen.\n  DRMProtected: Videos die beschermd worden door DRM (Digital Rights Management) kunnen niet worden afgespeeld in FreeTube omdat ze beschermde closed source onderdelen vereisen. Als u deze video wilt bekijken, probeer het dan via de officiële YouTube website met een web browser die DRM ondersteund.\n  Unlisted: Verborgen\n  DeArrow:\n    Show Original Details: Oorspronkelijke Details Weergeven\n    Show Modified Details: Aangepaste Details Weergeven\n  MembersOnly: Members-only videos kunnen niet bekeken worden via FreeTube omdat ze een Google login en betaald abonnement op het kanaal van de uploader vereisen.\n  AgeRestricted: Videos met een leeftijdsbeperking kunnen niet via FreeTube bekeken worden omdat ze een Google login en een YouTube account met bevestigde leeftijd vereisen.\n  Save Watched Progress: Kĳk­voortgang opslaan\n  Watched Progress Saved: Kĳk­voortgang opgeslagen\nPlaylist:\n  #& About\n  View Full Playlist: 'Volledige afspeellijst bekijken'\n  Last Updated On: 'Laatst bijgewerkt op'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Afspeellijst\n  Sort By:\n    DateAddedNewest: Datum toegevoegd (Nieuwste)\n    AuthorAscending: Auteur (A-Z)\n    AuthorDescending: Auteur (Z-A)\n    VideoTitleAscending: Titel (A-Z)\n    VideoTitleDescending: Titel (Z-A)\n    DateAddedOldest: Datum toegevoegd (Oudste)\n    Custom: Aangepast\n    PublishedOldest: Publiceringsdatum (Oudste)\n    PublishedNewest: Publiceringsdatum (Nieuwste)\n    VideoDurationDescending: Lengte (Langste)\n    VideoDurationAscending: Lengte (Kortste)\nChange Format:\n  Change Media Formats: 'Videoformaten veranderen'\n  Use Dash Formats: 'DASH-formaten gebruiken'\n  Use Legacy Formats: 'Verouderde formaten gebruiken'\n  Use Audio Formats: 'Audioformaten gebruiken'\n  Audio formats are not available for this video: Audio formaten zijn niet beschikbaar voor deze video\n  Dash formats are not available for this video: DASH formaten zijn niet beschikbaar voor deze video\n  Legacy formats are not available for this video: Legacy formaten zijn niet beschikbaar voor deze video\nShare:\n  Share Video: 'Video delen'\n  Share Playlist: 'Afspeellijst delen'\n  Copy Link: 'Koppeling kopiëren'\n  Open Link: 'Koppeling openen'\n  Copy Embed: 'Insluitlink kopiëren'\n  Open Embed: 'Insluitlink openen'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-URL is naar het klembord gekopieerd'\n  Invidious Embed URL copied to clipboard: 'Invidious Insluitlink is naar het klembord gekopieerd'\n  YouTube URL copied to clipboard: 'YouTube-URL is naar het klembord gekopieerd'\n  YouTube Embed URL copied to clipboard: 'YouTube Insluitlink is gekopieerd naar het klemboard'\n  Include Timestamp: Inclusief tijdstempel\n  YouTube Channel URL copied to clipboard: YouTube URL is gekopieerd naar het klembord\n  Invidious Channel URL copied to clipboard: Invidiouskanaal-URL is naar het klembord gekopieerd\n  Share Channel: Kanaal delen\n  Share Post: Post delen\nMini Player: 'Mini­speler'\nComments:\n  Comments: 'Opmerkingen'\n  Click to View Comments: 'Klik om reacties te tonen'\n  Getting comment replies, please wait: 'Reacties worden verzameld, even geduld aub'\n  Hide Comments: 'Opmerkingen verbergen'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Er zijn geen reacties beschikbaar voor deze video'\n  Load More Comments: 'Meer opmerkingen laden'\n  There are no more comments for this video: Er zijn geen verdere reacties op deze video\n  Newest first: Nieuwste eerst\n  Top comments: Beste opmerkingen\n  Show More Replies: Meer reacties tonen\n  Pinned by: Vastgemaakt door\n  Member: Lid\n  Hearted: Met hartje\n  View {replyCount} replies: '1 reactie bekijken | {replyCount} reacties bekijken'\n  Subscribed: Geabonneerd\n  There are no comments available for this post: Er zijn geen reacties beschikbaar voor deze post\n  Hide {replyCount} replies: 1 reactie verbergen | Verberg {replyCount} reacties\n  View 1 reply from {channelName}: Bekijk 1 reactie van {channelName}\n  View {replyCount} replies from {channelName} and others: '{replyCount} reacties van {channelName} en anderen bekijken'\nUp Next: 'Volgende'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Fout in lokale API (Klik om te kopiëren)'\nInvidious API Error (Click to copy): 'Fout in API van Invidious (Klik op te kopiëren)'\nFalling back to Invidious API: 'Terugvallen op Invidious API'\nFalling back to Local API: 'Terugvallen op lokale API'\nLoop is now disabled: 'Herhalen is nu uitgeschakeld'\nLoop is now enabled: 'Herhalen is nu ingeschakeld'\nShuffle is now disabled: 'Willekeurig afspelen is nu uitgeschakeld'\nShuffle is now enabled: 'Willekeurig afspelen is nu ingeschakeld'\nPlaying Next Video: 'Volgende video afspelen'\nPlaying Previous Video: 'Vorige video afspelen'\nCanceled next video autoplay: 'Automatisch afspelen is geannuleerd'\n'The playlist has ended. Enable loop to continue playing': 'Het einde van de afspeellijst is bereikt.  Schakel herhalen in om de afspeellijst te blijven afspelen'\n\nYes: 'Ja'\nNo: 'Nee'\nThe playlist has been reversed: De afspeellijst is omgedraaid\nProfile:\n  '{profile} is now the active profile': '{profile} is nu het actieve profiel'\n  Your default profile has been changed to your primary profile: Uw standaardprofiel is veranderd naar uw hoofdprofiel\n  Removed {profile} from your profiles: '{profile} is verwijderd uit uw profielen'\n  Your default profile has been set to {profile}: Uw standaard profiel is ingesteld op {profile}\n  Profile has been updated: Profiel is bijgewerkt\n  Profile has been created: Profiel is aangemaakt\n  Your profile name cannot be empty: Uw profielnaam mag niet leeg zijn\n  All subscriptions will also be deleted.: Alle abonnementen zullen ook worden verwijderd.\n  Are you sure you want to delete this profile?: Weet u zeker dat u dit profiel wilt verwijderen?\n  Delete Profile: Profiel verwijderen\n  Make Default Profile: Als standaard­profiel instellen\n  Update Profile: Profiel bijwerken\n  Create Profile: Profiel aanmaken\n  Profile Preview: Profielvoorbeeld\n  Custom Color: Eigen kleur\n  Color Picker: Kleurselectie\n  Edit Profile: Profiel aanpassen\n  Create New Profile: Nieuw profiel aanmaken\n  Profile Manager: Profiel­beheer\n  All Channels: Alle kanalen\n  Profile Select: Profiel­selectie\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Weet u zeker dat u de geselecteerde kanalen wil verwijderen? Deze actie zal de geselecteerde kanalen niet uit andere profielen verwijderen.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Dit is u primaire profiel. Weet u zeker dat u de geselecteerde kanalen wil verwijderen? Dezelfde kanalen zullen worden verwijderd uit andere profielen.\n  No channel(s) have been selected: Er zijn geen kanalen geselecteerd\n  Add Selected To Profile: Selectie aan profiel toevoegen\n  Delete Selected: Selectie verwijderen\n  Select None: Niks selecteren\n  Select All: Alles selecteren\n  '{number} selected': '{number} geselecteerd'\n  Other Channels: Andere kanalen\n  Subscription List: Abonnementen\n  Profile Filter: Profielfilter\n  Profile Settings: Profiel\n  Toggle Profile List: Profiellijst omschakelen\n  Profile Name: Profiel­naam\n  Edit Profile Name: Profiel­naam wijzigen\n  Create Profile Name: Profiel­naam aanmaken\n  Close Profile Dropdown: Profiel­menu sluiten\n  Open Profile Dropdown: Profiel­menu openen\nA new blog is now available, {blogTitle}. Click to view more: 'Een nieuwe blogpost is beschikbaar: {blogTitle}. Klik voor meer informatie'\nDownload From Site: Van website downloaden\nVersion {versionNumber} is now available!  Click for more details: Versie {versionNumber} is nu beschikbaar! Klik voor meer informatie\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Deze video is niet beschikbaar vanwege ontbrekende videoformaten. Dit kan gebeuren als de video niet in uw land beschikbaar is.\nTooltips:\n  Player Settings:\n    Default Video Format: Selecteer de video indeling die wordt gebruikt wanneer u een video afspeelt. DASH kan video's afspelen met hogere kwaliteitsinstellingen. Legacy gaat niet hoger dan 360p maar gebruikt minder bandbreedte. Audio zal alleen het geluid streamen.\n    Proxy Videos Through Invidious: FreeTube zal verbinden met Invidious en daar de video's downloaden in de plaats van de video's rechtstreeks bij YouTube vandaan te halen.\n    Scroll Playback Rate Over Video Player: Terwijl de muis zich over de video bevindt, houd de Control-toets (Command-toets op Mac) ingedrukt en scroll met de muis om de afspeelsnelheid te besturen. Houd de Control-toets (Command-toets op Mac) ingedrukt en klik met de linker muisknop om snel terug te schakelen naar de standaard afspeelsnelheid (1x tenzij aangepast in de instellingen).\n    Skip by Scrolling Over Video Player: Gebruik het scroll-wieltje om door de video te spoelen, zoals bij MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: Wanneer ingeschakeld zal FreeTube RSS gebruiken in plaats van de standaard­methode om uw abonnementen­feed op te halen. RSS is sneller en voorkomt IP-blokkering, maar geeft geen toegang tot sommige informatie zoals de video­duur, live-status en berichten\n    Fetch Automatically: Indien ingeschakeld, haalt FreeTube automatisch uw abonnementen­feed op bĳ het opstarten en wanneer een nieuw venster wordt geopend.\n  General Settings:\n    Invidious Instance: Dit is de Invidious-instantie waar FreeTube mee zal verbinden om API calls te maken.\n    Thumbnail Preference: Alle miniaturen in FreeTube zullen worden vervangen met een moment­opname uit de video, worden vervaagd, of worden verborgen, in plaats van de standaard­miniatuur.\n    Fallback to Non-Preferred Backend on Failure: Wanneer het API met voorkeur problemen geeft dan zal FreeTube automatisch terugvallen op het alternatieve niet-voorkeur API wanneer deze instelling is ingeschakeld.\n    Preferred API Backend: Kies de backend die FreeTube gebruikt om data te verzamelen. De lokale API is een ingebouwde inhoudsverzamelaar. De Invidious API moet worden verbonden met een Invidious server.\n    Region for Trending: Met trend regio kan je instellen uit welk land je trending video's je wil zien.\n    External Link Handling: \"Kies het standaard gedrag voor wanneer een link dat niet kan worden geopend in FreeTube is aangeklikt.\\nStandaard zal FreeTube de aangeklikte link openen in je standaardbrowser.\\n\"\n    Open Deep Links In New Window: URLs die aan FreeTube doorgegeven worden zoals doorverwijzingen van browser extensies of opdrachtenprompt argumenten worden geopend in een nieuw venster.\n  External Player Settings:\n    Custom External Player Arguments: Aangepaste opdrachtregelargumenten, die je wil doorgeven aan de externe videospeler.\n    Ignore Warnings: Onderdruk waarschuwingen wanneer de geselecteerde videospeler een opgegeven actie niet ondersteund (bijv. afspeellijsten omkeren, etc.).\n    Custom External Player Executable: Standaard gaat FreeTube er vanuit dat de gekozen videospeler kan worden benaderd via het PATH omgevingsvariabele. Wanneer nodig kan er hier een aangepast pad worden ingevoerd.\n    External Player: 'Door het kiezen van een externe videospeler zal er een icoontje verschijnen op de miniatuur waarmee de video (of afspeellijst indien ondersteund) in de gekozen externe videospeler kan worden geopend. Let op: Invidious-instellingen beïnvloeden externe videospelers niet.'\n    DefaultCustomArgumentsTemplate: \"(standaard: ‘{defaultCustomArguments}’)\"\n    Ignore Default Arguments: Stuurt geen standaard­argumenten naar de externe speler, afgezien van de video-URL (bij­voorbeeld afspeel­snelheid, afspeellijst-URL, enz.). Aan­gepaste argumenten worden nog steeds door­gegeven.\n  Distraction Free Settings:\n    Hide Channels: Voer een kanaal-ID in om alle video's, afspeel­lijsten en het kanaal zelf te verbergen zodat ze niet worden weer­gegeven in zoeken, trending, populairst en aan­bevolen. De ingevoerde kanaal-ID moet volledig overeen­komen en is hoofdletter­gevoelig.\n    Hide Subscriptions Live: Deze instelling wordt overschreven door de app-brede instelling ‘{appWideSetting}’, in het gedeelte ‘{subsection}’ van ‘{settingsSection}’\n    Hide Videos, Playlists and Channels Containing Text: Voer een woord, woord­fragment of woord­groep in (niet hoofdletter­gevoelig) om alle video's en afspeel­lijsten waarvan de oorspronkelijke titel dit bevat, in heel FreeTube te verbergen, met uit­zondering van alleen geschiedenis, uw afspeel­lijsten en video's in afspeel­lijsten.\n    Hide Videos on Watch: Verbergt bekeken video's op de tabbladen Video's, Shorts en Live; op de pagina's Abonnementen en Kanalen. Dit heeft geen invloed op het tabblad Thuis op kanaal­pagina's\n  SponsorBlock Settings:\n    UseDeArrowTitles: Vervangt videotitels met door gebruikers ingediende titels van DeArrow.\n    UseDeArrowThumbnails: Video­miniaturen vervangen met miniaturen van DeArrow.\n  Experimental Settings:\n    Replace HTTP Cache: Schakelt de schijfgebaseerde HTTP-cache van Electron uit en schakelt een aangepaste afbeeldings­cache in het geheugen in. Zal leiden tot een verhoogd RAM-gebruik.\nPlaying Next Video Interval: Volgende video wordt afgespeeld. Klik om te onderbreken. | Volgende video wordt afgespeeld in {nextVideoInterval} seconde. Klik om te onderbreken. | Volgende video wordt afgespeeld in {nextVideoInterval} seconden. Klik om te onderbreken.\nMore: Meer\nUnknown YouTube url type, cannot be opened in app: Onbekende YouTube-URL; de URL kan niet worden geopend in de app\nOpen New Window: Nieuw venster openen\nDefault Invidious instance has been cleared: Standaard Invidious-instantie is verwijderd\nDefault Invidious instance has been set to {instance}: Standaard Invidious-instantie is ingesteld op {instance}\nAre you sure you want to open this link?: Weet u zeker dat u deze link wilt openen?\nSearch Bar:\n  Clear Input: Invoer wissen\n  Remove: Verwĳderen\nExternal link opening has been disabled in the general settings: Het openen van externe links is uitgeschakeld in de algemene instellingen\nNew Window: Nieuw Venster\nScreenshot Success: Schermafbeelding opgeslagen\nChannels:\n  Title: Kanaal­lĳst\n  Search bar placeholder: Kanalen zoeken\n  Count: '{number} kanaal/kanalen gevonden.'\n  Channels: Kanalen\n  Empty: Uw kanaal­lĳst is momenteel leeg.\n  Unsubscribe Prompt: Weet u zeker dat u zich van ‘{channelName}’ wilt deabonneren?\nScreenshot Error: Schermafbeelding kon niet worden opgeslagen. {error}\nPreferences: Voorkeuren\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Deze hashtag heeft momenteel geen video's\nOk: Oké\nChapters:\n  Chapters: Hoofdstukken\n  Key Moments: Belangrijke Momenten\nClipboard:\n  Cannot access clipboard without a secure connection: Geen toegang tot klembord zonder een beveiligde verbinding\n  Copy failed: Kopiëren naar klembord mislukt\nGo to page: Pagina {page}\nTag already exists: Tag ‘{tagName}’ bestaat al\nChannel Unhidden: ‘{channel}’ verwijderd uit kanaal­filter\nChannel Hidden: ‘{channel}’ toe­gevoegd aan kanaal­filter\nClose Banner: Banner sluiten\nAge Restricted:\n  This channel is age restricted: Dit kanaal heeft een leeftijds­beperking\n  This video is age restricted: Deze video heeft een leeftijds­beperking\nTrimmed input must be at least N characters long: Bij­gesneden invoer moet minimaal 1 teken lang zijn | Bij­gesneden invoer moet minimaal {length} tekens lang zijn\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nYes, Delete: Ja, verwĳderen\nYes, Restart: Ja, herstarten\nFeed:\n  Feed Last Updated: 'Feed \"{feedName}\" laatst bĳgewerkt op: \"{date}\"'\n  Refresh Feed: '\"{subscriptionName}\" verversen'\nYes, Open Link: Ja, link openen\nCancel: Annuleren\nMoments Ago: momenten geleden\nSearch character limit: Zoekopdracht overschrĳdt de tekemlimiet van {searchCharacterLimit}\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Ondertiteling\n    Closed Captions: Ingesloten ondertiteling\n    3D: 3D\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nieuw\nRight-click or hold to see history: Rechtsklik of houd vast om kĳk­geschiedenis weer te geven\nDescription:\n  Collapse Description: Minder Weergeven\n  Expand Description: '...meer'\nKeyboardShortcutPrompt:\n  Play: Afspelen en pauzeren wisselen\n  Volume Up: Volume verhogen\n  Theatre Mode: Theater modus wisselen\n  History Forward: Een pagina vooruit gaan\n  Mute: Dempen wisselen\n  Toggle Developer Tools: Developer Tools wisselen\n  Search in New Window: Zoeken in een nieuw venster\n  Last Frame: Vorige frame (tijdens pauze)\n  Small Fast Forward: X seconden doorspoelen op basis van de Doorspoelinterval en de huidige Afspeelsnelheid\n  Last Chapter: Laatste hoofd­stuk\n  Skip by Tenths: Delen van video overslaan via percentage (3x overslaan voor 30% van de lengte)\n  Large Fast Forward: 10 seconden vooruitspoelen / Vooruitspoelen op basis van de huidige Afspeelsnelheid\n  New Window: Een nieuw venster openen\n  Navigate to History: Naar geschiedenis pagina navigeren\n  Navigate to Settings: Naar instellingen pagina navigeren\n  Focus Secondary Search: Focus naar de secundaire zoekbalk verplaatsen (als deze aanwezig is)\n  Captions: Schakel ondertiteling AAN/UIT\n  Stats: Video statistieken weergeven\n  Minimize Window: Venster minimaliseren\n  Take Screenshot: Schermopname maken\n  Focus Search: Focus naar de zoekbalk verplaatsen\n  Zoom In: Inzoomen\n  Volume Down: Volume verminderen\n  Next Chapter: Volgend hoofd­stuk\n  Sections:\n    App:\n      Situational: 'App: Afhankelijk van de Situatie'\n      General: App: Algemeen\n    Video:\n      General: Video: Algemeen\n      Playback: Video: Afspelen\n  Refresh: Feed vernieuwen met nieuwste inhoud\n  Picture in Picture: Picture-in-Picture modus wisselen\n  Next Frame: Volgende frame (tijdens pauze)\n  Small Rewind: X seconden terugspoelen op basis van de Terugspoelinterval en de huidige Afspeelsnelheid\n  Keyboard Shortcuts: Sneltoetsen\n  Show Keyboard Shortcuts: Sneltoetsen weergeven\n  History Backward: Een pagina terug gaan\n  Fullscreen: Fullscreen wisselen\n  Large Rewind: 10 seconden terugspoelen/ Video terugspoelen op basis van de huidige Afspeelsnelheid\n  Full Window: Volledig venster wisselen\n  Reset Zoom: Reset zoom niveau / UI groote\n  Close Window: Venster sluiten\n  Zoom Out: Uitzoomen\n  Decrease Video Speed: Videosnelheid verminderen op basis van Afspeelsnelheid\n  Increase Video Speed: Videosnelheid verhogen op basis van Afspeelsnelheid\n  Home: Terug­spoelen naar het begin van de video\n  End: Verder­spoelen naar het eind van de video\n  Skip to Next Video: Naar de volgende video in een afspeel­lĳst of de volgende aanbevolen video gaan\n  Skip to Previous Video: Naar de vorige video in een afspeel­lĳst gaan\nshortcutLabelSeparator: ｜\nKeys:\n  alt: Alt\n  arrowleft: Pijltjestoets Naar Links\n  arrowright: Pijltjestoets Naar Rechts\n  arrowup: Pijltjestoets Naar Boven\n  ctrl: Ctrl\n  arrowdown: Pijltjestoets Naar Beneden\n  shift: Shift\n  enter: Enter\n  plus: Plus\nAutoplay Interruption Timer: Automatisch afspelen geannuleerd door {autoplayInterruptionIntervalHours} uur aan inactiviteit\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nCompact side navigation: Minimaliseer Zijbar\n"
  },
  {
    "path": "static/locales/nn.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Norsk nynorsk'\n\n# Webkit Menu Bar\nFile: 'Fil'\nQuit: 'Avslutt'\nEdit: 'Rediger'\nUndo: 'Angre'\nRedo: 'Gjenta'\nCut: 'Klipp'\nCopy: 'Kopier'\nPaste: 'Lim'\nDelete: 'Fjern'\nSelect all: 'Vel alle'\nToggle Developer Tools: 'Veksle utviklarverktøy'\nActual size: 'Originalstorleik'\nZoom in: 'Forstørr'\nZoom out: 'Forminsk'\nToggle fullscreen: 'Veksle fullskjerm'\nWindow: 'Vindauge'\nMinimize: 'Minimer'\nClose: 'Lukk'\nBack: 'Tilbake'\nForward: 'Framover'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videoar'\n\n  Counts:\n    Comment Count: 1 kommentar | {count} kommentarar\n    Video Count: 1 video | {count} videoar\n    Channel Count: 1 kanal | {count} kanalar\n    Subscriber Count: 1 abonnent | {count} abonnentar\n    View Count: 1 visning | {count} visningar\n  Shorts: Shorts-videoer\n  Live: Direkte\n  Posts: Innlegg\n  Sort By: 'Sorter etter'\nVersion {versionNumber} is now available!  Click for more details: 'Versjon {versionNumber} er no tilgjengeleg! Klikk for meir informasjon'\nDownload From Site: 'Last ned frå nettstaden'\nA new blog is now available, {blogTitle}. Click to view more: 'Eit nytt blogginnlegg er tilgjengeleg, {blogTitle}. Klikk her for å sjå meir'\n\n# Search Bar\nSearch / Go to URL: 'Søk/gå til nettadresse'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Søkefilter'\n  Sort By:\n    Most Relevant: 'Mest relevant'\n    Rating: 'Vurdering'\n    Upload Date: 'Opplastingsdato'\n    View Count: 'Sjåartal'\n  Time:\n    Time: 'Tid'\n    Any Time: 'Når som helst'\n    Last Hour: 'Den siste timen'\n    Today: 'I dag'\n    This Week: 'Denne veka'\n    This Month: 'Denne månaden'\n    This Year: 'Dette året'\n  Type:\n    Type: 'Type'\n    All Types: 'Alle typar'\n    Videos: 'Videoar'\n    Channels: 'Kanalar'\n    #& Playlists\n  Duration:\n    Duration: 'Varigheit'\n    All Durations: 'Alle varigheitene'\n    Short (< 4 minutes): 'Kort (< 4 minutt)'\n    Long (> 20 minutes): 'Lang (> 20 minutt)'\n  # On Search Page\n  Search Results: 'Søkeresultat'\n  Fetching results. Please wait: 'Henter resultat. Ver venleg og vent'\n  Fetch more results: 'Hent fleire resultat'\n  There are no more results for this search: 'Det er inga fleire resultat for dette søket'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnement'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Denne profilen har ei stor mengd abonnentar. Tvinger RSS til å unngå å avgrense hastigheita'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Di abonnementliste er tom for augeblikket. Start å legge til fleire abonnement for å sjå dei her.'\n  Load More Videos: 'Last inn fleire videoar'\n  Error Channels: Kanalar med feil\n  Disabled Automatic Fetching: Du har deaktivert automatisk henting av abonnement. Oppdater abonnement for å sjå dei her.\n  Empty Channels: Kanalane du abonnerer på har ingen videoar for augeblikket.\nTrending:\n  Trending: 'På veg opp'\n  Trending Tabs: På veg opp\n  Gaming: Dataspel\n  Sports: Sport\nMost Popular: 'Mest populært'\nPlaylists: 'Spelelister'\nUser Playlists:\n  Your Playlists: 'Dine spelelister'\n  Search bar placeholder: Søk i speleliste\n  Empty Search Message: Det er ingen videoar i denne spelelista som samsvarar med søket ditt\nHistory:\n  # On History Page\n  History: 'Historikk'\n  Watch History: 'Visingshistorikk'\n  Your history list is currently empty.: 'Historikken din er tom for augeblikket.'\n  Empty Search Message: Det er ingen videoar i historikken din som samsvarer med søket ditt\n  Search bar placeholder: Søk i historikk\nSettings:\n  # On Settings Page\n  Settings: 'Innstillingar'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Programmet må starte på nytt for at endringane skal tre i kraft. Start på nytt og ta i bruk endringane?'\n  General Settings:\n    General Settings: 'Generelle innstillingar'\n    Check for Updates: 'Sjå etter oppdateringar'\n    Check for Latest Blog Posts: 'Sjå etter nye blogginnlegg'\n    Fallback to Non-Preferred Backend on Failure: 'Tilbakefall til ikkje-føretrekte backend ved feil'\n    Enable Search Suggestions: 'Slå på søkeforslag'\n    Default Landing Page: 'Standardlandingside'\n    Locale Preference: 'Språkinnstilling'\n    Preferred API Backend:\n      Preferred API Backend: 'Føretrekte API-backend'\n      Local API: 'Lokalt API'\n      Invidious API: 'Invidious-API'\n    Video View Type:\n      Video View Type: 'Videovisingstype'\n      Grid: 'Rutenett'\n      List: 'Liste'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatyrbiletepreferanse'\n      Default: 'Standard'\n      Beginning: 'Begynning'\n      Middle: 'Mellom'\n      End: 'Slutt'\n    View all Invidious instance information: 'Vis informasjon om alle Invidious-førekomstar'\n    Region for Trending: 'Region for \"På veg opp\"'\n        #! List countries\n    System Default: Systemstandard\n    External Link Handling:\n      External Link Handling: Handtering av eksterne lenker\n      Open Link: Opne lenke\n      Ask Before Opening Link: Spør før opning av lenke\n      No Action: Ingen handling\n    Current instance will be randomized on startup: Gjeldande førekomst vil bli satt tilfeldig ved oppstart\n    Current Invidious Instance: Gjeldande Invidious-førekomstar\n    Set Current Instance as Default: Sett gjeldande førekomst som standardførekomst\n    Clear Default Instance: Tilbakestill standardførekomst\n    No default instance has been set: Ingen standardførekomst har blitt satt\n    The currently set default instance is {instance}: Gjeldande standardførekomst er {instance}\n  Theme Settings:\n    Theme Settings: 'Temainnstillingar'\n    Match Top Bar with Main Color: 'Tilpass topplinja slik at den har same farge som hovudfargen'\n    Expand Side Bar by Default: 'Utvid sidefeltet som standard'\n    Disable Smooth Scrolling: 'Slå av jamn rulling'\n    UI Scale: 'Skalering av brukargrensesnitt'\n    Base Theme:\n      Base Theme: 'Hovudtema'\n      Black: 'Svart'\n      Dark: 'Mørk'\n      Light: 'Lys'\n      Dracula: 'Dracula'\n      System Default: Systemstandard\n      Catppuccin Mocha: 'Catppuccin-mokka'\n    Main Color Theme:\n      Main Color Theme: 'Hovudfargetema'\n      Red: 'Raud'\n      Pink: 'Rosa'\n      Purple: 'Lilla'\n      Deep Purple: 'Djuplilla'\n      Indigo: 'Indigo'\n      Blue: 'Blå'\n      Light Blue: 'Lyseblå'\n      Cyan: 'Turkis'\n      Teal: 'Blågrøn'\n      Green: 'Grøn'\n      Light Green: 'Lysegrøn'\n      Lime: 'Lime'\n      Yellow: 'Gul'\n      Amber: 'Rav'\n      Orange: 'Oransje'\n      Deep Orange: 'Djuporansje'\n      Dracula Cyan: 'Dracula Turkis'\n      Dracula Green: 'Dracula Grøn'\n      Dracula Orange: 'Dracula Oransje'\n      Dracula Pink: 'Dracula Rosa'\n      Dracula Purple: 'Dracula Lilla'\n      Dracula Red: 'Dracula Raud'\n      Dracula Yellow: 'Dracula Gul'\n      Catppuccin Mocha Mauve: Catppuccin-mokkalilla\n      Catppuccin Mocha Red: Catppuccin-mokkarød\n      Catppuccin Mocha Maroon: Catppuccin-mokkakastanjebrun\n      Catppuccin Mocha Peach: Catppuccin-mokkafersken\n      Catppuccin Mocha Green: Catppuccin-mokkagrøn\n      Catppuccin Mocha Teal: Catppuccin-mokkablågrøn\n      Catppuccin Mocha Sky: Catppuccin-mokkahimmelblå\n      Catppuccin Mocha Flamingo: Catppuccin-mokka-flamingo\n      Catppuccin Mocha Rosewater: Catppuccin-mokkarosevann\n      Catppuccin Mocha Pink: Catppuccin-mokkarosa\n      Catppuccin Mocha Yellow: Catppuccin-mokkagul\n      Catppuccin Mocha Sapphire: Catppuccin-mokkasafir\n      Catppuccin Mocha Blue: Catppuccin-mokkablå\n      Catppuccin Mocha Lavender: Catppuccin-mokkalavendel\n    Secondary Color Theme: 'Sekundærfargetema'\n        #* Main Color Theme\n    Hide Side Bar Labels: Skjul sidefeltetikettar\n    Hide FreeTube Header Logo: Skjul FreeTube-tittellogo\n  Player Settings:\n    Player Settings: 'Videoavspelingsinnstillingar'\n    Play Next Video: 'Spel av neste video'\n    Turn on Subtitles by Default: 'Slå på undertekst som standard'\n    Autoplay Videos: 'Spel av videoar automatisk'\n    Proxy Videos Through Invidious: 'Mellomten videoar gjennom Invidious'\n    Autoplay Playlists: 'Spel av spelelister automatisk'\n    Enable Theatre Mode by Default: 'Kinomodus som standard'\n    Default Volume: 'Standardvolum'\n    Default Playback Rate: 'Avspelingshastigheit'\n    Default Video Format:\n      Default Video Format: 'Videoformat'\n      Dash Formats: 'DASH-format'\n      Legacy Formats: 'Utdaterte format'\n      Audio Formats: 'Lydformat'\n    Default Quality:\n      Default Quality: 'Kvalitetsinnstilling'\n      Auto: 'Automatisk'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Tid mellom videoar\n    Display Play Button In Video Player: Vis videoavspelingsknappen i videoavspelaren\n    Scroll Volume Over Video Player: Juster volum ved å bla på video\n    Screenshot:\n      Ask Path: Spør om kvar ting skal lagrast\n      Error:\n        Forbidden Characters: Forbodne teikn\n        Empty File Name: Tomt filnamn\n      Format Label: Skjermbileteformat\n      Enable: Aktiver skjermbilete\n      Folder Label: Skjermbiletemappe\n      Folder Button: Vel mappe\n      Quality Label: Skjermbiletekvalitet\n      File Name Label: Filnamnmøster\n      File Name Tooltip: Du kan bruke variablane nedanfor. %Y for år, med fire siffer. %M for månad, med to siffer. %D for dag, med to siffer. %H for time, med to siffer. %N for minutt, med to siffer. %S for sekund, med to siffer. %T for millisekund, med tre siffer. %s for videosekund. %t for videomillisekund, med tre siffer. %i for Video-ID.\n    Fast-Forward / Rewind Interval: Intervall for framover- og bakoverspoling\n    Skip by Scrolling Over Video Player: Hopp over ved å blad over videoavspelaren\n    Scroll Playback Rate Over Video Player: Blaavspelingshastigheit over videoavspelar\n    Video Playback Rate Interval: Intervall for videoavspelinghastigheit\n    Enter Fullscreen on Display Rotate: Bytt til fullskjerm ved skjermrotasjon\n    Max Video Playback Rate: Maksimal videoavspelinghastigheit\n  Privacy Settings:\n    Privacy Settings: 'Personverninnstillingar'\n    Remember History: 'Husk historikk'\n    Save Watched Progress: 'Lagre framgangsdrift'\n    Clear Search Cache: 'Slett søkehurtiglager'\n    Are you sure you want to clear out your search cache?: 'Er du sikker på at du vil slette søkehurtiglageret?'\n    Search cache has been cleared: 'Søkehurtiglageret har blitt tømt'\n    Remove Watch History: 'Slett visingshistorikk'\n    Are you sure you want to remove your entire watch history?: 'Er du sikker på at du vil fjerne heile visingshistorikken din?'\n    Watch history has been cleared: 'Visingshistorikk har blitt fjerna'\n    Remove All Subscriptions / Profiles: 'Fjern alle abonnentar/profil'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Er du sikker på at du vil fjerne alle abonnentar og profil? Dette kan ikkje bli ugjort.'\n  Subscription Settings:\n    Subscription Settings: 'Abonnementinnstillingar'\n    Fetch Feeds from RSS: 'Hent informasjonkanalar frå RSS'\n    Fetch Automatically: Hent informasjonkanalar automatisk\n  Distraction Free Settings:\n    Distraction Free Settings: '\"Ikkje forstyrr\"-innstillingar'\n    Hide Video Views: 'Skjul videovisingar'\n    Hide Video Likes And Dislikes: 'Skjul videogunst'\n    Hide Channel Subscribers: 'Skjul kanalabonnement'\n    Hide Comment Likes: 'Skjul kommentargunst'\n    Hide Recommended Videos: 'Skjul anbefalte videoar'\n    Hide Trending Videos: 'Skjul \"På veg opp\"'\n    Hide Popular Videos: 'Skjul \"Mest populært\"'\n    Hide Live Chat: 'Skjul direktechat'\n    Hide Active Subscriptions: 'Skjul aktive abonnement'\n    Hide Playlists: Skjul spelelister\n    Hide Upcoming Premieres: Skjul komande premierar\n    Hide Sharing Actions: Skjul delehandlingar\n    Hide Videos on Watch: 'Skjul sette videoar'\n    Hide Comments: Skjul kommentarar\n    Hide Live Streams: Skjul direktesendingar\n    Hide Video Description: Skjul videobeskriving\n    Hide Chapters: Skjul kapittel\n    Display Titles Without Excessive Capitalisation: Vis titlar utan overdriven bruk av store bokstavar\n    Hide Channels: Skjul videoar frå kanalar\n    Hide Channels Placeholder: Kanalnamn eller kanal-ID\n  Data Settings:\n    Data Settings: 'Datainnstillingar'\n    Select Export Type: 'Vel eksporttype'\n    Import Subscriptions: 'Importer abonnement'\n    Export Subscriptions: 'Eksporter abonnement'\n    Export FreeTube: 'Eksporter FreeTube'\n    Export YouTube: 'Eksporter YouTube'\n    Export NewPipe: 'Eksporter NewPipe'\n    Import History: 'Importer historikk'\n    Export History: 'Eksporter historikk'\n    Profile object has insufficient data, skipping item: 'Eit profilobjekt manglar data, hoppar over objektet'\n    All subscriptions and profiles have been successfully imported: 'Alle abonnement og profila har blitt importert'\n    All subscriptions have been successfully imported: 'Alle abonnement har blitt importert'\n    Invalid subscriptions file: 'Ugyldig abonnementfil'\n    Invalid history file: 'Ugyldig historikkfil'\n    Subscriptions have been successfully exported: 'Abonnement har blitt importert'\n    History object has insufficient data, skipping item: 'Eit historikkobjekt manglar data, hoppar over objektet'\n    All watched history has been successfully imported: 'Visingshistorikken har blitt importert'\n    All watched history has been successfully exported: 'Visingshistorikken har blitt eksportert'\n    Unable to read file: 'Kan ikkje lese fil'\n    Unable to write file: 'Kan ikkje skrive til fil'\n    Unknown data key: 'Ukjent datanøkkel'\n    How do I import my subscriptions?: 'Korleis importerer eg abonnementa mine?'\n    Manage Subscriptions: 'Behandle abonnement'\n    Import Playlists: Importer spelelister\n    Subscription File: Abonnementfil\n    History File: Historikkfil\n    Playlist insufficient data: Utilstrekkeleg data for \"{playlist}\" speleliste, hopper over element\n    All playlists has been successfully exported: Alle spelelister har blitt vellykka eksportert\n    Export Playlists: Eksporter spelelister\n    All playlists has been successfully imported: Alle spelelister har blitt vellykka importert\n    Playlist File: Spelelistefil\n  Proxy Settings:\n    Proxy Settings: 'Mellomtenarinnstillingar'\n    Enable Tor / Proxy: 'Skru på Tor/mellomtenar'\n    Proxy Protocol: 'Mellomtenarprotokoll'\n    Proxy Host: 'Mellomtenarvert'\n    Proxy Port Number: 'Mellomtenarportnummer'\n    Clicking on Test Proxy will send a request to: 'Viss du klikker på \"Test mellomtenar\" sender me ein førespurnad til'\n    Test Proxy: 'Test mellomtenar'\n    Your Info: 'Din informasjon'\n    Ip: 'IP-adresse'\n    Country: 'Land'\n    Region: 'Region'\n    City: 'By'\n    Error getting network information. Is your proxy configured properly?: 'Kunne ikkje hente nettverksinformasjon. Er mellomtenaren din konfigurert skikkeleg?'\n  SponsorBlock Settings:\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock-API-nettadresse (standard er https://sponsor.ajay.app)\n    Enable SponsorBlock: Skru på SponsorBlock\n    SponsorBlock Settings: SponsorBlock-innstillingar\n    Notify when sponsor segment is skipped: Gi beskjed når sponsordelen blir hoppa over\n    Skip Options:\n      Skip Option: Alternativ for å hoppe over\n      Auto Skip: Hopp over automatisk\n      Show In Seek Bar: Vis i søkefelt\n      Prompt To Skip: Spør om å hoppe over\n      Do Nothing: Ikkje gjer noko\n    Category Color: Kategorifarge\n  External Player Settings:\n    External Player Settings: Innstillingar for ekstern avspelar\n    Custom External Player Executable: Eigendefinert køyrbar fil for ekstern avspelar\n    Custom External Player Arguments: Eigendefinerte argument for ekstern avspelar\n    External Player: Ekstern avspelar\n    Ignore Unsupported Action Warnings: Ignorer handlingvarslar som ikkje støttast\n    Players:\n      None:\n        Name: Ingen\n  Experimental Settings:\n    Replace HTTP Cache: Erstatt HTTP-hurtiglager\n    Experimental Settings: Eksperimentelle innstillingar\n    Warning: Desse innstillingane er eksperimentelle, og dei kan forårsake krasjar mens dei er aktivert. Det anbefalast å ta tryggleikskopiar. Bruk på eiget ansvar.\n  Parental Control Settings:\n    Hide Search Bar: Skjul søkefelt\n    Hide Unsubscribe Button: Skjul knapp for oppheving av abonnement\n    Parental Control Settings: Foreldrekontrollinnstillingar\n    Show Family Friendly Only: Vis kun familevenleg\n  Password Dialog:\n    Enter Password To Unlock: Skriv inn passord for å låse opp innstillingar\n    Password: Passord\n  Password Settings:\n    Set Password To Prevent Access: Angi eit passord for å forhindre tilgang til innstillingane\n    Password Settings: Passordinnstillingar\n    Set Password: Angi passord\n    Remove Password: Fjern passord\nAbout:\n  #On About page\n  About: 'Om'\n  Beta: 'Beta'\n  Source code: 'Kjeldekode'\n  Downloads / Changelog: 'Nedlastingar / Endringslogg'\n  GitHub releases: 'GitHub-utgjevingar'\n  Help: 'Hjelp'\n  FreeTube Wiki: 'FreeTube-wiki'\n  FAQ: 'Ofte stilte spørsmål'\n  Report a problem: 'Rapporter eit problem'\n  GitHub issues: 'GitHub-problemsporar'\n  Please check for duplicates before posting: 'Ver venleg og sjå etter duplikat før du poster noko'\n  Website: 'Nettstad'\n  Blog: 'Blogg'\n  Email: 'E-post'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Snakk med oss på Matrix'\n  room rules: 'Romreglar'\n  Translate: 'Omsetje'\n  Credits: 'Bidrag'\n  these people and projects: 'desse folka og prosjekta'\n  Donate: 'Doner'\n\nProfile:\n  Profile Select: 'Profilval'\n  All Channels: 'Alle kanalar'\n  Profile Manager: 'Profilbehandlar'\n  Create New Profile: 'Lag ny profil'\n  Edit Profile: 'Rediger profil'\n  Color Picker: 'Fargeveljar'\n  Custom Color: 'Eigendefinert farge'\n  Profile Preview: 'Forhandsvising av profil'\n  Create Profile: 'Lag profil'\n  Update Profile: 'Oppdater profil'\n  Make Default Profile: 'Angi som standardprofil'\n  Delete Profile: 'Fjern profil'\n  Are you sure you want to delete this profile?: 'Er du sikker på at du vil fjerne denne profilet?'\n  All subscriptions will also be deleted.: 'Alle abonnement vil òg bli sletta.'\n  Your profile name cannot be empty: 'Profilnamnet ditt kan ikkje vere tomt'\n  Profile has been created: 'Profilet har blitt laga'\n  Profile has been updated: 'Profilet har blitt oppdatert'\n  Your default profile has been set to {profile}: 'Ditt standardprofil har blitt satt til {profile}'\n  Removed {profile} from your profiles: 'Fjerna {profile} frå profila dine'\n  Your default profile has been changed to your primary profile: 'Ditt standardprofil har blitt endra til ditt hovudprofil'\n  '{profile} is now the active profile': '{profile} er no det aktive profilet'\n  Subscription List: 'Abonnementliste'\n  Other Channels: 'Andre kanalar'\n  '{number} selected': '{number} valt'\n  Select All: 'Vel alle'\n  Select None: 'Vel ingen'\n  Delete Selected: 'Slett valte'\n  Add Selected To Profile: 'Legg til valt i profilen'\n  No channel(s) have been selected: 'Ingen kanal(ar) har blitt valt'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Dette er primærprofilet ditt. Er du sikker på at du vil fjerne dei valte kanalane? Dei same kanalane vil bli sletta i profila dei er funne i.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Er du sikker på at du vil fjerne dei valte kanalane? Dette vil ikkje slette kanalane frå andre profil.'\n#On Channel Page\n  Profile Filter: Profilfilter\n  Profile Settings: Profilinnstillingar\nChannel:\n  Subscribe: 'Abonner'\n  Unsubscribe: 'Opphev abonnement'\n  Channel has been removed from your subscriptions: 'Kanalen har blitt fjerna frå dine abonnement'\n  Removed subscription from {count} other channel(s): 'Fjerna abonnement frå {count} kanal(ar)'\n  Added channel to your subscriptions: 'Lagt til kanal til dine abonnentar'\n  Search Channel: 'Søk i kanal'\n  Your search results have returned 0 results: 'Søket gitt gav 0 resultat'\n  Videos:\n    Videos: 'Videoar'\n    This channel does not currently have any videos: 'Kanalen har ingen videoar enda'\n    Sort Types:\n      Newest: 'Nyaste'\n      Oldest: 'Eldste'\n      Most Popular: 'Mest populære'\n  Playlists:\n    Playlists: 'Spelelister'\n    This channel does not currently have any playlists: 'Denne kanalen har ingen spelelister enda'\n    Sort Types:\n      Last Video Added: 'Siste video lagt til'\n      Newest: 'Nyaste'\n      Oldest: 'Eldste'\n  About:\n    About: 'Om'\n    Channel Description: 'Kanalbeskriving'\n    Featured Channels: 'Utvalte kanalar'\nVideo:\n  Mark As Watched: 'Marker som sett'\n  Remove From History: 'Fjern frå historikk'\n  Video has been marked as watched: 'Videoen har blitt markert som sett'\n  Video has been removed from your history: 'Videoen har blitt fjerna frå historikken din'\n  Save Video: 'Lagre video'\n  Video has been saved: 'Videoen har blitt lagra'\n  Video has been removed from your saved list: 'Videoen har blitt fjerna frå di liste over lagra videoar'\n  Open in YouTube: 'Opne i YouTube'\n  Copy YouTube Link: 'Kopier YouTube-lenke'\n  Open YouTube Embedded Player: 'Opne innebygd YouTube-spelar'\n  Copy YouTube Embedded Player Link: 'Kopier lenke til innebygd YouTube-spelar'\n  Open in Invidious: 'Opne i Invidious'\n  Copy Invidious Link: 'Kopier Invidious-lenke'\n  Open Channel in YouTube: 'Opne kanal i YouTube'\n  Copy YouTube Channel Link: 'Kopier YouTube-kanallenke'\n  Open Channel in Invidious: 'Opne kanal i Invidious'\n  Copy Invidious Channel Link: 'Kopier Invidious-kanallenke'\n  Views: 'Visingar'\n  Loop Playlist: 'Gjenta speleliste'\n  Shuffle Playlist: 'Spel av tilfeldig frå spelelista'\n  Reverse Playlist: 'Snu spelelista'\n  Previous: 'Forrige'\n  Next: 'Neste'\n  Watched: 'Sett'\n  Autoplay: 'Automatisk avspeling'\n  Starting soon, please refresh the page to check again: 'Starter snart. Ver venleg og oppdater sida for å sjekke igjen'\n  # As in a Live Video\n  Live: 'Direkte'\n  Live Now: 'Direkte no'\n  Live Chat: 'Direktechat'\n  Enable Live Chat: 'Slå på direktechat'\n  Live Chat is currently not supported in this build.: 'Direktechat er ikkje støtta i den noverande versjonen.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Direktechat er slått på. Chatmeldingar vil bli vist her når dei er sendt.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Direktechat er førebels ikkje støtta av Invidious-API-et. Ei direkte tilkopling til YouTube er krevja.'\n  Published:\n    In less than a minute: Om mindre enn eit minutt\n  Published on: 'Publisert på'\n  Streamed on: 'Strauma på'\n  Started streaming on: 'Begynte å straume på'\n#& Videos\n  Sponsor Block category:\n    outro: Avslutting\n    interaction: Samhandling\n    intro: Introduksjon\n    sponsor: Sponsor\n    music offtopic: Musikk utanfor tema\n    self-promotion: Eigenpromotering\n    recap: Oppsummering\n    filler: Fyllstoff\n  External Player:\n    video: video\n    playlist: speleliste\n    UnsupportedActionTemplate: '{externalPlayer} støtter ikkje: {action}'\n    OpeningTemplate: Opner {videoOrPlaylist} om {externalPlayer} ...\n    OpenInTemplate: Opne i {externalPlayer}\n    Unsupported Actions:\n      opening playlists: opner spelelister\n      setting a playback rate: set ein avspelingshastigheit\n      shuffling playlists: sorterer spelelister i tilfeldig rekkefølgje\n      looping playlists: gjentar spelelister\n      starting video at offset: starter video ved punktet\n      reversing playlists: speler av spelelister baklengs\n      opening specific video in a playlist (falling back to opening the video): opner valt video i ei speleliste (faller tilbake til å opne videoen)\n  Show Super Chat Comment: Vis super-chat-kommentar\n  Premieres: Premiere\n  Scroll to Bottom: Rull til botn\n  Upcoming: Komande\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Vis heile spelelista'\n  Last Updated On: 'Sist oppdatert'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Speleliste\nChange Format:\n  Change Media Formats: 'Endre videoformat'\n  Use Dash Formats: 'Bruk DASH-format'\n  Use Legacy Formats: 'Bruk utdaterte format'\n  Use Audio Formats: 'Bruk lydformat'\n  Dash formats are not available for this video: 'DASH-format er ikkje tilgjengeleg for denne videoen'\n  Audio formats are not available for this video: 'Lydformat er ikkje tilgjengeleg for denne videoen'\nShare:\n  Share Video: 'Del video'\n  Share Playlist: 'Del speleliste'\n  Include Timestamp: 'Inkluder tidsstempel'\n  Copy Link: 'Kopier lenke'\n  Open Link: 'Opne lenke'\n  Copy Embed: 'Kopier innebyggingslenke'\n  Open Embed: 'Opne innebygde versjon'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-URL kopiert til utklippstavle'\n  Invidious Embed URL copied to clipboard: 'Innebygd Invidious-nettadresse kopiert til utklippstavle'\n  Invidious Channel URL copied to clipboard: 'Invidious-kanalnettadresse kopiert til utklippstavle'\n  YouTube URL copied to clipboard: 'YouTube-nettadresse kopiert til utklippstavle'\n  YouTube Embed URL copied to clipboard: 'Innebygd YouTube-nettadresse kopiert til utklippstavle'\n  YouTube Channel URL copied to clipboard: 'YouTube-kanalnettadresse kopiert til utklippstavle'\n\n  Share Channel: Del kanal\nMini Player: 'Miniavspelar'\nComments:\n  Comments: 'Kommentarar'\n  Click to View Comments: 'Klikk her for å vise kommentarar'\n  Getting comment replies, please wait: 'Laster inn kommentarar. Ver venleg og vent'\n  There are no more comments for this video: 'Det finst ingen fleire kommentarar for denne videoen'\n  Hide Comments: 'Skjul kommentarar'\n  Top comments: 'Toppkommentarar'\n  Newest first: 'Nyaste først'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Det er ingen kommentarar tilgjengeleg for denne videoen'\n  Load More Comments: 'Last inn fleire kommentarar'\n  Show More Replies: Vis fleire svar\n  Pinned by: Festa av\n  Member: Medlem\n  Hearted: Likt\n  View {replyCount} replies: Vis {replyCount} svar\nUp Next: 'Neste'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Vel metoden FreeTube bruker for å hente data. Det lokale API-et er ein innebygd utpakkar. Invidious-API-et krev ein Invidious-tenar å kople til.'\n    Fallback to Non-Preferred Backend on Failure: 'Når ditt føretrekte API har eit problem, vil FreeTube prøve å automatisk bruke ditt ikkje-føretrekte API som ein tilbakefallingsmetode dersom det er aktivert.'\n    Thumbnail Preference: 'Alle miniatyrbilete i FreeTube vil bli erstatta av eit bilete av videoen i staden for standardminiatyrbiletet'\n    Invidious Instance: 'Invidious-førekomsten som FreeTube vil kople til for API-kall.'\n    Region for Trending: 'Trendsregionen lar deg enkelt velje kva lands populære videoar du ynskjer å vise.'\n    External Link Handling: \"Vel kva FreeTube skal gjer, når ein trykker på ei lenke, som ikkje kan bli opna av FreeTube. \\nFreeTube vil vanlegvis opne lenka i din standardnettlesar.\\n\"\n  Player Settings:\n    Proxy Videos Through Invidious: 'Koplar til Invidious for å servere videoar i staden for å kople direkte til YouTube.'\n    Default Video Format: 'Sett format som blir brukt når ein video spelast. DASH-format kan spele høgare kvalitet. Utdaterte format er avgrensa til maks 720p, men bruker mindre bandbreidde. Lydformat er berre for lydstraumar.'\n    Skip by Scrolling Over Video Player: Bla for å hoppe deg gjennom videoen i MPV-stil.\n    Scroll Playback Rate Over Video Player: Mens musepeikaren er over videoen, trykk og hald inne CTRL-tasten (kommandotasen på Mac) og bla opp og ned for å kontrollere avspelingshastigheita. Trykk og hald inne CTRL-tasten (kommandotasten på Mac) og venstretrykk rakst for å gå tilbake til standard avspelingshastigheita. Standard avspelingshastigheit er 1x med mindre den har blitt endra i innstillingane.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Bruk RSS i staden for FreeTube sin standardmetode for innhenting av din abonnementsstraum. RSS er raskaren og forhindrar IP-blokkering, men manglar noko informasjon som videovarigheit og sanntidsstatus.'\n\n# Toast Messages\n    Fetch Automatically: Om dette alternativet er aktivert, vil FreeTube automatisk hente abonnementfeeden din når eit nytt vindauge opnast og når du bytter profil.\n  External Player Settings:\n    DefaultCustomArgumentsTemplate: \"(Standard: '{defaultCustomArguments}')\"\n    Custom External Player Executable: Som standard vil FreeTube anta at den valte eksterne videoavspelaren kan bli funnen via programstivariabelen. Om naudsynt kan ein endre på programstien.\n    Ignore Warnings: Skjul åtvaringar angåande eksterne videoavspelarar som ikkje støtter gjeldande handlingar (f.eks. snu spelelister, osv.).\n    External Player: Viss ein har valt ein ekstern videoavspelar, blir eit ikon vist på miniatyrbiletet til videoar. Dette ikonet lar ein opne desse videoane i ein ekstern videoavspelar. Ver merksam på at Invidious-innstillingar ikkje påverker den eksterne videoavspelaren.\n    Custom External Player Arguments: Eventuelle eigendefinerte kommandolinjeargument, du vil at skal bli sendt til den eksterne videoavspelaren.\n  Experimental Settings:\n    Replace HTTP Cache: Deaktiver Electrons diskbaserte HTTP-hurtiglager og aktiver eit eigendefinert biletehurtiglager i minnet. Dette vil føre til ei auking i minnebruk.\n  Distraction Free Settings:\n    Hide Channels: Skriv inn eit kanalnamn eller ein kanal-ID for å skjule alle videoar, spelelister og sjølve kanalen frå å dukke opp i \"Søk\" eller \"På veg opp\". Kanalnamnet som blir skriven inn må samsvare fullstendig og skilje mellom store og små bokstavar.\nLocal API Error (Click to copy): 'Lokal API-feil (Klikk her for å kopiere)'\nInvidious API Error (Click to copy): 'Invidious-API-feil (Klikk her for å kopiere)'\nFalling back to Invidious API: 'Faller tilbake til Invidious-API-et'\nFalling back to Local API: 'Faller tilbake til det lokale API-et'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Denne videoen er utilgjengeleg grunna manglande format. Dette kan skuldast tilgangsavgrensingar i ditt land.'\nLoop is now disabled: 'Gjenta er no deaktivert'\nLoop is now enabled: 'Gjenta er no aktivert'\nShuffle is now disabled: 'Tilfeldig avspeling er no deaktivert'\nShuffle is now enabled: 'Tilfeldig avspeling er no aktivert'\nThe playlist has been reversed: 'Spelelista har blitt snudd'\nPlaying Next Video: 'Speler av neste video'\nPlaying Previous Video: 'Speler av førre video'\nCanceled next video autoplay: 'Avbryt automatisk avspeling av neste video'\n'The playlist has ended. Enable loop to continue playing': 'Spelelista har nådd si ende. Klikk på \"Gjenta\" for å fortsette avspelinga'\n\nYes: 'Ja'\nNo: 'Nei'\nUnknown YouTube url type, cannot be opened in app: Ukjent type YouTube-nettadresse, kan ikkje opnast i programmet\nPlaying Next Video Interval: Speler av neste video no. Klikk her for å avbryte. | Speler av neste video om {nextVideoInterval} sekund. Klikk her for å avbryte. | Speler av neste video om {nextVideoInterval} sekund. Klikk her for å avbryte.\nMore: Meir\nOpen New Window: Opne nytt vindauge\nSearch Bar:\n  Clear Input: Tøm inndata\nAre you sure you want to open this link?: Er du sikker på at du vil opne denne lenka?\nNew Window: Nytt vindauge\nPreferences: Innstillingar\nChannels:\n  Channels: Kanalar\n  Title: Kanalliste\n  Search bar placeholder: Søk etter kanalar\n  Count: Fant {number} kanal(ar).\n  Empty: Kanallista di er tom.\n  Unsubscribe Prompt: Er du sikker på at du vil avslutte abonnementet på \"{channelName}\"?\nScreenshot Success: Lagra skjermbilete som \"{filePath}\"\nScreenshot Error: Skjermbilete feila. {error}\nOk: OK\nClipboard:\n  Cannot access clipboard without a secure connection: Får ikkje tilgang til utklipptavla utan ei sikker forbinding\n  Copy failed: Kopiering til utklipptavle feila\nChapters:\n  Chapters: Kapittel\nDefault Invidious instance has been cleared: Standard-Invidious-førekomst har blitt tilbakestilt\nDefault Invidious instance has been set to {instance}: Standard-Invidious-førekomst har blitt satt til {instance}\nExternal link opening has been disabled in the general settings: Opening av eksterne lenker har blitt deaktivert i innstillingane\nGo to page: Gå til {page}\nSearch Listing:\n  Label:\n    8K: 8K\n    New: Ny\n    3D: 3D\n    4K: 4K\n    Subtitles: Undertekstar\n    Closed Captions: Undertekstar\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Veksle utviklarverktøy\n  Zoom Out: Forminsk\n  Zoom In: Forstørr\n  Fullscreen: Veksle fullskjerm\n"
  },
  {
    "path": "static/locales/or.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ଓଡ଼ିଆ'\nFile: 'ଫାଇଲ୍'\nEdit: 'ସମ୍ପାଦନା'\nUndo: 'ପୂର୍ଵଵତ୍'\nRedo: 'ପୁନଃକରଣ'\n\nGlobal:\n  Sort By: 'ଏହା ଅନୁଯାୟୀ ସଜାଅ'\n\n  Videos: ଭିଡିଓ\n  Live: ଲାଇଭ୍\nSearch Filters:\n  Sort By:\n    Most Relevant: 'ସବୁଠୁ ପ୍ରାସଙ୍ଗିକ'\n    View Count: 'ଦର୍ଶନ ଗଣନା'\n  Time:\n    Time: 'ସମୟ'\n    Any Time: 'ଯେକୌଣସି ସମୟରେ'\n    Last Hour: 'ଗତ ଘଣ୍ଟା'\n    Today: 'ଆଜି'\n    This Week: 'ଚଳିତ ସପ୍ତାହରେ'\n    This Month: 'ଚଳିତ ମାସରେ'\n    This Year: 'ଚଳିତ ଵର୍ଷରେ'\n  Type:\n    Type: 'ପ୍ରକାର'\n    All Types: 'ସମସ୍ତ ପ୍ରକାର'\n    Videos: 'ଭିଡିଓ'\n    Channels: 'ଚ୍ୟାନେଲ'\n    #& Playlists\n    Movies: ଚଳଚ୍ଚିତ୍ର\n  Duration:\n    Duration: 'ଅଵଧି'\n    All Durations: 'ସମସ୍ତ ଅଵଧି'\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'ସଦସ୍ୟତା'\n  # channels that were likely deleted\nMore: 'ଅଧିକ'\nChannels:\n  Channels: 'ଚ୍ୟାନେଲ'\n  Title: 'ଚ୍ୟାନେଲ ତାଲିକା'\nTrending:\n  Gaming: 'ଖେଳ'\nPlaylists: 'ଚାଳନାତାଲିକା'\nUser Playlists:\n  Your Playlists: 'ଆପଣଙ୍କ ଚାଳନାତାଲିକା'\nSettings:\n  # On Settings Page\n  General Settings:\n    Thumbnail Preference:\n      Default: 'ଡିଫଲ୍ଟ'\n    External Link Handling:\n      No Action: 'କିଛି କରନ୍ତୁନି'\n  Theme Settings:\n    Theme Settings: 'ଥିମ୍ ସେଟିଂ'\n    Base Theme:\n      Base Theme: 'ଆଧାର ଥିମ୍'\n      Black: 'କଳା'\n      Dark: 'ଗାଢ଼'\n      Light: 'ହାଲୁକା'\n    Main Color Theme:\n      Red: 'ନାଲି'\n      Pink: 'ଗୋଲାପୀ'\n      Purple: 'ବାଇଗଣୀ'\n      Deep Purple: 'ଗାଢ଼ ବାଇଗଣୀ'\n      Blue: 'ନୀଳ'\n      Light Blue: 'ହାଲୁକା ନୀଳ'\n      Green: 'ସବୁଜ'\n      Light Green: 'ହାଲୁକା ସବୁଜ'\n      Lime: 'ଚୂନ'\n      Yellow: 'ହଳଦିଆ'\n      Orange: 'କମଳା'\n      Deep Orange: 'ଗାଢ଼ କମଳା'\n  Player Settings:\n    Player Settings: 'ଚାଳକ ସେଟିଂ'\n    Autoplay Videos: 'ଵିଡ଼ିଓ ସ୍ୱତଃଚାଳନ'\n    Autoplay Playlists: 'ଚାଳନାତାଲିକା ସ୍ୱତଃଚାଳନ'\n    Default Video Format:\n      Audio Formats: 'ଅଡ଼ିଓ ଫର୍ମାଟ୍'\n    Default Quality:\n      Default Quality: 'ଡିଫଲ୍ଟ ଗୁଣବତ୍ତା'\n      Auto: 'ସ୍ୱତଃ'\n      144p: '୧୪୪p'\n      240p: '୨୪୦p'\n      360p: '୩୬୦p'\n      480p: '୪୮୦p'\n      720p: '୭୨୦p'\n      1080p: '୧୦୮୦p'\n      1440p: '୧୪୪୦p'\n      4k: '୪k'\n      8k: '୮k'\n  External Player Settings:\n    External Player Settings: 'ବାହ୍ୟ ଚାଳକ ସେଟିଂ'\n    External Player: 'ବାହ୍ୟ ଚାଳକ'\n    Players: {}\n  Privacy Settings:\n    Privacy Settings: 'ଗୋପନୀୟତା ସେଟିଂ'\n    Remember History: 'ଇତିଵୃତ୍ତି ମନେରଖିବା'\n  Subscription Settings:\n    Manage Subscriptions: 'ସଦସ୍ୟତା ପରିଚାଳନା'\n  Distraction Free Settings:\n    Hide Comments: 'ମନ୍ତଵ୍ୟ ଲୁଚାଇବା'\n    Display Titles Without Excessive Capitalisation: ଅତ୍ୟଧିକ ବଡ଼ ଅକ୍ଷର ବିନା ଆଖ୍ୟା ପ୍ରଦର୍ଶନ\n      କରିବା\n  SponsorBlock Settings: {}\nChannel:\n  Videos:\n    Videos: ଭିଡିଓ\n  Playlists: {}\nVideo:\n  External Player: {}\nTooltips: {}\nSearch Listing:\n  Label:\n    4K: 4K\n    8K: 8K\n"
  },
  {
    "path": "static/locales/pl.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Plik'\nQuit: 'Wyjdź'\nEdit: 'Edytuj'\nUndo: 'Cofnij'\nRedo: 'Ponów'\nCut: 'Wytnij'\nCopy: 'Kopiuj'\nPaste: 'Wklej'\nDelete: 'Usuń'\nSelect all: 'Zaznacz wszystko'\nToggle Developer Tools: 'Włącz/wyłącz narzędzia deweloperskie'\nActual size: 'Rzeczywisty rozmiar'\nZoom in: 'Powiększ'\nZoom out: 'Zmniejsz'\nToggle fullscreen: 'Przełącz na cały ekran'\nWindow: 'Okno'\nMinimize: 'Zminimalizuj'\nClose: 'Zamknij'\nBack: 'Wstecz'\nForward: 'Naprzód'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Filmy'\n  Shorts: Filmy Short\n  Live: Na żywo\n  Posts: Wpisy\n  Sort By: Sortuj według\n\n# Search Bar\n  Counts:\n    Video Count: 1 film | {count} film(y/ów)\n    Channel Count: 1 kanał | {count} kanał(y/ów)\n    Subscriber Count: 1 subskrybujący | {count} subskrybentów\n    View Count: 1 wyświetlenie | {count} wyświetle(nia/ń)\n    Watching Count: 1 oglądający | {count} oglądających\n    Like Count: Jedno polubienie | {count} polubie(ń/nia)\n    Comment Count: Jeden komentarz | {count} komentarz(e/y)\nSearch / Go to URL: 'Szukaj / Przejdź do adresu URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtry wyszukiwania'\n  Sort By:\n    Most Relevant: 'Trafność'\n    Rating: 'Ocena'\n    Upload Date: 'Data przesłania'\n    View Count: 'Liczba wyświetleń'\n  Time:\n    Time: 'Czas przesłania'\n    Any Time: 'Kiedykolwiek'\n    Last Hour: 'Ostatnia godzina'\n    Today: 'Dzisiaj'\n    This Week: 'W tym tygodniu'\n    This Month: 'W tym miesiącu'\n    This Year: 'W tym roku'\n  Type:\n    Type: 'Typ'\n    All Types: 'Wszystkie typy'\n    Videos: 'Filmy'\n    Channels: 'Kanały'\n    #& Playlists\n    Movies: Filmy kinowe\n  Duration:\n    Duration: 'Długość'\n    All Durations: 'Każda'\n    Short (< 4 minutes): 'Krótkie (< 4 minuty)'\n    Long (> 20 minutes): 'Długie (> 20 minut)'\n  # On Search Page\n    Medium (4 - 20 minutes): Średnie (4 - 20 minut)\n  Search Results: 'Wyniki wyszukiwania'\n  Fetching results. Please wait: 'Trwa wyszukiwanie. Proszę poczekać'\n  Fetch more results: 'Pokaż więcej wyników'\n# Sidebar\n  There are no more results for this search: Nie ma więcej wyników dla tego wyszukiwania\n  Features:\n    Features: Cechy\n    Subtitles: Napisy\n    4K: 4K\n    HD: HD\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Transmisja\n    360 Video: Film 360°\n    HDR: HDR\n    VR180: VR180\n    Location: Miejsce\n  Clear Filters: Odznacz filtry\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subskrypcje'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Twoja lista subskrypcji jest obecnie pusta. Możesz zaimportować swoje subskrypcje w Ustawieniach danych, klikając w „Zaimportuj subskrypcje”.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Ten profil posiada dużą liczbę subskrypcji. Wymuszenie RSS w celu uniknięcia ograniczenia dostępu\n  Load More Videos: Załaduj więcej filmów\n  Error Channels: Kanały z błędami\n  Disabled Automatic Fetching: Wyłączyłeś automatyczne pobieranie subskrypcji. Odśwież subskrypcje, by je zobaczyć.\n  Empty Channels: Twoje subskrypcje nie mają obecnie żadnych filmów.\n  All Subscription Tabs Hidden: Wszystkie karty subskrypcji są pochowane. Aby je zobaczyć, proszę odznaczyć ich ukrycie w podgrupie „{subsection}” grupy „{settingsSection}”.\n  Subscriptions Tabs: Karty subskrypcji\n  Load More Posts: Załaduj więcej wpisów\n  Empty Posts: Zasubskrybowane przez Ciebie kanały nie mają żadnych wpisów.\nTrending:\n  Trending: 'Na czasie'\n  Trending Tabs: Karty „Na czasie”\n  Gaming: Gry\n  Sports: Sport\nMost Popular: 'Popularne'\nPlaylists: 'Playlisty'\nUser Playlists:\n  Your Playlists: 'Twoje playlisty'\n  Search bar placeholder: Szukaj playlist\n  Empty Search Message: Na tej playliście nie ma filmów, które pasowałyby do Twojego zapytania\n  AddVideoPrompt:\n    Search in Playlists: Szukaj w playlistach\n    Save: Zapisz\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Film(y) dodan(y/e) do playlisty | Film(y) dodan(y/e) do {playlistCount} playlist\"\n      You haven't selected any playlist yet.: Nie wybrano jeszcze żadnych playlist.\n    Select a playlist to add your N videos to: Wybierz playlistę, do której chcesz dodać swój film | Wybierz playlistę, do której chcesz dodać swoje {videoCount} film(y/ów)\n    N playlists selected: Zaznaczono {playlistCount}\n    Added {count} Times: Dodano już wcześniej | Dodano {count} razy\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} filmów zostanie dodanych'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} film(y/ów) już dodano'\n    Allow Adding Duplicate Video(s): Zezwól na dodawanie duplikatów\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Nie było żadnych filmów do usunięcia.\n      Video has been removed: Film został usunięty\n      Playlist has been updated.: Playlista została zmieniona.\n      There was an issue with updating this playlist.: Pojawił się problem podczas wprowadzania zmian w playliście.\n      This video cannot be moved up.: Ten film nie może zostać przeniesiony wyżej.\n      This playlist is protected and cannot be removed.: Ta playlista jest zabezpieczona i nie może zostać usunięta.\n      Playlist {playlistName} has been deleted.: Playlista {playlistName} została usunięta.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Niektóre filmy z playlisty nie zostały jeszcze załadowane. Kliknij tutaj, by powielić playlistę mimo wszystko.\n      This playlist does not exist: Ta playlista nie istnieje\n      Playlist name cannot be empty. Please input a name.: Nazwa playlisty nie może być pusta. Proszę, nadaj nazwę.\n      There was a problem with removing this video: Pojawił się problem z usunięciem tego filmu\n      \"{videoCount} video(s) have been removed\": 1 film został usunięty | Usunięto {videoCount} film(y/ów)\n      This video cannot be moved down.: Ten film nie może zostać przeniesiony niżej.\n      This playlist is now used for quick bookmark: Ta playlista będzie używana dla funkcji Szybkiej Zakładki\n      Reverted to use {oldPlaylistName} for quick bookmark: Cofnięto zmianę. „{oldPlaylistName}” będzie używana dla funkcji Szybkiej Zakładki\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Teraz ta playlista, zamiast „{oldPlaylistName}”, będzie używana dla funkcji Szybkiej Zakładki . Kliknij tutaj, by cofnąć zmianę\n      This playlist is already being used for quick bookmark.: Ta playlista jest już używana dla funkcji Szybkiej Zakładki.\n      This playlist has a video with a duration error: Ta playlista zawiera przynajmniej jeden film bez określonego czasu trwania. Będą one rozmieszczone tak, jakby ich czas trwania wynosił zero.\n      Video has been removed. Click here to undo.: Wideo zostało usunięte. Kliknij aby powrócić.\n    Search for Videos: Szukaj filmów\n  Are you sure you want to delete this playlist? This cannot be undone: Czy na pewno chcesz usunąć tę playlistę? Nie można cofnąć tej czynności.\n  Sort By:\n    LatestPlayedFirst: Daty odtworzenia (od najświeższej)\n    EarliestCreatedFirst: Daty utworzenia (od najdawniejszej)\n    LatestCreatedFirst: Daty utworzenia (od najświeższej)\n    EarliestUpdatedFirst: Daty ostatniej zmiany (od najdawniejszej)\n    NameDescending: Z-A\n    EarliestPlayedFirst: Daty odtworzenia (od najdawniejszej)\n    LatestUpdatedFirst: Daty ostatniej zmiany (od najświeższej)\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Nie masz żadnych playlist. Kliknij na przycisk „Utwórz nową playlistę”, by dodać jedną.\n  Remove from Playlist: Usuń z playlisty\n  Save Changes: Zapisz zmiany\n  CreatePlaylistPrompt:\n    Create: Utwórz\n    Toast:\n      There was an issue with creating the playlist.: Pojawił się problem z utworzeniem playlisty.\n      Playlist {playlistName} has been successfully created.: Playlista „{playlistName}” została utworzona..\n      There is already a playlist with this name. Please pick a different name.: Istnieje już playlista z taką nazwą. Proszę wybrać inną nazwę.\n    New Playlist Name: Nowa nazwa playlisty\n  This playlist currently has no videos.: Ta playlista nie ma żadnych filmów.\n  Add to Playlist: Dodaj do playlisty\n  Move Video Down: Przenieś film niżej\n  Playlist Name: Nazwa playlisty\n  Remove Watched Videos: Usuń obejrzane filmy\n  Move Video Up: Przenieś film wyżej\n  Cancel: Anuluj\n  Delete Playlist: Usuń playlistę\n  Create New Playlist: Utwórz nową playlistę\n  Edit Playlist Info: Zmień opis playlisty\n  Copy Playlist: Powiel playlistę\n  Playlist Description: Opis playlisty\n  Add to Favorites: Dodaj do „{playlistName}”\n  Remove from Favorites: Usuń z „{playlistName}”\n  Enable Quick Bookmark With This Playlist: Włącz Szybką Zakładkę z tą playlistą\n  Playlists with Matching Videos: Playlisty z pasującymi filmami\n  Quick Bookmark Enabled: Włączono Szybką Zakładkę\n  Cannot delete the quick bookmark target playlist.: Nie można usunąć playlisty wskazanej dla Szybkiej Zakładki.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Czy na pewno chcesz usunąć 1 obejrzany film z tej listy odtwarzania? Nie można tego cofnąć. | Czy na pewno chcesz usunąć {playlistItemCount} obejrzanych filmów z tej listy odtwarzania? Nie można tego cofnąć.\n  Remove Duplicate Videos: Usuń zduplikowane filmy\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Czy na pewno chcesz usunąć 1 zduplikowany film z tej listy odtwarzania? Nie można tego cofnąć. | Czy na pewno chcesz usunąć {playlistItemCount} duplikatów wideo z tej listy odtwarzania? Nie można tego cofnąć.\n  Export Playlist: Eksportuj listę odtwarzania\n  The playlist has been successfully exported: Lista odtwarzania została pomyślnie wyeksportowana\n  TotalTimePlaylist: 'Całkowita długość: {duration}'\n  Export list of URLs: Eksportuj listę adresów URL\nHistory:\n  # On History Page\n  History: 'Historia'\n  Watch History: 'Historia oglądania'\n  Your history list is currently empty.: 'Twoja historia jest obecnie pusta.'\n  Search bar placeholder: Przeszukaj historię\n  Empty Search Message: W historii nie ma filmów, które pasowałyby do Twojego zapytania\n  Case Sensitive Search: Rozróżniaj wielkość liter\n  DateOldestHistory: Daty obejrzenia (od najdawniejszej)\n  DateNewestHistory: Daty obejrzenia (od najświeższej)\nSettings:\n  # On Settings Page\n  Settings: 'Ustawienia'\n  General Settings:\n    General Settings: 'Ogólne'\n    Fallback to Non-Preferred Backend on Failure: 'Wycofaj się do niepreferowanego back-endu przy niepowodzeniu'\n    Enable Search Suggestions: 'Włącz sugestie wyszukiwania'\n    Default Landing Page: 'Domyślna karta startowa'\n    Locale Preference: 'Ustawienia regionalne'\n    Preferred API Backend:\n      Preferred API Backend: 'Preferowany back-end API'\n      Local API: 'Lokalne API'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Sposób prezentacji filmów'\n      Grid: 'Siatka'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Ustawienia miniaturek'\n      Default: 'Domyślnie'\n      Beginning: 'Początek'\n      Middle: 'Środek'\n      End: 'Koniec'\n      Hidden: Nie pokazuj\n      Blur: Rozmyte\n    Region for Trending: '„Na czasie” z obszaru'\n        #! List countries\n    Check for Latest Blog Posts: Sprawdź ostatnie wpisy na blogu\n    Check for Updates: Szukaj aktualizacji\n    View all Invidious instance information: Pokaż informacje o wszystkich instancjach Invidious\n    System Default: Ustawienie systemowe\n    Clear Default Instance: Wyczyść domyślną instancję\n    Set Current Instance as Default: Ustaw obecną instancję jako domyślną\n    Current instance will be randomized on startup: Obecna instancja będzie losowana przy uruchamianiu\n    No default instance has been set: Nie ustawiono domyślnej instancji\n    The currently set default instance is {instance}: Obecnie domyślną instancją jest {instance}\n    Current Invidious Instance: Obecna instancja Invidious\n    External Link Handling:\n      No Action: Brak akcji\n      Ask Before Opening Link: Zapytaj przed otworzeniem odnośnika\n      Open Link: Otwórz odnośnik\n      External Link Handling: Obsługa zewnętrznych odnośników\n    Auto Load Next Page:\n      Tooltip: Wczytuj kolejne strony oraz komentarze automatycznie.\n      Label: Automatycznie wczytaj kolejną stronę\n    Open Deep Links In New Window: Odnośniki URL przekazane do FreeTube otwieraj w nowym oknie\n    Minimize to system tray: Minimalizuj do zasobnika systemowego\n  Theme Settings:\n    Theme Settings: 'Wygląd'\n    Match Top Bar with Main Color: 'Dopasuj górną belkę do głównego koloru'\n    Base Theme:\n      Base Theme: 'Bazowy motyw'\n      Black: 'Czarny'\n      Dark: 'Ciemny'\n      Light: 'Jasny'\n      Dracula: 'Drakula'\n      System Default: Domyślny systemu\n      Catppuccin Mocha: Catppuccin Mocha\n      Hot Pink: Gorący róż\n      Pastel Pink: Pastelowy róż\n      Nordic: Nordycki\n      Solarized Light: Nasłoneczniony jasny\n      Solarized Dark: Nasłoneczniony ciemny\n      Gruvbox Dark: Gruvbox ciemny\n      Gruvbox Light: Gruvbox jasny\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Medium: Everforest Ciemny\n      Everforest Light Hard: Everforest Mocno Jasny\n      Everforest Light Low: Everforest Lekko Jasny\n      Everforest Dark Hard: Everforest Mocno Ciemny\n      Everforest Dark Low: Everforest Lekko Ciemny\n      Everforest Light Medium: Everforest Jasny\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Główny kolor motywu'\n      Red: 'Czerwony'\n      Pink: 'Różowy'\n      Purple: 'Fioletowy'\n      Deep Purple: 'Granatowy'\n      Indigo: 'Indygo'\n      Blue: 'Niebieski'\n      Light Blue: 'Jasnoniebieski'\n      Cyan: 'Turkusowy'\n      Teal: 'Morski'\n      Green: 'Zielony'\n      Light Green: 'Jasnozielony'\n      Lime: 'Limonkowy'\n      Yellow: 'Żółty'\n      Amber: 'Bursztynowy'\n      Orange: 'Pomarańczowy'\n      Deep Orange: 'Głęboka pomarańcza'\n      Dracula Cyan: 'Dracula Turkusowy'\n      Dracula Green: 'Dracula Zielony'\n      Dracula Orange: 'Dracula Pomarańczowy'\n      Dracula Pink: 'Dracula Różowy'\n      Dracula Purple: 'Dracula Fioletowy'\n      Dracula Red: 'Dracula Czerwony'\n      Dracula Yellow: 'Dracula Żółty'\n      Catppuccin Mocha Pink: Catppuccin Mocha Różowy\n      Catppuccin Mocha Red: Catppuccin Mocha Czerwony\n      Catppuccin Mocha Yellow: Catppuccin Mocha Żółty\n      Catppuccin Mocha Green: Catppuccin Mocha Zielony\n      Catppuccin Mocha Teal: Catppuccin Mocha Turkusowy\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lawendowy\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Szafirowy\n      Catppuccin Mocha Blue: Catppuccin Mocha Niebieski\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Woda Różana\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flaming\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Peach: Catppuccin Mocha Brzoskwiniowy\n      Catppuccin Mocha Sky: Catppuccin Mocha Kolor Nieba\n      Catppuccin Mocha Maroon: Catppuccin Mocha Kasztanowy\n      Solarized Orange: Nasłoneczniony pomarańczowy\n      Solarized Red: Nasłoneczniony czerwony\n      Solarized Magenta: Nasłoneczniony magenta\n      Solarized Violet: Nasłoneczniony fioletowy\n      Solarized Blue: Nasłoneczniony niebieski\n      Solarized Cyan: Nasłoneczniony cyjan\n      Solarized Green: Nasłoneczniony zielony\n      Solarized Yellow: Nasłoneczniony żółty\n      Gruvbox Dark Green: Gruvbox ciemnozielony\n      Gruvbox Dark Yellow: Gruvbox żółty\n      Gruvbox Dark Blue: Gruvbox niebieski\n      Gruvbox Dark Purple: Gruvbox ciemnopurpurowy\n      Gruvbox Dark Aqua: Gruvbox ciemny wodny\n      Gruvbox Dark Orange: Gruvbox ciemnopomarańczowy\n      Gruvbox Light Red: Gruvbox jasnoczerwony\n      Gruvbox Light Blue: Gruvbox jasnoniebieski\n      Gruvbox Light Purple: Gruvbox jasnopurpurowy\n      Gruvbox Light Orange: Gruvbox jasnopomarańczowy\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Szafirowy\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Woda Różana\n      Catppuccin Frappe Blue: Catppuccin Frappe Niebieski\n      Catppuccin Frappe Pink: Catppuccin Frappe Różowy\n      Catppuccin Frappe Red: Catppuccin Frappe Czerwony\n      Catppuccin Frappe Sky: Catppuccin Frappe Kolor nieba\n      Catppuccin Frappe Teal: Catppuccin Frappe Turkusowy\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flaming\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Maroon: Catppuccin Frappe Kasztanowy\n      Catppuccin Frappe Peach: Catppuccin Frappe Brzoskwiniowy\n      Catppuccin Frappe Yellow: Catppuccin Frappe Żółty\n      Catppuccin Frappe Green: Catppuccin Frappe Zielony\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lawendowy\n      Everforest Dark Red: Everforest Ciemny Czerwony\n      Everforest Dark Orange: Everforest Ciemny Pomarańczowy\n      Everforest Dark Yellow: Everforest Ciemny Żółty\n      Everforest Dark Green: Everforest Ciemny Zielony\n      Everforest Dark Purple: Everforest Ciemny Fiolet\n      Everforest Light Red: Everforest Jasny Czerwony\n      Everforest Light Orange: Everforest Jasny Pomarańczowy\n      Everforest Light Yellow: Everforest Jasny Żółty\n      Everforest Light Green: Everforest Jasny Zielony\n      Everforest Light Aqua: Everforest Jasny Aqua\n      Everforest Light Blue: Everforest Jasny Niebieski\n      Everforest Dark Aqua: Everforest Ciemny Aqua\n      Everforest Light Purple: Everforest Jasny Fioletowy\n      Everforest Dark Blue: Everforest Ciemny Niebieski\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Czerwony\n    Secondary Color Theme: 'Drugi kolor motywu'\n        #* Main Color Theme\n    UI Scale: Skala UI\n    Expand Side Bar by Default: Domyślnie rozwiń pasek boczny\n    Disable Smooth Scrolling: Wyłącz płynne przewijanie\n    Hide Side Bar Labels: Schowaj etykiety paska bocznego\n    Hide FreeTube Header Logo: Schowaj logo FreeTube z paska górnego\n  Player Settings:\n    Player Settings: 'Odtwarzacz'\n    Play Next Video: 'Automatycznie otwórz polecane wideo'\n    Turn on Subtitles by Default: 'Domyślnie odtwarzaj z napisami'\n    Autoplay Videos: 'Autoodtwarzanie filmów'\n    Proxy Videos Through Invidious: 'Odtwarzaj filmy przez proxy Invidious'\n    Autoplay Playlists: 'Autoodtwarzanie playlist'\n    Enable Theatre Mode by Default: 'Domyślnie włącz tryb kinowy'\n    Default Volume: 'Domyślna głośność'\n    Default Playback Rate: 'Domyślna szybkość odtwarzania'\n    Default Video Format:\n      Default Video Format: 'Domyślny format filmów'\n      Dash Formats: 'Formaty DASH'\n      Legacy Formats: 'Stare formaty'\n      Audio Formats: 'Formaty audio'\n    Default Quality:\n      Default Quality: 'Domyślna jakość'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Czas do następnego autoodtwarzania\n    Scroll Volume Over Video Player: Kontroluj głośność kółkiem myszy na obszarze odtwarzacza\n    Display Play Button In Video Player: Pokaż przycisk odtwarzania na odtwarzaczu\n    Fast-Forward / Rewind Interval: Interwał przewijania\n    Scroll Playback Rate Over Video Player: Kontroluj szybkość odtwarzania kółkiem myszy na obszarze odtwarzacza\n    Max Video Playback Rate: Maksymalna szybkość odtwarzania\n    Video Playback Rate Interval: Przeskoki w wyborze prędkości odtwarzania\n    Screenshot:\n      Format Label: Format zrzutu\n      Quality Label: Jakość zrzutu\n      Ask Path: Pytaj o folder zapisu\n      Folder Label: Folder ze zrzutami\n      Folder Button: Wybierz folder\n      File Name Label: Wzorzec nazwy pliku\n      File Name Tooltip: 'Możesz użyć następujących zmiennych: %Y Rok 4 cyfry. %M Miesiąc 2 cyfry. %D Dzień 2 cyfry. %H Godzina 2 cyfry. %N Minuta 2 cyfry. %S Sekunda 2 cyfry. %T Milisekunda 3 cyfry. %s Sekunda filmu. %t Milisekunda filmu 3 cyfry. %i ID filmu.'\n      Error:\n        Forbidden Characters: Niedozwolone znaki\n        Empty File Name: Pusta nazwa pliku\n      Enable: Włącz zrzuty ekranu\n    Enter Fullscreen on Display Rotate: Przyłącz na cały ekran przy obrocie wyświetlacza\n    Skip by Scrolling Over Video Player: Przewijaj film kółkiem myszy na obszarze odtwarzacza\n    Autoplay Interruption Timer: Czas do przerwania autoodtwarzania\n    Default Viewing Mode:\n      Theater: Tryb kina\n      Picture in Picture: Obraz w obrazie\n      External Player: Zewnętrzny odtwarzacz ({externalPlayerName})\n      Default Viewing Mode: Domyślny tryb odtwarzania\n      Full Screen: Cały ekran\n  Subscription Settings:\n    Subscription Settings: 'Subskrypcje'\n    Fetch Feeds from RSS: Pobierz subskrypcje z RSS\n    Fetch Automatically: Automatycznie odświeżaj subskrypcje\n    Confirm Before Unsubscribing: Uniknij przypadkowego usunięcia subskrypcji\n\n    To: do\n    'Limit the number of videos displayed for each channel': Ogranicz liczbę filmów wyświetlanych dla każdego z kanałów\n  Privacy Settings:\n    Watch history has been cleared: Historia oglądania została wyczyszczona\n    Are you sure you want to remove your entire watch history?: Jesteś pewny/a, że chcesz usunąć całą historię oglądania?\n    Remove Watch History: Usuń historię oglądania\n    Search cache has been cleared: Plik pamięci podręcznej wyszukiwań został wyczyszczony\n    Are you sure you want to clear out your search cache?: Jesteś pewny/a, że chcesz wyczyścić plik pamięci podręcznej wyszukiwań?\n    Clear Search Cache: Wyczyść plik pamięci podręcznej wyszukiwań\n    Save Watched Progress: Zapisuj postęp odtwarzania\n    Remember History: Pamiętaj historię\n    Privacy Settings: Prywatność\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Czy jesteś pewny/a, że chcesz usunąć wszystkie subskrypcje i profile? Nie będzie można tego cofnąć.\n    Remove All Subscriptions / Profiles: Usuń wszystkie subskrypcje / profile\n    Save Watched Videos With Last Viewed Playlist: Zapisuj do historii film wraz z ostatnią odtwarzaną playlistą, która go zawierała\n    All playlists have been removed: Wszystkie playlisty zostały usunięte\n    Remove All Playlists: Usuń wszystkie playlisty\n    Are you sure you want to remove all your playlists?: Czy na pewno usunąć wszystkie Twoje playlisty?\n    Are you sure you want to clear out your search history and cache?: Na pewno usunąć historię wyszukiwania i pamięć podręczną?\n    Remember Search History: Pamiętaj historię wyszukiwania\n    Clear Search History and Cache: Wyczyść historię wyszukiwania i pamięć podręczną\n    Search history and cache have been cleared: Historia wyszukiwania i pamięć podręczna została wyczyszczona\n    Watched Progress Saving Mode:\n      Modes:\n        Semi-auto: Półautomatyczny\n        Never: Nie zapisuj\n        Auto: Automatyczny\n      Tooltip: Automatyczny – zapisuje przy każdym zamknięciu strony odtwarzania, po zakończeniu odtwarzania oraz gdy wystąpi błąd (np. ograniczenie przesyłu, wygaśnięcie sesji odtwarzania). Półautomatyczny – podobny do automatycznego, ale bez zapisu przy zamknięciu strony oraz z możliwością ręcznego zapisu postępu przyciskiem „Zapisz postęp odtwarzania”, umieszczonym pod odtwarzaczem.\n  Data Settings:\n    How do I import my subscriptions?: Jak mogę zaimportować swoje subskrypcje?\n    Unknown data key: Nieznany klucz danych\n    Unable to write file: Nie można zapisać pliku\n    Unable to read file: Nie można odczytać pliku\n    All watched history has been successfully exported: Cała historia oglądania została pomyślnie wyeksportowana\n    All watched history has been successfully imported: Cała historia oglądania została pomyślnie zaimportowana\n    History object has insufficient data, skipping item: Obiekt historii ma niewystarczającą ilość danych, pomijam element\n    Subscriptions have been successfully exported: Subskrypcje zostały z powodzeniem wyeksportowane\n    Invalid history file: Nieprawidłowy plik historii\n    Invalid subscriptions file: Nieprawidłowy plik subskrypcji\n    All subscriptions have been successfully imported: Wszystkie subskrypcje zostały z powodzeniem zaimportowane\n    All subscriptions and profiles have been successfully imported: Wszystkie subskrypcje i profile zostały z powodzeniem zaimportowane\n    Profile object has insufficient data, skipping item: Obiekt profilu ma niewystarczającą ilość danych, pomijam element\n    Export History: Wyeksportuj historię\n    Import History: Zaimportuj historię\n    Export FreeTube: Eksport do FreeTube\n    Export YouTube: Eksport do YouTube\n    Export NewPipe: Eksport do NewPipe\n    Export Subscriptions: Wyeksportuj subskrypcje\n    Import Subscriptions: Zaimportuj subskrypcje\n    Select Export Type: Wybierz typ eksportu\n    Data Settings: Dane\n    Manage Subscriptions: Zarządzaj subskrypcjami\n    Export Playlists: Wyeksportuj playlisty\n    All playlists has been successfully exported: Wszystkie playlisty pomyślnie wyeksportowano\n    Playlist insufficient data: Niewystarczająca ilość danych dla playlisty „{playlist}”, pomijam element\n    Import Playlists: Zaimportuj playlisty\n    All playlists has been successfully imported: Wszystkie playlisty pomyślnie zaimportowano\n    History File: Plik historii\n    Playlist File: Plik playlist\n    Subscription File: Plik subskrypcji\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Opcja ta wyeksportuje filmy ze wszystkich playlist, jako jedną playlistę o nazwie „Ulubione”.\\nOto jak wyeksportować i zaimportować filmy z playlist do starszych wersji FreeTube:\\n1. Wyeksportuj swoje playlisty z tą opcją włączoną.\\n 2. Usuń wszystkie swoje istniejące playlisty przy użyciu opcji „Usuń wszystkie playlisty” z ustawień prywatności.\\n3. Uruchom starszą wersję FreeTube, następnie zaimportuj wyeksportowane playlisty.\"\n      Label: Wyeksportuj playlisty dla starszych wersji FreeTube\n    Search history file: Plik historii wyszukiwania\n    Search history: Historia wyszukiwania\n    Import search history: Zaimportuj historię wyszukiwania\n    Export search history: Wyeksportuj historię wyszukiwania\n    All search history has been successfully imported: Cała historia wyszukiwania została pomyślnie zaimportowana\n    All search history has been successfully exported: Cała historia wyszukiwania została pomyślnie wyeksportowana\n  Distraction Free Settings:\n    Distraction Free Settings: Skupienie uwagi\n    Hide Live Chat: Schowaj czat na żywo\n    Hide Popular Videos: Schowaj filmy „Popularne”\n    Hide Trending Videos: Schowaj filmy „Na czasie”\n    Hide Recommended Videos: Schowaj polecane filmy\n    Hide Comment Likes: Schowaj polubienia komentarzy\n    Hide Channel Subscribers: Schowaj subskrybentów kanału\n    Hide Video Likes And Dislikes: Schowaj łapki w górę i w dół\n    Hide Video Views: Schowaj wyświetlenia filmów\n    Hide Active Subscriptions: Schowaj aktywne subskrypcje\n    Hide Playlists: Schowaj playlisty\n    Hide Video Description: Schowaj opis filmu\n    Hide Comments: Schowaj komentarze\n    Hide Sharing Actions: Schowaj opcje udostępniania\n    Hide Videos on Watch: 'Ukrywaj filmy po obejrzeniu'\n    Hide Live Streams: Schowaj transmisje na żywo\n    Hide Chapters: Schowaj rozdziały\n    Hide Upcoming Premieres: Schowaj nadchodzące premiery\n    Hide Channels: Schowaj filmy z kanałów\n    Hide Channels Placeholder: ID kanału\n    Display Titles Without Excessive Capitalisation: Wyświetlaj tytuły nie nadużywając wielkich liter i interpunkcji\n    Hide Channel Shorts: Schowaj kartę kanału „Filmy Short”\n    Hide Featured Channels: Schowaj polecane kanały\n    Hide Channel Playlists: Schowaj kartę kanału „Playlisty”\n    Sections:\n      Side Bar: Pasek boczny\n      Channel Page: Strona kanału\n      General: Ogólne\n      Watch Page: Strona odtwarzacza\n      Subscriptions Page: Strona subskrypcji\n    Hide Channel Releases: Schowaj kartę kanału „Wydawnictwa”\n    Hide Channel Podcasts: Schowaj kartę kanału „Podkasty”\n    Hide Subscriptions Videos: Schowaj filmy z subskrypcji\n    Hide Subscriptions Shorts: Schowaj filmy Short z subskrypcji\n    Hide Subscriptions Live: Schowaj transmisje na żywo z subskrypcji\n    Hide Profile Pictures in Comments: Nie pokazuj zdjęć profilowych w komentarzach\n    Hide Channels Invalid: Podane ID kanału jest niepoprawne\n    Hide Channels Disabled Message: Niektóre z kanałów nie zostały przetworzone, ponieważ zostały zablokowane po swoim ID. Funkcja jest zablokowana, aż do momentu, w którym zostaną one zaktualizowane\n    Hide Channels Already Exists: To ID kanału już jest\n    Hide Channels API Error: Nie udało się wyszukać użytkownika po podanym ID. Proszę sprawdzić, czy wpisane ID jest poprawne.\n    Hide Videos, Playlists and Channels Containing Text: Schowaj filmy i playlisty zawierające poniższy tekst\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Słowo, fragment słowa, lub wyrażenie\n    Hide Channel Home: Schowaj kartę kanału „Główna”\n    Show Added Items: Pokaż dodane rzeczy\n    Hide Channel Courses: Ukryj kartę „Kursy” kanału\n    Hide Channel Posts: Schowaj kartę kanału „Wpisy”\n    Hide Subscriptions Posts: Schowaj wpisy z subskrypcji\n  The app needs to restart for changes to take effect. Restart and apply change?: Aplikacja musi zostać ponownie uruchomiona, aby zmiany zostały wprowadzone. Uruchomić ponownie i zastosować zmiany?\n  Proxy Settings:\n    Your Info: O Tobie\n    Error getting network information. Is your proxy configured properly?: Wystąpił błąd przy pozyskiwaniu informacji o sieci. Czy Twoje proxy jest poprawnie ustawione?\n    City: Miasto\n    Region: Region\n    Country: Kraj\n    Ip: IP\n    Test Proxy: Sprawdź proxy\n    Clicking on Test Proxy will send a request to: Kliknięcie „Sprawdź proxy” wyśle żądanie do\n    Proxy Port Number: Numer portu proxy\n    Proxy Host: Host proxy\n    Proxy Protocol: Protokół proxy\n    Enable Tor / Proxy: Włącz Tor / Proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube nie ma wbudowanego proxy, ale może połączyć z zewnętrznym proxy. Na przykład z uruchomionym na Twoim komputerze, jak Tor, albo z uruchomionym na zewnętrznym serwerze, takim jak SOCKS5 proxy, oferowanym przez niektórych dostawców VPN. Po włączeniu upewnij się, że Twoje proxy lub Tor są skonfigurowane poprawnie, by FreeTube był w stanie wymieniać jakiekolwiek dane.\n    Proxy Username: Nazwa użytkownika usługi proxy\n    Proxy Password: Hasło do usługi proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Powiadamiaj, kiedy segment sponsorowany zostanie pominięty\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Adres URL interfejsu API SponsorBlock (Domyślnie jest https://sponsor.ajay.app)\n    Enable SponsorBlock: Włącz SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Opcja pominięcia\n      Auto Skip: Pomijaj automatycznie\n      Show In Seek Bar: Pokazuj na pasku postępu\n      Prompt To Skip: Zapytaj, czy pominąć\n      Do Nothing: Nic nie rób\n    Category Color: Kolor segmentu\n    UseDeArrowTitles: Użyj tytułów filmów z DeArrow\n    UseDeArrowThumbnails: Użyj DeArrow do miniaturek\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL do API generatora miniaturek DeArrow (Domyślny jest https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Niestandardowe argumenty zewnętrznego odtwarzacza\n    Custom External Player Executable: Niestandardowy plik wykonywalny zewnętrznego odtwarzacza\n    Ignore Unsupported Action Warnings: Ignoruj ostrzeżenia o nieobsługiwanych działaniach\n    External Player: Zewnętrzny odtwarzacz\n    External Player Settings: Zewnętrzny odtwarzacz\n    Players:\n      None:\n        Name: Żaden\n    Ignore Default Arguments: Zignoruj argumenty domyślne\n  Parental Control Settings:\n    Parental Control Settings: Kontrola rodzicielska\n    Hide Unsubscribe Button: Schowaj przycisk „Odsubskrybuj”\n    Show Family Friendly Only: Pokazuj tylko filmy przyjazne rodzinie\n    Hide Search Bar: Schowaj pole wyszukiwania\n    Hide Uploader on Watch page: Ukryj przesyłającego na stronie obserwowanych\n  Experimental Settings:\n    Replace HTTP Cache: Zastąp pamięć podręczną HTTP\n    Experimental Settings: Eksperymentalne\n    Warning: Te ustawienia są w fazie testów i po włączeniu mogą powodować wywalanie się programu. Zalecane jest stworzenie kopii zapasowej. Używaj na własne ryzyko!\n  Password Dialog:\n    Enter Password To Unlock: Wprowadź hasło, by odblokować ustawienia\n    Password: Hasło\n  Password Settings:\n    Password Settings: Hasło\n    Set Password To Prevent Access: Ustaw hasło, aby zabezpieczyć dostęp do ustawień\n    Set Password: Ustaw hasło\n    Remove Password: Usuń hasło\n  Sort Settings Sections (A-Z): Sortuj sekcje ustawień (A-Z)\n  Return to Settings Menu: Wróć do menu „Ustawienia”\n  SABR:\n    Label: Włącz SABR jako back-end dla DASH-a\n    Tooltip: W przyszłości SABR będzie jedynym back-endem DASH-a i nie będzie można go wyłączyć. Ten przełącznik został wprowadzony na wypadek, gdyby wczesna implementacja powodowała problemy.\nAbout:\n  #On About page\n  About: 'O projekcie'\n  #& About\n#On Channel Page\n  Website: Strona internetowa\n  Blog: Blog\n  Credits: Zasługi\n  FAQ: FAQ\n  Email: E-mail\n  Beta: Beta\n  Donate: Wesprzyj\n  Help: Pomoc\n  these people and projects: tym ludziom i projektom\n  Translate: Przetłumacz\n  room rules: zasady pokoju\n  Chat on Matrix: Czat na Matrix\n  Mastodon: Mastodon\n  Please check for duplicates before posting: Proszę poszukać duplikatów przed wysłaniem\n  GitHub issues: problemy na GitHub\n  Report a problem: Zgłoś problem\n  FreeTube Wiki: Wiki FreeTube\n  GitHub releases: Wydania na GitHub\n  Downloads / Changelog: Wydania / Lista zmian\n  Source code: Kod źródłowy\n  Discussions: Dyskusje\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licencjonowany na {licenseLink}\n  Please read the {roomRulesLink}: Proszę przeczytać {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube powstał dzięki {creditsPageLink}\nChannel:\n  Subscribe: 'Zasubskrybuj'\n  Unsubscribe: 'Odsubskrybuj'\n  Search Channel: 'Przeszukaj kanał'\n  Your search results have returned 0 results: 'Twoje zapytanie zwróciło 0 wyników'\n  Videos:\n    Videos: 'Filmy'\n    This channel does not currently have any videos: 'Ten kanał nie ma obecnie żadnych filmów'\n    Sort Types:\n      Newest: 'Najnowsze'\n      Oldest: 'Najstarsze'\n      Most Popular: 'Najpopularniejsze'\n  Playlists:\n    Playlists: 'Playlisty'\n    This channel does not currently have any playlists: 'Ten kanał nie ma żadnych playlist'\n    Sort Types:\n      Last Video Added: 'Ostatnio dodany film'\n      Newest: 'Najnowsze'\n      Oldest: 'Najstarsze'\n  About:\n    About: 'O kanale'\n    Channel Description: 'Opis kanału'\n    Featured Channels: 'Polecane kanały'\n    Details: Szczegóły\n    Joined: Data dołączenia\n    Location: Lokalizacja\n    Tags:\n      Tags: Tagi\n      Search for: Szukaj „{tag}”\n  Added channel to your subscriptions: Dodano kanał do twoich subskrypcji\n  Removed subscription from {count} other channel(s): Usunięto subskrypcje z {count} pozostałych kanałów\n  Channel has been removed from your subscriptions: Kanał został usunięty z twoich subskrypcji\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Kanał ten ma ograniczenie wiekowe, dlatego nie zostanie wyświetlony we FreeTube.\n  Channel Tabs: Karty kanału\n  This channel does not exist: Nie ma takiego kanału\n  This channel does not allow searching: Ten kanał nie zezwala na przeszukiwanie\n  Posts:\n    This channel currently does not have any posts: Ten kanał nie ma obecnie żadnych wpisów\n    votes: '{votes} głosów'\n    Reveal Answers: Pokaż odpowiedzi\n    Hide Answers: Schowaj odpowiedzi\n    Video hidden by FreeTube: Film schowany przez FreeTube\n    View Full Post: Zobacz całe wpisy\n    Viewing Posts Only Supported By Invidious: Wyświetlanie postów jest wspierane tylko przez Invidious. Możesz zobaczyć zawartość nie korzystając z Invidious, przechodząc do karty „Społeczność” danego kanału.\n  Live:\n    Live: Transmisje\n    This channel does not currently have any live streams: Ten kanał nie ma obecnie żadnych transmisji\n  Shorts:\n    This channel does not currently have any shorts: Ten kanał nie ma obecnie żadnych filmów Short\n  Releases:\n    Releases: Wydania\n    This channel does not currently have any releases: Ten kanał nie ma obecnie żadnych wydawnictw\n  Podcasts:\n    Podcasts: Podkasty\n    This channel does not currently have any podcasts: Ten kanał nie ma żadnych podkastów\n  Home:\n    Home: Główna\n    View Playlist: Zobacz playlistę\n  Courses:\n    Courses: Kursy\n    This channel does not currently have any courses: Na tym kanale nie ma obecnie żadnych kursów\nVideo:\n  Mark As Watched: 'Oznacz jako obejrzany'\n  Remove From History: 'Usuń z historii'\n  Video has been marked as watched: 'Film został oznaczony jako obejrzany'\n  Video has been removed from your history: 'Film został usunięty z Twojej historii'\n  Open in YouTube: 'Otwórz na stronie YouTube'\n  Copy YouTube Link: 'Skopiuj odnośnik do strony YouTube'\n  Open YouTube Embedded Player: 'Otwórz odtwarzacz YouTube'\n  Copy YouTube Embedded Player Link: 'Skopiuj odnośnik do odtwarzacza YouTube'\n  Open in Invidious: 'Otwórz na stronie Invidious'\n  Copy Invidious Link: 'Skopiuj odnośnik do strony Invidious'\n  Views: 'wyświetleń'\n  Watched: 'Obejrzany'\n  # As in a Live Video\n  Live: 'Transmisja'\n  Live Now: 'Teraz na żywo'\n  Live Chat: 'Czat na żywo'\n  Enable Live Chat: 'Włącz czat na żywo'\n  Live Chat is currently not supported in this build.: 'Czat na żywo nie jest obecnie wspierany w tej kompilacji.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Czat na żywo jest włączony. Wiadomości z czatu pojawią się tutaj po wysłaniu.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Czat na żywo nie wspiera obecnie API Invidious. Konieczne jest połączenie bezpośrednie z YouTube.'\n  Published:\n    In less than a minute: Za mniej niż minutę\n  Published on: 'Opublikowano'\n#& Videos\n  Autoplay: Autoodtwarzanie\n  Previous: Poprzedni\n  Next: Dalej\n  Reverse Playlist: Odwróć playlistę\n  Shuffle Playlist: Losuj z playlisty\n  Loop Playlist: Zapętl playlistę\n  Starting soon, please refresh the page to check again: Wkrótce się zacznie. Proszę odświeżyć stronę, aby ponownie sprawdzić\n  Copy Invidious Channel Link: Skopiuj odnośnik do kanału na stronie Invidious\n  Open Channel in Invidious: Otwórz kanał na stronie Invidious\n  Copy YouTube Channel Link: Skopiuj odnośnik do kanału na stronie YouTube\n  Open Channel in YouTube: Otwórz kanał na stronie YouTube\n  Started streaming on: Transmisję rozpoczęto\n  Streamed on: Transmitowane dnia\n  Video has been removed from your saved list: Film został usunięty z Twojej listy zapisanych\n  Video has been saved: Film został zapisany\n  Save Video: Zapisz film\n  Sponsor Block category:\n    music offtopic: niemuzyczny\n    interaction: o interakcji\n    self-promotion: z własną promocją\n    outro: z ekranem końcowym\n    intro: z intrem\n    sponsor: sponsorowany\n    filler: z wypełniaczem\n    recap: z podsumowaniem\n  External Player:\n    Unsupported Actions:\n      reversing playlists: odwracania playlist\n      shuffling playlists: losowania z playlist\n      looping playlists: zapętlania playlist\n      opening specific video in a playlist (falling back to opening the video): otwierania wskazanego filmu na playliście (zamiast tego nastąpi otwarcie filmu)\n      opening playlists: otwierania playlist\n      setting a playback rate: ustawienia prędkości odtwarzania\n      starting video at offset: rozpoczynania filmu z przesunięciem\n    UnsupportedActionTemplate: '{externalPlayer} nie obsługuje: {action}'\n    OpeningTemplate: Otwieranie {videoOrPlaylist} w {externalPlayer}...\n    playlist: playlisty\n    video: filmu\n    OpenInTemplate: Otwórz w {externalPlayer}\n  Premieres: Premiery\n  Show Super Chat Comment: Pokazuj komentarze z „Superczatu”\n  Scroll to Bottom: Przewiń do końca\n  Upcoming: Nadchodzące\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Czat na żywo jest nie dostępny dla tej transmisji. Być może został on wyłączony przez osobę wstawiającą.\n  Unhide Channel: Pokaż kanał\n  Hide Channel: Ukryj kanał\n  More Options: Więcej opcji\n  Player:\n    TranslatedCaptionTemplate: '{language} (przetłumaczono z: \"{originalLanguage}\")'\n    Audio Tracks: Ścieżki audio\n    Theatre Mode: Tryb kina\n    Exit Theatre Mode: Wyłącz tryb kina\n    Exit Full Window: Wyłącz pełne okno\n    Take Screenshot: Zrób zrzut ekranu\n    Show Stats: Pokaż statystyki\n    Hide Stats: Schowaj statystyki\n    Stats:\n      Stats: Statystyki\n      Video ID: 'ID filmu: {videoId}'\n      Player Dimensions: 'Rozmiary odtwarzacza: {width}x{height}'\n      Bitrate: 'Bitrate: {bitrate} kbps'\n      Volume: 'Głośność: {volumePercentage}%'\n      Bandwidth: 'Szerokość pasma: {bandwidth} kbps'\n      Buffered: 'Zbuforowano: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Zgubione klatki: {droppedFrames} / Wszystkie klatki: {totalFrames}'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Kodeki: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Kodeki: {videoCodec} / {audioCodec}'\n      Media Formats: 'Formaty ścieżek: {formats}'\n      Resolution: 'Rozdzielczość: {width}x{height}{''@''}{frameRate}'\n    You appear to be offline: Zdaje się, że jesteś rozłączony.\n    Playback will resume automatically when your connection comes back: Odtwarzanie zostanie wznowione, jak tylko połączenie zostanie odzyskane.\n    Skipped segment: Pominięto segment {segmentCategory}\n    Full Window: Pełne okno\n    Autoplay is off: Autoodtwarzanie jest wyłączone\n    Autoplay is on: Autoodtwarzanie jest włączone\n  IP block: YouTube uniemożliwił odtworzenie filmów blokując Twój adres IP. Możesz spróbować przełączyć się na inny, korzystając z VPN lub proxy.\n  AgeRestricted: Filmy z ograniczeniem wiekowym nie mogą być odtwarzane przez FreeTube, ponieważ wymagają danych logowania do konta Google z potwierdzonym wiekiem użytkownika.\n  MembersOnly: Filmy tylko dla wspierających nie mogą być odtwarzane przez FreeTube, ponieważ wymagają danych logowania do konta Googla oraz płatną subskrypcje kanału.\n  Unlisted: Niepubliczny\n  DeArrow:\n    Show Original Details: Pokaż szczegóły oryginału\n    Show Modified Details: Pokaż zmodyfikowane szczegóły\n  DRMProtected: FreeTube nie może odtwarzać filmów chronionych przez DRM, ponieważ wymagają one obsługi zastrzeżonych prawnie komponentów o zamkniętym kodzie. By obejrzeć ten film, możesz odwiedzić oficjalną stronę YouTube, korzystając z przeglądarki z włączoną obsługą DRM.\n#& Playlists\n  Watched Progress Saved: Postęp odtwarzania zapisany\n  Save Watched Progress: Zapisz postęp odtwarzania\n  Popout Live Chat: Czat w okienku\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Do końca reklamy z początku pozostało: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'SABR – do przeczekania pozostało: {remindingTimeSeconds}s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Zobacz całą playlistę'\n  Last Updated On: 'Ostatnio zaktualizowano'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlista\n  Sort By:\n    VideoTitleDescending: Tytułu (Z-A)\n    VideoTitleAscending: Tytułu (A-Z)\n    Custom: Własny porządek\n    DateAddedOldest: Daty dodania (od najdawniejszej)\n    DateAddedNewest: Daty dodania (od najświeższej)\n    AuthorAscending: Po autorze (A-Z)\n    AuthorDescending: Po autorze (Z-A)\n    VideoDurationDescending: Czasu trwania (od najdłuższych)\n    VideoDurationAscending: Czasu trwania (od najkrótszych)\n    PublishedNewest: Daty publikacji (od najświeższej)\n    PublishedOldest: Daty publikacji (od najdawniejszej)\nChange Format:\n  Change Media Formats: 'Zmień formaty wideo'\n  Use Dash Formats: 'Użyj formatów DASH'\n  Use Legacy Formats: 'Użyj starych formatów'\n  Use Audio Formats: 'Użyj formatów audio'\n  Audio formats are not available for this video: Formaty audio nie są dostępne dla tego filmu\n  Dash formats are not available for this video: Formaty DASH nie są dostępne dla tego filmu\n  Legacy formats are not available for this video: Ten film nie jest dostępny w starych formatach\nShare:\n  Share Video: 'Podziel się filmem'\n  Share Playlist: 'Podziel się playlistą'\n  Copy Link: 'Skopiuj odnośnik'\n  Open Link: 'Otwórz odnośnik'\n  Copy Embed: 'Skopiuj odnośnik do osadzenia'\n  Open Embed: 'Otwórz odnośnik do osadzenia'\n  # On Click\n  Invidious URL copied to clipboard: 'Skopiowano URL Invidious do schowka'\n  Invidious Embed URL copied to clipboard: 'Skopiowano URL odtwarzacza Invidious do schowka'\n  YouTube URL copied to clipboard: 'Skopiowano URL YouTube do schowka'\n  YouTube Embed URL copied to clipboard: 'Skopiowano URL odtwarzacza YouTube do schowka'\n  Include Timestamp: Dołącz znacznik czasu\n  YouTube Channel URL copied to clipboard: Skopiowano URL kanału na YouTube do schowka\n  Invidious Channel URL copied to clipboard: Skopiowano URL kanału na Invidious do schowka\n  Share Channel: Podziel się kanałem\n  Share Post: Podziel się wpisem\nMini Player: 'Mini odtwarzacz'\nComments:\n  Comments: 'Komentarze'\n  Click to View Comments: 'Kliknij, aby zobaczyć komentarze'\n  Getting comment replies, please wait: 'Pobieranie odpowiedzi do komentarza, proszę poczekać'\n  Hide Comments: 'Schowaj komentarze'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Nie ma żadnych komentarzy odnośnie tego filmu'\n  Load More Comments: 'Pokaż więcej komentarzy'\n  There are no more comments for this video: Nie ma więcej komentarzy pod tym filmem\n  Newest first: Najpierw najnowsze\n  Top comments: Najlepsze komentarze\n  Show More Replies: Pokaż więcej odpowiedzi\n  Pinned by: Przypięty przez\n  Member: Wspierający\n  Hearted: z serduszkiem\n  View {replyCount} replies: Zobacz 1 odpowiedź | Zobacz {replyCount} odpowiedzi\n  Subscribed: Zasubskrybowano\n  There are no comments available for this post: Nie ma żadnych komentarzy pod tym wpisem\n  Hide {replyCount} replies: Ukryj 1 odpowiedź | Ukryj {replyCount} odpowiedzi\n  View 1 reply from {channelName}: Zobacz 1 odpowiedź od {channelName}\n  View {replyCount} replies from {channelName} and others: Zobacz {replyCount} odpowiedzi od {channelName} i innych\nUp Next: 'Następne'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Błąd lokalnego API (kliknij by skopiować)'\nInvidious API Error (Click to copy): 'Błąd API Invidious (kliknij by skopiować)'\nFalling back to Invidious API: 'Wycofywanie do API Invidious'\nFalling back to Local API: 'Wycofywanie do lokalnego API'\nLoop is now disabled: 'Zapętlenie jest teraz wyłączone'\nLoop is now enabled: 'Zapętlenie jest teraz włączone'\nShuffle is now disabled: 'Losowanie jest teraz wyłączone'\nShuffle is now enabled: 'Losowanie jest teraz włączone'\nPlaying Next Video: 'Odtwarzanie następnego filmu'\nPlaying Previous Video: 'Odtwórz poprzedni film'\nCanceled next video autoplay: 'Anulowano odtworzenie następnego filmu'\n'The playlist has ended. Enable loop to continue playing': 'Playlista się zakończyła. Włącz zapętlanie by kontynuować odtwarzanie'\n\nYes: 'Tak'\nNo: 'Nie'\nLocale Name: polski\nProfile:\n  '{profile} is now the active profile': '{profile} jest teraz aktywnym profilem'\n  Your default profile has been changed to your primary profile: Twój domyślny profil został zmieniony na profil główny\n  Removed {profile} from your profiles: Usunięto {profile} z twoich profili\n  Your default profile has been set to {profile}: '{profile} został ustawiony jako Twój domyślny profil'\n  Profile has been updated: Zaktualizowano profil\n  Profile has been created: Utworzono profil\n  Your profile name cannot be empty: Nazwa profilu nie może być pusta\n  All subscriptions will also be deleted.: Wszystkie subskrypcje również zostaną usunięte.\n  Are you sure you want to delete this profile?: Czy jesteś pewny/a, że chcesz usunąć ten profil?\n  Delete Profile: Usuń profil\n  Make Default Profile: Ustaw jako profil domyślny\n  Update Profile: Zaktualizuj profil\n  Create Profile: Utwórz profil\n  Profile Preview: Podgląd profilu\n  Custom Color: Własny kolor\n  Color Picker: Wybór koloru\n  Edit Profile: Edytuj profil\n  Create New Profile: Utwórz nowy profil\n  Profile Manager: Menadżer profili\n  All Channels: Wszystkie kanały\n  Profile Select: Wybór profilu\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Czy jesteś pewny/a, że chcesz usunąć wybrane kanały? Te kanały nie  zostaną usunięte w żadnym innym profilu.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : To jest Twój główny profil. Czy jesteś pewny/a, że chcesz usunąć wybrane kanały? Te kanały zostaną usunięte we wszystkich profilach, w których się znajdują.\n  No channel(s) have been selected: Nie wybrano żadnego kanału\n  Add Selected To Profile: Dodaj wybrane do profilu\n  Delete Selected: Usuń wybrane\n  Select None: Nic nie wybieraj\n  Select All: Wybierz wszystkie\n  '{number} selected': Wybrano {number}\n  Other Channels: Inne kanały\n  Subscription List: Lista subskrypcji\n  Profile Filter: Filtr profilu\n  Profile Settings: Profil\n  Toggle Profile List: Włącz/wyłącz listę profili\n  Open Profile Dropdown: Otwórz rozwijane menu profilu\n  Close Profile Dropdown: Zamknij rozwijane menu profilu\n  Profile Name: Nazwa profilu\n  Edit Profile Name: Edytuj nazwę profilu\n  Create Profile Name: Nadaj nazwę profilowi\nThe playlist has been reversed: Playlista została odwrócona\nA new blog is now available, {blogTitle}. Click to view more: 'Nowy wpis na blogu jest dostępny, {blogTitle}. Kliknij, aby zobaczyć więcej'\nDownload From Site: Pobierz ze strony\nVersion {versionNumber} is now available!  Click for more details: Wersja {versionNumber} jest już dostępna!  Kliknij po więcej szczegółów\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Ten film jest niedostępny z powodu brakujących formatów. Przyczyną może być blokada regionalna.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Po włączeniu FreeTube będzie używać RSS zamiast domyślnej metody pobierania subskrypcji. RSS jest szybszy i zapobiega blokadzie IP, ale nie dostarcza informacji, takich jak czas trwania filmu, status transmisji na żywo, czy wpisy\n    Fetch Automatically: Po włączeniu lub przy otwarciu nowego okna FreeTube będzie automatycznie odświeżał Twoje subskrypcje.\n  General Settings:\n    Fallback to Non-Preferred Backend on Failure: Po włączeniu, kiedy Twój preferowany API napotka problem, FreeTube automatycznie spróbuje użyć niepreferowanego API jako metody zapasowej.\n    Preferred API Backend: Wybierz back-end , który FreeTube użyje do uzyskiwania danych. Lokalne API jest wbudowanym ekstraktorem. API Invidious wymaga połączenia z serwerem Invidious.\n    Region for Trending: Obszar filmów „Na czasie” pozwala wybrać kraj, z którego chciałbyś zobaczyć filmy zdobywające popularność.\n    Invidious Instance: Serwer Invidious, którym FreeTube będzie się łączył do wywołań API.\n    Thumbnail Preference: Wszystkie miniaturki na FreeTube zostaną ukryte, rozmazane albo zastąpione klatką z filmu zamiast miniaturki domyślnej.\n    External Link Handling: \"Wybierz domyślne zachowanie kiedy odnośnik, który nie może zostać otworzony w FreeTube, został kliknięty.\\nDomyślnie FreeTube otworzy kliknięty odnośnik w domyślnej przeglądarce.\\n\"\n    Open Deep Links In New Window: Odnośniki URL przekazane do FreeTube (np. przez rozszerzenie przeglądarki, albo argumenty linii komend) są otwierane w nowym oknie.\n  Player Settings:\n    Default Video Format: Ustaw formaty, które zostaną użyte do odtwarzania filmów. Formaty DASH obsługują wyższe rozdzielczości. Stare formaty są ograniczone do 360p, ale zużywają mniej przepustowości. Formaty audio odtwarzają tylko dźwięk.\n    Proxy Videos Through Invidious: Filmy dostarczane będą poprzez Invidious, a nie przez bezpośrednie połączenie z YouTube.\n    Scroll Playback Rate Over Video Player: Umieść kursor nad odtwarzaczem, przytrzymaj klawisz „Ctrl” („Command” na Mac-u) i przewijaj kółkiem myszy w górę i w dół, aby kontrolować szybkość odtwarzania. Przytrzymaj klawisz „Ctrl” („Command” na Mac-u) i kliknij lewym przyciskiem myszy, by szybko powrócić do domyślnej wartości (1x, chyba że została zmieniona w ustawieniach).\n    Skip by Scrolling Over Video Player: Użyj kółka myszy, by przewijać film tak jak w MPV.\n  External Player Settings:\n    Ignore Warnings: Nie pokazuj ostrzeżeń o nieobsługiwanych akcjach przez zewnętrzny odtwarzacz (n.p. odwracanie playlist, itp.).\n    External Player: Wybranie zewnętrznego odtwarzacza spowoduje wyświetlenie na miniaturkach ikony, która otworzy film (playlistę, jeśli są obsługiwane) w zewnętrznym odtwarzaczu. Uwaga! Ustawienia Invidious nie mają wpływu na zewnętrzny odtwarzacz.\n    Custom External Player Arguments: Wszelkie niestandardowe argumenty wiersza poleceń, które chcesz przekazać do zewnętrznego odtwarzacza.\n    Custom External Player Executable: FreeTube domyślnie przyjmie, że wybrany odtwarzacz jest do znalezienia za pomocą zmiennej środowiskowej PATH. Jeśli trzeba, można tutaj ustawić niestandardową ścieżkę.\n    DefaultCustomArgumentsTemplate: \"(Domyślnie: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Nie wysyłaj do zewnętrznego odtwarzacza żadnych domyślnych argumentów (takich jak prędkość odtwarzania, URL playlisty itp.), oprócz URL-u filmu. Niestandardowe argumenty zostaną wysłane.\n  Experimental Settings:\n    Replace HTTP Cache: Wyłącza opartą na przestrzeni dyskowej pamięć podręczną HTTP Electrona i włącza własny obraz pamięci podręcznej wewnątrz pamięci RAM. Spowoduje to większe użycie pamięci RAM.\n  Distraction Free Settings:\n    Hide Channels: Wprowadź ID kanału, aby schować wszystkie filmy i playlisty tego kanału, oraz sam kanał z wyszukiwań, z zakładek „Na czasie” i „Popularne” oraz z polecanych. ID kanału musi być dokładnym dopasowaniem, z uwzględnieniem wielkości liter.\n    Hide Subscriptions Live: Ta opcja została nadpisana opcją ogólną „{appWideSetting}” z podgrupy „{subsection}” grupy „{settingsSection}”\n    Hide Videos, Playlists and Channels Containing Text: Wprowadź słowo, fragment słowa, lub wyrażenie (bez znaczenia jest wielkość liter), by schować wszystkie filmy i playlisty zawierające w tytule podane sformułowanie w całym programie FreeTube, poza Historią, Twoimi playlistami i filmami w tych playlistach.\n    Hide Videos on Watch: Ukryj obejrzane filmy z kart „Filmy”, „Filmy Short” oraz z „Na żywo” na stronie subskrypcji oraz na stronie kanału. Opcja ta nie wpływa na kartę „Główna” ze strony kanału\n  SponsorBlock Settings:\n    UseDeArrowTitles: Zastąp tytuły filmów tytułami zasugerowanymi przez użytkowników DeArrow.\n    UseDeArrowThumbnails: Zastąp miniaturki filmów miniaturkami z DeArrow.\nPlaying Next Video Interval: Odtwarzanie kolejnego filmu już za chwilę. Wciśnij aby przerwać. | Odtwarzanie kolejnego filmu za {nextVideoInterval} sekundę. Wciśnij aby przerwać. | Odtwarzanie kolejnego filmu za {nextVideoInterval} sekund. Wciśnij aby przerwać.\nMore: Więcej\nUnknown YouTube url type, cannot be opened in app: Nieznany typ adresu URL YouTube, nie można go otworzyć w aplikacji\nOpen New Window: Otwórz nowe okno\nDefault Invidious instance has been cleared: Domyślna instancja Invidious została wyczyszczona\nDefault Invidious instance has been set to {instance}: Domyślna instancja Invidious została ustawiona na {instance}\nSearch Bar:\n  Clear Input: Wyczyść pole\n  Remove: Usuń\nExternal link opening has been disabled in the general settings: Otwieranie zewnętrznych odnośników zostało wyłączone w ustawieniach ogólnych\nAre you sure you want to open this link?: Czy na pewno chcesz otworzyć ten link?\nScreenshot Error: Wykonanie zrzutu nie powiodło się. {error}\nScreenshot Success: Zapisano zrzut ekranu jako „{filePath}”\nNew Window: Nowe okno\nChannels:\n  Title: Lista kanałów\n  Count: Znaleziono {number} kanał(y/ów).\n  Empty: Twoja lista kanałów jest na razie pusta.\n  Unsubscribe Prompt: Czy na pewno chcesz zrezygnować z subskrypcji „{channelName}”?\n  Channels: Kanały\n  Search bar placeholder: Przeszukaj kanały\nClipboard:\n  Copy failed: Skopiowanie do zasobnika nie powiodło się\n  Cannot access clipboard without a secure connection: Bez bezpiecznego połączenia nie można uzyskać dostępu do schowka\nChapters:\n  Chapters: Rozdziały\n  Key Moments: Kluczowe momenty\nPreferences: Preferencje\nOk: Ok\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Nie ma na razie żadnych filmów z takim hashtagiem\nChannel Hidden: '{channel} dodany do filtra kanałów'\nGo to page: Idź do {page}\nChannel Unhidden: '{channel} usunięty z filtra kanału'\nTag already exists: Tag „{tagName}” już istnieje\nTrimmed input must be at least N characters long: Przycięte wyrażenie musi mieć przynajmniej 1 znak | Przycięte wyrażenie musi mieć przynajmniej {length} znaki/ów\nAge Restricted:\n  This video is age restricted: Ten film ma ograniczenie wiekowe\n  This channel is age restricted: Ten kanał ma ograniczenie wiekowe\nClose Banner: Zamknij Baner\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nFeed:\n  Refresh Feed: Odśwież „{subscriptionName}”\n  Feed Last Updated: 'Ostatnia aktualizacja „{feedName}”: {date}'\nMoments Ago: chwilę temu\nYes, Delete: Tak, usuń\nSearch character limit: Zapytanie przekroczyło limit {searchCharacterLimit} znaków\nYes, Restart: Tak, uruchom ponownie\nYes, Open Link: Tak, otwórz odnośnik\nCancel: Anuluj\nSearch Listing:\n  Label:\n    Subtitles: Napisy\n    Closed Captions: Napisy z opisami\n    4K: 4K\n    New: Nowe\n    3D: 3D\n    VR180: VR180\n    8K: 8K\n    360 Video: 360°\nKeys:\n  arrowup: Strzałka do góry\n  arrowright: Strzałka w prawo\n  arrowleft: Strzałka w lewo\n  arrowdown: Strzałka w dół\n  alt: Alt\n  ctrl: Ctrl\n  enter: Enter\n  plus: Plus\n  shift: Shift\nRight-click or hold to see history: Kliknij prawym lub przytrzymaj, by zobaczyć historię\nshortcutJoinOperator: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nAutoplay Interruption Timer: Automatyczne odtwarzanie zostało anulowane, z powodu {autoplayInterruptionIntervalHours} godzin(y) braku aktywności\nDescription:\n  Expand Description: '...więcej'\n  Collapse Description: Zwiń\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Skróty\n  Sections:\n    Video:\n      Playback: Filmy: Odtwarzanie\n      General: Filmy: Ogólne\n    App:\n      Situational: 'Aplikacja: Kontekstowe'\n      General: Aplikacja: Ogólne\n  New Window: Otwórz nowe okno\n  Navigate to Settings: Przejdź do strony Ustawień\n  Navigate to History: Przejdź do strony Historii\n  Focus Secondary Search: Przełącz na drugi pasek wyszukiwania (jeżeli dostępny)\n  Captions: Przełącz napisy WŁĄCZ/WYŁĄCZ\n  Show Keyboard Shortcuts: Pokaż skróty\n  History Forward: Dalej o jedną stronę\n  Refresh: Wczytaj ponownie subskrypcje z nową zawartością\n  History Backward: Wróć o jedną stronę\n  Fullscreen: Przełącz na cały ekran\n  Picture in Picture: Przełącz na tryb obraz w obrazie\n  Decrease Video Speed: Zwolnij odtwarzanie filmu o wartość przeskoku w wyborze prędkości odtwarzania filmu\n  Full Window: Przełącz na pełne okno\n  Take Screenshot: Zrób zrzut ekranu\n  Minimize Window: Zminimalizuj okno\n  Volume Up: Podgłośnij\n  Volume Down: Ścisz\n  Last Chapter: Poprzedni rozdział\n  Next Chapter: Następny rozdział\n  Skip by Tenths: Przeskakuj przez film o wartość procentową („3” przeskakuje do 30% długości)\n  Small Rewind: Przewiń o X sekund wstecz, bazując na interwale przewijania oraz obecnej prędkości odtwarzania\n  Small Fast Forward: Przewiń o X sekund do przodu, bazując na interwale przewijania oraz obecnej prędkości odtwarzania\n  Reset Zoom: Resetuj stopień przybliżenia / skalę UI\n  Zoom Out: Pomniejsz\n  Play: Przełącz na odtwarzanie/wstrzymanie\n  Mute: Przełącz na wyciszony\n  Search in New Window: Wyszukaj w nowym oknie\n  Increase Video Speed: Przyśpiesz odtwarzanie filmu o wartość przeskoku w wyborze prędkości odtwarzania filmu\n  Theatre Mode: Przełącz na tryb kina\n  Close Window: Zamknij okno\n  Toggle Developer Tools: Przełącz narzędzia deweloperskie\n  Zoom In: Powiększ\n  Focus Search: Przełącz na pasek wyszukiwania\n  Last Frame: Poprzednia klatka (podczas wstrzymania)\n  Next Frame: Następna klatka (podczas wstrzymania)\n  Large Rewind: Przewiń o 10 sekund wstecz / Przewiń film wstecz, bazując na obecnej prędkości odtwarzania\n  Large Fast Forward: Przewiń o 10 sekund do przodu / Przewiń film do przodu, bazując na obecnej prędkości odtwarzania\n  Stats: Pokaż statystyki filmu\n  End: Przeskocz na koniec filmu\n  Home: Przeskocz na początek filmu\n  Skip to Next Video: Odtwórz następny film z playlisty lub z rekomendowanych filmów\n  Skip to Previous Video: Odtwórz poprzedni film z playlisty lub z rekomendowanych filmów\nshortcutLabelSeparator: ｜\nCompact side navigation: Skompresuj boczną nawigację\nExpand side navigation: Rozwiń boczną nawigację\n"
  },
  {
    "path": "static/locales/pt-BR.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Arquivo'\nQuit: 'Sair'\nEdit: 'Editar'\nUndo: 'Desfazer'\nRedo: 'Refazer'\nCut: 'Recortar'\nCopy: 'Copiar'\nPaste: 'Colar'\nDelete: 'Excluir'\nSelect all: 'Selecionar tudo'\nToggle Developer Tools: 'Alternar ferramentas de desenvolvedor'\nActual size: 'Tamanho real'\nZoom in: 'Ampliar'\nZoom out: 'Reduzir'\nToggle fullscreen: 'Alternar tela cheia'\nWindow: 'Janela'\nMinimize: 'Minimizar'\nClose: 'Fechar'\nBack: 'Voltar'\nForward: 'Avançar'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vídeos'\n  Shorts: Shorts\n  Live: Ao vivo\n  Posts: Posts\n  Sort By: Ordenar por\n\n# Search Bar\n  Counts:\n    Video Count: 1 vídeo | {count} vídeos\n    Channel Count: 1 canal | {count} canais\n    Subscriber Count: 1 inscrito | {count} inscritos\n    View Count: 1 visualização | {count} visualizações\n    Watching Count: 1 assistindo | {count} assistindo\n    Like Count: 1 curtida | {count} curtidas\n    Comment Count: 1 comentário | {count} comentários\nSearch / Go to URL: 'Buscar ou digite um URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtros de busca'\n  Sort By:\n    Most Relevant: 'Mais relevantes'\n    Rating: 'Avaliação'\n    Upload Date: 'Data de envio'\n    View Count: 'Número de visualizações'\n  Time:\n    Time: 'Tempo'\n    Any Time: 'Qualquer momento'\n    Last Hour: 'Últimas horas'\n    Today: 'Hoje'\n    This Week: 'Esta semana'\n    This Month: 'Este mês'\n    This Year: 'Este ano'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Qualquer tipo'\n    Videos: 'Vídeos'\n    Channels: 'Canais'\n    #& Playlists\n    Movies: Filmes\n  Duration:\n    Duration: 'Duração'\n    All Durations: 'Todas as durações'\n    Short (< 4 minutes): 'Curto (menos de 4 minutos)'\n    Long (> 20 minutes): 'Longo (mais de 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Médio (4 a 20 minutos)\n  Search Results: 'Resultados da busca'\n  Fetching results. Please wait: 'Buscando resultados. Por favor, aguarde'\n  Fetch more results: 'Buscar mais resultados'\n# Sidebar\n  There are no more results for this search: Não há mais resultados para esta busca\n  Features:\n    HD: HD\n    Subtitles: Legendas\n    Live: Ao vivo\n    4K: 4K\n    360 Video: Vídeo em 360º\n    Location: Localização\n    HDR: HDR\n    VR180: VR180\n    Creative Commons: Creative Commons (licença)\n    Features: Destaques\n    3D: 3D\n  Clear Filters: Excluir filtros\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Inscrições'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Sua lista de inscrições está vazia no momento. Se quiser importar suas inscrições, acesse \"Configurações de dados\" e selecione \"Importar inscrições\" ou tente buscar um canal para inscrever-se.'\n  Load More Videos: Carregar mais vídeos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil tem um grande número de inscrições. Forçando RSS para evitar limitação de rede\n  Error Channels: Canais com erros\n  Disabled Automatic Fetching: Você desabilitou a busca automática de inscrições. Atualize as inscrições para vê-las aqui.\n  Empty Channels: Atualmente, os canais em que você está inscrito não possuem vídeos.\n  Subscriptions Tabs: Guias de inscrições\n  All Subscription Tabs Hidden: Todas as guias de inscrição estão ocultas. Para ver o conteúdo aqui, desoculte algumas guias na seção \"{subsection}\" em \"{settingsSection}\".\n  Load More Posts: Carregar mais postagens\n  Empty Posts: Atualmente, os canais em que você está inscrito não possuem postagens.\nTrending:\n  Trending: 'Em alta'\n  Trending Tabs: Guias em destaque\n  Gaming: Jogos\n  Sports: Esportes\nMost Popular: 'Mais populares'\nPlaylists: 'Playlists'\nUser Playlists:\n  Your Playlists: 'Suas playlists'\n  Search bar placeholder: Buscar playlists\n  Empty Search Message: Não há vídeos nesta playlist que correspondam à sua busca\n  You have no playlists. Click on the create new playlist button to create a new one.: Você não tem playlists. Clique no botão \"Criar nova playlist\" para criar uma.\n  This playlist currently has no videos.: Esta playlist não tem vídeos atualmente.\n  Create New Playlist: Criar nova playlist\n  Add to Playlist: Adicionar à playlist\n  Move Video Up: Mover vídeo para cima\n  Remove from Playlist: Remover da playlist\n  CreatePlaylistPrompt:\n    Create: Criar\n    New Playlist Name: Novo nome da playlist\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Já existe uma playlist com este nome. Escolha um nome diferente.\n      Playlist {playlistName} has been successfully created.: A playlist \"{playlistName}\" foi criada com sucesso.\n      There was an issue with creating the playlist.: Ocorreu um problema ao criar a playlist.\n  Add to Favorites: Adicionar a \"{playlistName}\"\n  Remove from Favorites: Remover de \"{playlistName}\"\n  Move Video Down: Mover vídeo para baixo\n  Playlist Name: Nome da playlist\n  Playlist Description: Descrição da playlist\n  Save Changes: Salvar alterações\n  Cancel: Cancelar\n  Edit Playlist Info: Editar informação da playlist\n  Copy Playlist: Copiar playlist\n  Enable Quick Bookmark With This Playlist: Habilitar \"Quick Bookmark\" para esta playlist\n  Delete Playlist: Excluir playlist\n  Are you sure you want to delete this playlist? This cannot be undone: Tem certeza de que deseja excluir esta playlist? Isto não pode ser desfeito.\n  Sort By:\n    NameDescending: Z-A\n    LatestCreatedFirst: Data de criação (mais recente)\n    EarliestCreatedFirst: Data de criação (mais antiga)\n    LatestUpdatedFirst: Data de atualização (mais recente)\n    LatestPlayedFirst: Data de reprodução (mais recente)\n    EarliestPlayedFirst: Data de reprodução (mais antiga)\n    EarliestUpdatedFirst: Data de atualização (mais antiga)\n    NameAscending: A-Z\n  SinglePlaylistView:\n    Toast:\n      This playlist is now used for quick bookmark: Esta playlist agora é usada como \"Quick Bookmark\"\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Esta playlist agora é usada como \"Quick Bookmark\" em vez de \"{oldPlaylistName}\". Clique aqui para desfazer\n      There was an issue with updating this playlist.: Ocorreu um problema ao atualizar esta playlist.\n      This video cannot be moved down.: Este vídeo não pode ser movido para baixo.\n      Reverted to use {oldPlaylistName} for quick bookmark: Habilitado para usar \"{oldPlaylistName}\" como \"Quick Bookmark\"\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Alguns vídeos da playlist ainda não foram carregados. Clique aqui para copiar mesmo assim.\n      Playlist name cannot be empty. Please input a name.: O nome da playlist não pode ficar vazio. Por favor insira um nome.\n      \"{videoCount} video(s) have been removed\": 1 vídeo foi removido | {videoCount} vídeos foram removidos\n      There were no videos to remove.: Não havia vídeos para remover.\n      This playlist is protected and cannot be removed.: Esta playlist está protegida e não pode ser removida.\n      Playlist {playlistName} has been deleted.: Playlist \"{playlistName}\" excluída.\n      This playlist does not exist: Esta playlist não existe\n      This video cannot be moved up.: Este vídeo não pode ser movido para cima.\n      There was a problem with removing this video: Houve um problema ao remover este vídeo\n      Playlist has been updated.: Playlist atualizada.\n      Video has been removed: Vídeo removido\n      This playlist is already being used for quick bookmark.: Esta playlist já está sendo usada como \"Quick Bookmark\".\n      This playlist has a video with a duration error: Esta playlist contém pelo menos um vídeo que não tem duração, ela será classificada como se sua duração fosse zero.\n      Video has been removed. Click here to undo.: O vídeo foi removido. Clique aqui para desfazer.\n    Search for Videos: Buscar vídeos\n  AddVideoPrompt:\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Vídeo(s) adicionado(s) a 1 playlist | Vídeo(s) adicionado(s) a {playlistCount} playlists\"\n      You haven't selected any playlist yet.: Você ainda não selecionou nenhuma playlist.\n    Select a playlist to add your N videos to: Selecione uma playlist para adicionar seu vídeo | Selecione uma playlist para adicionar seus {videoCount} vídeos\n    N playlists selected: '{playlistCount} selecionada(s)'\n    Search in Playlists: Buscar nas playlists\n    Save: Salvar\n    Added {count} Times: Já adicionado | Adicionado {count} vezes\n    Allow Adding Duplicate Video(s): Permitir adição de vídeos duplicados\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} vídeos serão adicionados'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} vídeos já adicionados'\n  Remove Watched Videos: Remove vídeos assistidos\n  Playlists with Matching Videos: Playlists com vídeos correspondentes\n  Quick Bookmark Enabled: Quick Bookmark habilitado\n  Cannot delete the quick bookmark target playlist.: Não é possível excluir a playlist de destino do \"Quick Bookmark\".\n  Remove Duplicate Videos: Remover vídeos duplicados\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Tem certeza de que deseja remover 1 vídeo duplicado desta playlist? Isso não pode ser desfeito. | Tem certeza de que deseja remover {playlistItemCount} vídeos duplicados desta playlist? Isso não pode ser desfeito.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Tem certeza de que deseja remover 1 vídeo assistido desta playlist? Isso não pode ser desfeito. | Tem certeza de que deseja remover {playlistItemCount} vídeos assistidos desta playlist? Isso não pode ser desfeito.\n  The playlist has been successfully exported: Playlist exportada com sucesso\n  Export Playlist: Exportar esta playlist\n  TotalTimePlaylist: 'Tempo total: {duration}'\n  Export list of URLs: Exportar lista de URLs\nHistory:\n  # On History Page\n  History: 'Histórico'\n  Watch History: 'Histórico de reprodução'\n  Your history list is currently empty.: 'Seu histórico está vazio no momento.'\n  Search bar placeholder: Buscar no histórico\n  Empty Search Message: Não há vídeos em seu histórico que correspondam à sua busca\n  Case Sensitive Search: Busca que diferencia maiúsculas de minúsculas\n  DateOldestHistory: Data de reprodução (mais antiga)\n  DateNewestHistory: Data de reprodução (mais recente)\nSettings:\n  # On Settings Page\n  Settings: 'Configurações'\n  General Settings:\n    General Settings: 'Geral'\n    Fallback to Non-Preferred Backend on Failure: 'Usar mecanismo de busca alternativo em caso de falha'\n    Enable Search Suggestions: 'Habilitar sugestões de busca'\n    Default Landing Page: 'Página inicial preferida'\n    Locale Preference: 'Idioma'\n    Preferred API Backend:\n      Preferred API Backend: 'API de processamento preferida'\n      Local API: 'API local'\n      Invidious API: 'API do Invidious'\n    Video View Type:\n      Video View Type: 'Tipo de visualização de vídeo'\n      Grid: 'Em grade'\n      List: 'Em lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferências de miniaturas'\n      Default: 'Normal'\n      Beginning: 'No começo'\n      Middle: 'No meio'\n      End: 'No fim'\n      Hidden: Escondido\n      Blur: Desfocar\n    Region for Trending: 'Região para conteúdos em alta'\n        #! List countries\n    Check for Updates: Buscar por atualizações\n    Check for Latest Blog Posts: Verificar se há novas postagens no blog\n    View all Invidious instance information: Ver todas as informações da instância Invidious\n    System Default: Definido pelo Sistema\n    No default instance has been set: Nenhuma instância padrão foi definida\n    The currently set default instance is {instance}: A instância padrão atualmente definida é {instance}\n    Current instance will be randomized on startup: A instância atual será aleatória na inicialização\n    Set Current Instance as Default: Definir instância atual como padrão\n    Clear Default Instance: Excluir instância padrão\n    Current Invidious Instance: Instância Invidious atual\n    External Link Handling:\n      No Action: Nenhuma ação\n      Ask Before Opening Link: Perguntar antes de abrir o link\n      Open Link: Abrir link\n      External Link Handling: Ação para links externos\n    Auto Load Next Page:\n      Label: Carregamento automático da próxima página\n      Tooltip: Carregar páginas e comentários adicionais automaticamente.\n    Open Deep Links In New Window: Abrir URLs enviados para o FreeTube em uma nova janela\n    Minimize to system tray: Minimizar para a bandeja do sistema\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Usar cor principal na barra superior'\n    Base Theme:\n      Base Theme: 'Tema base'\n      Black: 'Preto'\n      Dark: 'Escuro'\n      Light: 'Claro'\n      Dracula: 'Dracula'\n      System Default: Definido pelo Sistema\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Rosa Pastel\n      Hot Pink: Rosa Choque\n      Nordic: Nordico\n      Solarized Light: Claro Solarizado\n      Solarized Dark: Escuro Solarizado\n      Gruvbox Light: 'Gruvbox: Claro'\n      Gruvbox Dark: 'Gruvbox: Escuro'\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: 'Everforest: Escuro Sólido'\n      Everforest Dark Low: 'Everforest: Escuro Suave'\n      Everforest Dark Medium: 'Everforest: Escuro Médio'\n      Everforest Light Hard: 'Everforest: Claro Sólido'\n      Everforest Light Medium: 'Everforest: Claro Médio'\n      Everforest Light Low: 'Everforest: Claro Suave'\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Cor principal'\n      Red: 'Vermelho'\n      Pink: 'Rosa'\n      Purple: 'Roxo'\n      Deep Purple: 'Roxo escuro'\n      Indigo: 'Índigo'\n      Blue: 'Azul'\n      Light Blue: 'Azul claro'\n      Cyan: 'Ciano'\n      Teal: 'Azul-petróleo'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Limão'\n      Yellow: 'Amarelo'\n      Amber: 'Âmbar'\n      Orange: 'Laranja'\n      Deep Orange: 'Laranja escuro'\n      Dracula Cyan: 'Dracula: Ciano'\n      Dracula Green: 'Dracula: Verde'\n      Dracula Orange: 'Dracula: Laranja'\n      Dracula Pink: 'Dracula: Rosa'\n      Dracula Purple: 'Dracula: Roxo'\n      Dracula Red: 'Dracula: Vermelho'\n      Dracula Yellow: 'Dracula: Amarelo'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mocha: Água de Rosas'\n      Catppuccin Mocha Flamingo: 'Catppuccin Mocha: Flamingo'\n      Catppuccin Mocha Mauve: 'Catppuccin Mocha: Malva'\n      Catppuccin Mocha Pink: 'Catppuccin Mocha: Rosa'\n      Catppuccin Mocha Red: 'Catppuccin Mocha: Vermelho'\n      Catppuccin Mocha Maroon: 'Catppuccin Mocha: Marrom'\n      Catppuccin Mocha Blue: 'Catppuccin Mocha: Azul'\n      Catppuccin Mocha Peach: 'Catppuccin Mocha: Pêssego'\n      Catppuccin Mocha Green: 'Catppuccin Mocha: Verde'\n      Catppuccin Mocha Sapphire: 'Catppuccin Mocha: Safira'\n      Catppuccin Mocha Yellow: 'Catppuccin Mocha: Amarelo'\n      Catppuccin Mocha Sky: 'Catppuccin Mocha: Celeste'\n      Catppuccin Mocha Teal: 'Catppuccin Mocha: Azul-petróleo'\n      Catppuccin Mocha Lavender: 'Catppuccin Mocha: Lavanda'\n      Solarized Yellow: Amarelo Solarizado\n      Solarized Red: Vermelho Solarizado\n      Solarized Magenta: Magenta Solarizado\n      Solarized Violet: Violeta Solarizado\n      Solarized Blue: Azul Solarizado\n      Solarized Cyan: Ciano Solarizado\n      Solarized Green: Verde Solarizado\n      Solarized Orange: Laranja Solarizado\n      Gruvbox Dark Blue: 'Gruvbox: Azul Escuro'\n      Gruvbox Dark Purple: 'Gruvbox: Roxo Escuro'\n      Gruvbox Dark Aqua: 'Gruvbox: Aqua Escuro'\n      Gruvbox Light Red: 'Gruvbox: Vermelho Claro'\n      Gruvbox Light Blue: 'Gruvbox: Azul Claro'\n      Gruvbox Light Purple: 'Gruvbox: Roxo Claro'\n      Gruvbox Light Orange: 'Gruvbox: Laranja Claro'\n      Gruvbox Dark Green: 'Gruvbox: Verde Escuro'\n      Gruvbox Dark Yellow: 'Gruvbox: Amarelo Escuro'\n      Gruvbox Dark Orange: 'Gruvbox: Laranja Escuro'\n      Catppuccin Frappe Rosewater: 'Catppuccin Frappe: Água de Rosas'\n      Catppuccin Frappe Flamingo: 'Catppuccin Frappe: Flamingo'\n      Catppuccin Frappe Mauve: 'Catppuccin Frappe: Malva'\n      Catppuccin Frappe Red: 'Catppuccin Frappe: Vermelho'\n      Catppuccin Frappe Maroon: 'Catppuccin Frappe: Marrom'\n      Catppuccin Frappe Peach: 'Catppuccin Frappe: Pêssego'\n      Catppuccin Frappe Yellow: 'Catppuccin Frappe: Amarelo'\n      Catppuccin Frappe Green: 'Catppuccin Frappe: Verde'\n      Catppuccin Frappe Sky: 'Catppuccin Frappe: Celeste'\n      Catppuccin Frappe Sapphire: 'Catppuccin Frappe: Safira'\n      Catppuccin Frappe Blue: 'Catppuccin Frappe: Azul'\n      Catppuccin Frappe Lavender: 'Catppuccin Frappe: Lavanda'\n      Catppuccin Frappe Teal: 'Catppuccin Frappe: Azul-petróleo'\n      Catppuccin Frappe Pink: 'Catppuccin Frappe: Rosa'\n      Everforest Dark Red: 'Everforest: Vermelho Escuro'\n      Everforest Dark Orange: 'Everforest: Laranja Escuro'\n      Everforest Dark Yellow: 'Everforest: Amarelo Escuro'\n      Everforest Dark Blue: 'Everforest: Azul Escuro'\n      Everforest Dark Purple: 'Everforest: Roxo Escuro'\n      Everforest Light Red: 'Everforest: Vermelho Claro'\n      Everforest Light Orange: 'Everforest: Laranja Claro'\n      Everforest Light Yellow: 'Everforest: Amarelo Claro'\n      Everforest Light Blue: 'Everforest: Azul Claro'\n      Everforest Light Purple: 'Everforest: Roxo Claro'\n      Everforest Light Aqua: 'Everforest: Aqua Claro'\n      Everforest Dark Green: 'Everforest: Verde Escuro'\n      Everforest Dark Aqua: 'Everforest: Aqua Escuro'\n      Everforest Light Green: 'Everforest: Verde Claro'\n      Catppuccin Latte Mauve: 'Catppuccin Latte: Malva'\n      Catppuccin Latte Red: 'Catppuccin Latte: Vermelho'\n    Secondary Color Theme: 'Cor secundária'\n        #* Main Color Theme\n    UI Scale: Escala da Interface de Usuário\n    Disable Smooth Scrolling: Desabilitar rolagem suave\n    Expand Side Bar by Default: Expandir barra lateral por padrão\n    Hide Side Bar Labels: Ocultar título na barra lateral\n    Hide FreeTube Header Logo: Ocultar o logotipo \"FreeTube\" na barra superior\n  Player Settings:\n    Player Settings: 'Reprodução'\n    Play Next Video: 'Reprodução automática de vídeos recomendados'\n    Turn on Subtitles by Default: 'Habilitar legendas por padrão'\n    Autoplay Videos: 'Iniciar reprodução de vídeos automaticamente'\n    Proxy Videos Through Invidious: 'Usar Invidious como proxy'\n    Autoplay Playlists: 'Reprodução automática de vídeos da playlist'\n    Enable Theatre Mode by Default: 'Habilitar \"Modo Teatro\" por padrão'\n    Default Volume: 'Volume'\n    Default Playback Rate: 'Velocidade de reprodução'\n    Default Video Format:\n      Default Video Format: 'Formato de vídeo'\n      Dash Formats: 'Formatos DASH'\n      Legacy Formats: 'Formatos antigos'\n      Audio Formats: 'Formato de áudio'\n    Default Quality:\n      Default Quality: 'Qualidade'\n      Auto: 'Auto'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Mostrar contagem regressiva para reprodução automática\n    Display Play Button In Video Player: Mostrar botão \"Pausar/Reproduzir\"\n    Scroll Volume Over Video Player: Alterar o volume com o botão de rolagem do mouse com o cursor sobre a reprodução\n    Fast-Forward / Rewind Interval: Intervalo para avançar/retroceder rapidamente\n    Scroll Playback Rate Over Video Player: Alterar a taxa de velocidade com o botão de rolagem do mouse com o cursor sobre a reprodução\n    Max Video Playback Rate: Taxa máxima de reprodução de vídeo\n    Video Playback Rate Interval: Intervalo da taxa de reprodução de vídeo\n    Screenshot:\n      File Name Label: Padrão para nome de arquivo\n      Enable: Habilitar captura de tela\n      Ask Path: Perguntar onde salvar os arquivos\n      Folder Label: Pasta de capturas de tela\n      Folder Button: Selecionar pasta\n      Error:\n        Empty File Name: Nome do arquivo vazio\n        Forbidden Characters: Caracteres proibidos\n      Format Label: Formato da captura de tela\n      Quality Label: Qualidade da captura de tela\n      File Name Tooltip: 'Você pode usar estas variáveis: %Y - ano com 4 dígitos, %M - mês com 2 dígitos, %D - dia com 2 dígitos, %H - hora com 2 dígitos, %N - minuto com 2 dígitos, %S - segundos com 2 dígitos, %T - milissegundos com 3 dígitos, %s - segundos do vídeo, %t - milissegundos do vídeo com 3 dígitos, %i - id do vídeo.'\n    Enter Fullscreen on Display Rotate: Entrar em tela cheia ao girar o dispositivo para o modo paisagem\n    Skip by Scrolling Over Video Player: Avançar ou retroceder com o botão de rolagem do mouse com o cursor sobre a reprodução\n    Autoplay Interruption Timer: Mostrar temporizador de interrupções para reprodução automática\n    Default Viewing Mode:\n      Theater: Teatro\n      Default Viewing Mode: Modo de visualização\n      Full Screen: Tela cheia\n      Picture in Picture: Picture in Picture (PiP)\n      External Player: Player externo ({externalPlayerName})\n  Subscription Settings:\n    Subscription Settings: 'Inscrições'\n    Fetch Feeds from RSS: Buscar Informações através de RSS\n    Fetch Automatically: Buscar feed automaticamente\n    Confirm Before Unsubscribing: Pedir para confirmar antes de cancelar a inscrição\n\n    'Limit the number of videos displayed for each channel': Limitar o número de vídeos exibidos para cada canal\n    To: Para\n  Privacy Settings:\n    Watch history has been cleared: O histórico de reprodução foi excluído\n    Are you sure you want to remove your entire watch history?: Tem certeza de que deseja remover todo o seu histórico de reprodução?\n    Remove Watch History: Remover histórico de reprodução\n    Search cache has been cleared: Cache de buscas foi apagado\n    Are you sure you want to clear out your search cache?: Tem certeza de que deseja limpar o cache de buscas?\n    Clear Search Cache: Limpar cache de buscas\n    Save Watched Progress: Habilitar histórico de reprodução\n    Remember History: Ativar histórico de reprodução\n    Privacy Settings: Privacidade\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Tem certeza de que deseja remover todas as inscrições e perfis? Isto não pode ser desfeito.\n    Remove All Subscriptions / Profiles: Remover todas as inscrições ou perfis\n    Save Watched Videos With Last Viewed Playlist: Salvar vídeos assistidos com a última playlist visualizada\n    All playlists have been removed: Todas as playlists foram removidas\n    Are you sure you want to remove all your playlists?: Tem certeza de que deseja remover todas as suas playlists?\n    Remove All Playlists: Remover todas as playlists\n    Remember Search History: Ativar histórico de buscas\n    Clear Search History and Cache: Excluir histórico de busca e o cache\n    Search history and cache have been cleared: O histórico de busca e o cache foram excluídos\n    Are you sure you want to clear out your search history and cache?: Tem certeza de que deseja excluir o histórico de busca e o cache?\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Nunca\n        Semi-auto: Semiautomático\n        Auto: Auto\n      Tooltip: Auto = Salvar em cada saída da página de vídeo, quando o vídeo termina e ocorre um erro (por exemplo, taxa limitada e sessão de reprodução expirada). Semiautomático = O mesmo que \"Auto\", exceto na saída da página de vídeo e pode salvar o progresso manualmente por meio de um botão chamado \"Salvar progresso de reprodução\", localizado abaixo do player de vídeo.\n  Data Settings:\n    Subscriptions have been successfully exported: As inscrições foram exportadas com sucesso\n    Invalid history file: Arquivo de histórico inválido\n    All subscriptions have been successfully imported: Todas as inscrições foram importadas com sucesso\n    Data Settings: Dados\n    Export History: Exportar histórico\n    Import History: Importar histórico\n    Export NewPipe: Exportar NewPipe\n    Export YouTube: Exportar YouTube\n    Export FreeTube: Exportar FreeTube\n    Export Subscriptions: Exportar inscrições\n    Import Subscriptions: Importar inscrições\n    Select Export Type: Escolha o tipo de exportação\n    How do I import my subscriptions?: Como faço para importar minhas inscrições?\n    Unknown data key: Chave de dados desconhecida\n    Unable to write file: O arquivo não pôde ser salvo\n    Unable to read file: O arquivo não pôde ser lido\n    All watched history has been successfully exported: O histórico de reprodução foi exportado com sucesso\n    All watched history has been successfully imported: O histórico de reprodução foi importado com sucesso\n    History object has insufficient data, skipping item: O histórico tem dados insuficientes, ignorando item\n    Invalid subscriptions file: Arquivo de inscrições inválido\n    All subscriptions and profiles have been successfully imported: Todas as inscrições e perfis foram importados com sucesso\n    Profile object has insufficient data, skipping item: O perfil tem dados insuficientes, ignorando o item\n    Manage Subscriptions: Gerenciar inscrições\n    Import Playlists: Importar playlists\n    Export Playlists: Exportar playlists\n    Playlist insufficient data: Dados insuficientes para a playlist \"{playlist}\", ignorando item\n    All playlists has been successfully exported: Todas as playlists foram exportadas com sucesso\n    All playlists has been successfully imported: Todas as playlists foram importadas com sucesso\n    Subscription File: Arquivo de inscrições\n    History File: Arquivo de histórico\n    Playlist File: Arquivo de playlist\n    Export Playlists For Older FreeTube Versions:\n      Label: Exportar playlists para versões mais antigas do FreeTube\n      Tooltip: \"Esta opção exporta vídeos de todas as playlists para uma playlist chamada \\\"Favoritos\\\".\\nComo exportar e importar vídeos em playlists para uma versão mais antiga do FreeTube:\\n1. Exporte suas playlists com esta opção habilitada.\\n2. Exclua todas as suas playlists existentes usando a opção \\\"Remover todas as playlists\\\" em \\\"Configurações de privacidade\\\".\\n3. Inicie a versão mais antiga do FreeTube e importe as playlists exportadas\"\n    Search history file: Arquivo de histórico de buscas\n    Search history: Histórico de buscas\n    Import search history: Importar histórico de buscas\n    Export search history: Exportar histórico de buscas\n    All search history has been successfully imported: Todo o histórico de buscas foi importado com sucesso\n    All search history has been successfully exported: Todo o histórico de buscas foi exportado com sucesso\n  Distraction Free Settings:\n    Hide Live Chat: Ocultar chat ao vivo\n    Hide Popular Videos: Ocultar vídeos populares\n    Hide Trending Videos: Ocultar vídeos em alta\n    Hide Recommended Videos: Ocultar vídeos recomendados\n    Hide Comment Likes: Ocultar \"curtidas\" de comentários\n    Distraction Free Settings: Modo sem distração\n    Hide Channel Subscribers: Ocultar número de inscritos\n    Hide Video Likes And Dislikes: Ocultar \"curtidas\" em vídeo\n    Hide Video Views: Ocultar visualizações do vídeo\n    Hide Active Subscriptions: Ocultar inscrições ativas\n    Hide Playlists: Ocultar playlist\n    Hide Video Description: Ocultar descrição do vídeo\n    Hide Sharing Actions: Ocultar ações de compartilhamento\n    Hide Videos on Watch: 'Ocultar vídeos após assisti-los'\n    Hide Comments: Ocultar comentários\n    Hide Live Streams: Ocultar transmissões ao vivo\n    Hide Chapters: Ocultar capítulos\n    Hide Upcoming Premieres: Ocultar próximas estréias\n    Hide Channels Placeholder: ID do canal\n    Display Titles Without Excessive Capitalisation: Mostrar títulos sem capitalização excessiva nem pontuação\n    Hide Channels: Ocultar vídeos de canais\n    Sections:\n      Side Bar: Barra lateral\n      Channel Page: Página do canal\n      Watch Page: Página de reprodução\n      General: Geral\n      Subscriptions Page: Página de inscrições\n    Hide Featured Channels: Ocultar canais em destaque\n    Hide Channel Playlists: Ocultar a guia \"Playlists\" do canal\n    Hide Channel Shorts: Ocultar a guia \"Shorts\" do canal\n    Hide Channel Podcasts: Ocultar a guia \"Podcasts\" do canal\n    Hide Channel Releases: Ocultar a guia \"Lancamentos\" do canal\n    Hide Subscriptions Videos: Ocultar vídeos de suas inscrições\n    Hide Subscriptions Shorts: Ocultar \"Shorts\" de suas inscrições\n    Hide Subscriptions Live: Ocultar transmissões ao vivo de suas inscrições\n    Hide Profile Pictures in Comments: Ocultar foto de perfis nos comentários\n    Hide Channels Invalid: ID do canal inválido\n    Hide Channels Disabled Message: Alguns canais foram bloqueados por ID e não foram processados. A função está bloqueada enquanto esses IDs estão sendo atualizados\n    Hide Channels Already Exists: ID do canal já existe\n    Hide Channels API Error: Erro ao recuperar o usuário com o ID fornecido. Por favor, verifique novamente se o ID está correto.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Palavra, trecho de uma palavra ou frase\n    Hide Videos, Playlists and Channels Containing Text: Ocultar vídeos e playlists que contenham texto\n    Hide Channel Home: Ocultar a guia \"Início\" do canal\n    Show Added Items: Mostrar itens adicionados\n    Hide Channel Courses: Ocultar a guia “Cursos” do canal\n    Hide Subscriptions Posts: Ocultar inscrições na guia de postagens\n    Hide Channel Posts: Ocultar a guia \"Posts\" do canal\n  The app needs to restart for changes to take effect. Restart and apply change?: O aplicativo necessita reiniciar para as mudanças fazerem efeito. Reiniciar e aplicar mudança?\n  Proxy Settings:\n    Country: País\n    Ip: IP\n    Your Info: Suas Informações\n    Test Proxy: Testar Proxy\n    Clicking on Test Proxy will send a request to: Clicando em \"Testar Proxy\", será enviado uma solicitação para\n    Proxy Port Number: Porta do Proxy\n    Proxy Host: Host do Proxy\n    Proxy Protocol: Protocolo do Proxy\n    Enable Tor / Proxy: Habilitar Tor/Proxy\n    Proxy Settings: Proxy\n    Error getting network information. Is your proxy configured properly?: Erro ao obter informações da rede. Seu proxy está configurado corretamente?\n    City: Cidade\n    Region: Região\n    Proxy Warning: FreeTube não tem um proxy integrado, mas pode se conectar a um proxy externo, como um proxy em execução no seu computador, como o Tor, ou um proxy externo, como um proxy SOCKS5 fornecido por algumas VPNs. Se estiver habilitado, certifique-se de que seu proxy/Tor esteja configurado corretamente, ou o FreeTube não conseguirá obter nenhum dado.\n    Proxy Username: Nome de usuário do Proxy\n    Proxy Password: Senha do Proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar quando vídeos publicitários for ignorado\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL da API SponsorBlock (o padrão é https://sponsor.ajay.app)\n    Enable SponsorBlock: Habilitar SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Show In Seek Bar: Mostrar na barra de busca\n      Prompt To Skip: Solicitar para pular\n      Do Nothing: Não fazer nada\n      Auto Skip: Pular automaticamente\n      Skip Option: Opção para pular\n    Category Color: Cor da categoria\n    UseDeArrowTitles: Usar títulos de vídeo no estilo DeArrow\n    UseDeArrowThumbnails: Usar miniaturas no estilo DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL da API para gerar miniaturas no estilo DeArrow (o padrão é https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Argumentos do player externo personalizados\n    External Player: Player externo\n    Ignore Unsupported Action Warnings: Ignorar avisos de ação não suportada\n    External Player Settings: Player externo\n    Custom External Player Executable: Executável do player externo personalizado\n    Players:\n      None:\n        Name: Nenhum\n    Ignore Default Arguments: Ignorar argumentos padrão\n  Parental Control Settings:\n    Show Family Friendly Only: Ocultar conteúdo inadequado para menores de idade\n    Hide Search Bar: Ocultar barra de busca\n    Parental Control Settings: Controle dos Pais\n    Hide Unsubscribe Button: Ocultar botão \"Cancelar inscrição\"\n    Hide Uploader on Watch page: Ocultar o nome do autor na página de reprodução\n  Experimental Settings:\n    Experimental Settings: Experimental\n    Warning: Essas configurações são experimentais, elas podem causar travamentos enquanto habilitadas. Fazer backups é altamente recomendado. Use por sua conta e risco!\n    Replace HTTP Cache: Repor cache HTTP\n  Password Settings:\n    Password Settings: Senha\n    Set Password: Definir senha\n    Remove Password: Remover senha\n    Set Password To Prevent Access: Defina uma senha para impedir o acesso às configurações\n  Password Dialog:\n    Password: Senha\n    Enter Password To Unlock: Digite a senha para desbloquear as configurações\n  Sort Settings Sections (A-Z): Classificar seções de configurações (A-Z)\n  Return to Settings Menu: Retornar ao menu de configurações\nAbout:\n  #On About page\n  About: 'Sobre'\n  #& About\n#On Channel Page\n  GitHub issues: Publicações de relatórios (GitHub)\n  Report a problem: Informar um problema\n  FAQ: Perguntas frequentes\n  FreeTube Wiki: Wiki do FreeTube\n  Help: Ajuda\n  GitHub releases: Lançamentos do GitHub\n  Downloads / Changelog: Downloads / Modificações\n  Source code: Código-fonte\n  Beta: Beta\n  Donate: Doações\n  these people and projects: estas pessoas e projetos\n  Credits: Créditos\n  Translate: Traduzir\n  room rules: regras da sala\n  Chat on Matrix: Chat no Matrix\n  Mastodon: Mastodon\n  Email: E-mail\n  Blog: Blog\n  Website: Site\n  Please check for duplicates before posting: Por favor verifique se este problema já foi informado\n  Discussions: Discussões\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licenciado sob a {licenseLink}\n  Please read the {roomRulesLink}: Leia as {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: O FreeTube é possível graças a {creditsPageLink}\nChannel:\n  Subscribe: 'Inscrever-se'\n  Unsubscribe: 'Remover inscrição'\n  Search Channel: 'Buscar no canal'\n  Your search results have returned 0 results: 'Nenhum vídeo encontrado para a busca'\n  Videos:\n    Videos: 'Vídeos'\n    This channel does not currently have any videos: 'Este canal não possui vídeos no momento'\n    Sort Types:\n      Newest: 'Novos'\n      Oldest: 'Antigos'\n      Most Popular: 'Mais populares'\n  Playlists:\n    Playlists: 'Playlists'\n    This channel does not currently have any playlists: 'Este canal não possui nenhuma playlist no momento'\n    Sort Types:\n      Last Video Added: 'Último vídeo adicionado'\n      Newest: 'Novos'\n      Oldest: 'Antigos'\n  About:\n    About: 'Sobre'\n    Channel Description: 'Descrição do canal'\n    Featured Channels: 'Canais em destaque'\n    Tags:\n      Search for: Procurar por “{tag}”\n      Tags: Tags\n    Details: Detalhes\n    Location: Localização\n    Joined: Inscrito\n  Added channel to your subscriptions: Canal adicionado às suas inscrições\n  Removed subscription from {count} other channel(s): Inscrição removida de outros {count} canais\n  Channel has been removed from your subscriptions: O canal foi removido de suas inscrições\n  This channel does not exist: Este canal não existe\n  This channel does not allow searching: Este canal não permite buscas\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Este canal tem restrição de idade e atualmente não pode ser visualizado no FreeTube.\n  Posts:\n    This channel currently does not have any posts: Este canal atualmente não tem nenhuma postagem\n    votes: '{votes} voto(s)'\n    Reveal Answers: Mostrar respostas\n    Hide Answers: Ocultar respostas\n    Video hidden by FreeTube: Vídeo escondido pelo FreeTube\n    View Full Post: Ver postagem completa\n    Viewing Posts Only Supported By Invidious: A visualização de postagens só é compatível com o Invidious. Acesse a guia da comunidade de um canal para visualizar o conteúdo sem o Invidious.\n  Channel Tabs: Guias do canal\n  Live:\n    Live: Ao vivo\n    This channel does not currently have any live streams: Este canal não tem nenhuma transmissão ao vivo no momento\n  Shorts:\n    This channel does not currently have any shorts: Este canal não tem nenhum \"Shorts\" no momento\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Este canal não possui podcasts no momento\n  Releases:\n    Releases: Lançamentos\n    This channel does not currently have any releases: Este canal não tem nenhum lançamento no momento\n  Home:\n    Home: Início\n    View Playlist: Ver playlist\n  Courses:\n    This channel does not currently have any courses: Este canal não tem nenhum curso no momento\n    Courses: Cursos\nVideo:\n  Mark As Watched: 'Marcar como assistido'\n  Remove From History: 'Remover do histórico'\n  Video has been marked as watched: 'O vídeo foi marcado como assistido'\n  Video has been removed from your history: 'Vídeo removido do seu histórico'\n  Open in YouTube: 'Abrir no YouTube'\n  Copy YouTube Link: 'Copiar link do YouTube'\n  Open YouTube Embedded Player: 'Abrir player incorporado do YouTube'\n  Copy YouTube Embedded Player Link: 'Copiar link incorporado do YouTube'\n  Open in Invidious: 'Abrir no Invidious'\n  Copy Invidious Link: 'Copiar link do Invidious'\n  Views: 'Visualizações'\n  Watched: 'Assistido'\n  # As in a Live Video\n  Live: 'Ao vivo'\n  Live Now: 'Ao vivo agora'\n  Live Chat: 'Chat ao vivo'\n  Enable Live Chat: 'Habilitar chat ao vivo'\n  Live Chat is currently not supported in this build.: 'Chat ao vivo não é suportado nessa versão.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'O chat ao vivo está habilitado. As mensagens aparecerão aqui depois de enviadas.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'O chat ao vivo não é suportado pela API do Invidious. Uma conexão com o YouTube é necessária.'\n  Published:\n    In less than a minute: Em menos de um minuto\n  Published on: 'Publicado em'\n#& Videos\n  Started streaming on: Transmissão iniciada em\n  Streamed on: Transmitido em\n  Starting soon, please refresh the page to check again: Vai começar em breve, atualize a página para verificar novamente\n  Autoplay: Reprodução automática\n  Previous: Anterior\n  Next: Próximo\n  Reverse Playlist: Inverter ordem da playlist\n  Shuffle Playlist: Playlist aleatória\n  Loop Playlist: Repetir playlist\n  Copy Invidious Channel Link: Copiar link deste canal do Invidious\n  Open Channel in Invidious: Abrir canal no Invidious\n  Copy YouTube Channel Link: Copiar link deste canal do YouTube\n  Open Channel in YouTube: Abrir canal no YouTube\n  Video has been removed from your saved list: O vídeo foi removido da sua lista de vídeos salvos\n  Video has been saved: O vídeo foi salvo\n  Save Video: Salvar vídeo\n  Sponsor Block category:\n    music offtopic: Música fora do contexto\n    interaction: Interação\n    self-promotion: Auto-promoção\n    outro: Cartões finais e créditos\n    intro: Introdução\n    sponsor: Patrocinador\n    filler: Preenchimento\n    recap: Recapitulação\n  External Player:\n    Unsupported Actions:\n      shuffling playlists: Playlists aleatórias\n      opening specific video in a playlist (falling back to opening the video): abrir um vídeo específico em uma playlist (volta ao começo do vídeo)\n      reversing playlists: invertendo playlists\n      opening playlists: abrindo playlists\n      starting video at offset: iniciando vídeo num tempo específico\n      setting a playback rate: alterando a velocidade de reprodução\n      looping playlists: Repetição das playlists\n    UnsupportedActionTemplate: '{externalPlayer} não suporta: {action}'\n    playlist: playlist\n    OpeningTemplate: Abrindo {videoOrPlaylist} em {externalPlayer}...\n    OpenInTemplate: Abrir em {externalPlayer}\n    video: vídeo\n  Premieres: Estreia\n  Scroll to Bottom: Ir para o final\n  Show Super Chat Comment: Mostrar comentários de Super Chat\n  Upcoming: Em breve\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': O chat ao vivo não está disponível para esta transmissão. Pode ter sido desabilitado pelo autor.\n  Unhide Channel: Mostrar canal\n  Hide Channel: Ocultar canal\n  More Options: Mais opções\n  Player:\n    Audio Tracks: Faixas de áudio\n    Theatre Mode: Modo Teatro\n    Exit Theatre Mode: Sair do modo Teatro\n    Take Screenshot: Capturar tela\n    Hide Stats: Ocultar estatísticas\n    Stats:\n      Stats: Estatísticas\n      Video ID: 'ID do vídeo: {videoId}'\n      Media Formats: 'Formatos de mídia: {formats}'\n      Resolution: 'Resolução: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensões do player: {width}x{height}'\n      Bitrate: 'Taxa de bits: {bitrate} kbps'\n      Volume: 'Volume: {volumePercentage}%'\n      Dropped Frames / Total Frames: 'Quadros descartados: {droppedFrames} / Total de quadros: {totalFrames}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'\n      Buffered: 'Transferência: {bufferedPercentage}%'\n      Bandwidth: 'Transmissão de dados: {bandwidth} kbps'\n      CodecsVideoAudio: 'Codecs: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n    You appear to be offline: Parece que você está offline.\n    Playback will resume automatically when your connection comes back: A reprodução será retomada automaticamente quando a conexão for restabelecida.\n    Skipped segment: Segmento {segmentCategory} ignorado\n    Full Window: Preencher janela\n    TranslatedCaptionTemplate: '{language} (traduzido do \"{originalLanguage}\")'\n    Show Stats: Mostrar estatísticas\n    Exit Full Window: Sair do preenchimento de janela\n    Autoplay is off: A reprodução automática está desativada\n    Autoplay is on: A reprodução automática está ativada\n  IP block: O YouTube bloqueou seu endereço IP para assistir a vídeos. Tente mudar para uma VPN ou proxy diferente.\n  Unlisted: Não listado\n  MembersOnly: Vídeos exclusivos para membros não podem ser assistidos com o FreeTube, pois exigem login do Google e assinatura paga do canal do remetente.\n  AgeRestricted: Vídeos com restrição de idade não podem ser assistidos com o FreeTube, pois exigem login do Google e uso de uma conta do YouTube com verificação de idade.\n  DeArrow:\n    Show Original Details: Mostrar detalhes originais\n    Show Modified Details: Mostrar detalhes modificados\n  DRMProtected: Os vídeos protegidos por DRM não podem ser reproduzidos no FreeTube, pois exigem componentes proprietários e de código fechado. Se quiser assistir a esse vídeo, acesse o site oficial do YouTube em um navegador da Web habilitado para DRM.\n#& Playlists\n  Watched Progress Saved: Progresso de reprodução salvo\n  Save Watched Progress: Salvar progresso de reprodução\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Tempo restante para anúncios antes da reprodução: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Tempo restante de espera do SABR: {remindingTimeSeconds}s'\n  Popout Live Chat: Chat flutuante\nPlaylist:\n  #& About\n  View Full Playlist: 'Mostrar playlist completa'\n  Last Updated On: 'Atualizado em'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlist\n  Sort By:\n    AuthorAscending: Autor (A-Z)\n    VideoTitleAscending: Título (A-Z)\n    Custom: Personalizado\n    DateAddedNewest: Data adicionada (mais recente)\n    DateAddedOldest: Data adicionada (mais antiga)\n    AuthorDescending: Autor (Z-A)\n    VideoTitleDescending: Título (Z-A)\n    VideoDurationAscending: Duração (a mais curta)\n    VideoDurationDescending: Duração (a mais longa)\n    PublishedOldest: Data de publicação (mais antiga)\n    PublishedNewest: Data de publicação (mais recente)\nChange Format:\n  Change Media Formats: 'Mudar formato do vídeo'\n  Use Dash Formats: 'Usar formatos DASH'\n  Use Legacy Formats: 'Usar formatos antigos'\n  Use Audio Formats: 'Usar formato de áudio'\n  Audio formats are not available for this video: Formatos de áudio não disponíveis para este vídeo\n  Dash formats are not available for this video: Formatos DASH não disponíveis para este vídeo\n  Legacy formats are not available for this video: Os formatos antigos não estão disponíveis para este vídeo\nShare:\n  Share Video: 'Compartilhar vídeo'\n  Share Playlist: 'Compartilhar playlist'\n  Copy Link: 'Copiar link'\n  Open Link: 'Abrir link'\n  Copy Embed: 'Copiar link incorporado'\n  Open Embed: 'Abrir link incorporado'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious copiado para a área de transferência'\n  Invidious Embed URL copied to clipboard: 'URL incorporado do Invidious copiado para a área de transferência'\n  YouTube URL copied to clipboard: 'URL do YouTube copiado para a área de transferência'\n  YouTube Embed URL copied to clipboard: 'URL incorporado do YouTube copiado para a área de transferência'\n  YouTube Channel URL copied to clipboard: URL do canal do Youtube copiado para a área de transferência\n  Invidious Channel URL copied to clipboard: URL do canal Invidious copiado para a área de transferência\n  Include Timestamp: Incluir momento atual\n  Share Channel: Compartilhar canal\n  Share Post: Compartilhar postagem\nMini Player: 'Mini Player'\nComments:\n  Comments: 'Comentários'\n  Click to View Comments: 'Mostrar comentários'\n  Getting comment replies, please wait: 'Buscando respostas, por favor, aguarde'\n  Hide Comments: 'Ocultar comentários'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Não há comentários disponíveis neste vídeo'\n  Load More Comments: 'Buscar mais comentários'\n  Newest first: Mais recentes primeiro\n  Top comments: Melhores comentários\n  There are no more comments for this video: Não há mais comentários para este vídeo\n  Show More Replies: Mostrar mais respostas\n  Pinned by: Fixado por\n  Member: Membro\n  Hearted: Recebeu um coração\n  View {replyCount} replies: Mostrar 1 resposta | Mostrar {replyCount} respostas\n  Subscribed: Inscrito\n  There are no comments available for this post: Não há comentários disponíveis para esta postagem\n  Hide {replyCount} replies: Ocultar 1 resposta | Ocultar {replyCount} respostas\n  View 1 reply from {channelName}: Mostrar 1 resposta de {channelName}\n  View {replyCount} replies from {channelName} and others: Mostrar {replyCount} respostas de {channelName} e outros\nUp Next: 'Próximo'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Erro na API local (clique para copiar)'\nInvidious API Error (Click to copy): 'Erro na API Invidious (clique para copiar)'\nFalling back to Invidious API: 'Ocorreu um erro e a API Invidious será utilizada'\nFalling back to Local API: 'Ocorreu um erro e a API local será utilizada'\nLoop is now disabled: 'Modo de repetição desabilitado'\nLoop is now enabled: 'Modo de repetição habilitado'\nShuffle is now disabled: 'Reprodução aleatória desabilitado'\nShuffle is now enabled: 'Reprodução aleatória habilitado'\nPlaying Next Video: 'A reproduzir o próximo vídeo'\nPlaying Previous Video: 'A reproduzir o vídeo anterior'\nCanceled next video autoplay: 'Reprodução automática cancelada'\n'The playlist has ended. Enable loop to continue playing': 'A playlist acabou. Habilite o modo de repetição para continuar reproduzindo'\n\nYes: 'Sim'\nNo: 'Não'\nLocale Name: Português (Brasil)\nProfile:\n  Delete Profile: Excluir perfil\n  Update Profile: Atualizar perfil\n  Profile Preview: Pré-visualização do perfil\n  Color Picker: Escolha uma cor\n  Create New Profile: Criar novo perfil\n  All Channels: Todos os canais\n  All subscriptions will also be deleted.: Todas as inscrições serão também excluídas.\n  Are you sure you want to delete this profile?: Tem certeza de que quer excluir este perfil?\n  Make Default Profile: Tornar perfil padrão\n  Create Profile: Criar perfil\n  Custom Color: Cor personalizada\n  Edit Profile: Editar perfil\n  Profile Manager: Gerenciador de perfis\n  Profile Select: Escolha um perfil\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Tem certeza de que deseja excluir os canais selecionados? Isso não excluirá o canal de nenhum outro perfil.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Este é o seu perfil principal. Tem certeza de que quer excluir os canais selecionados? Os mesmos vão ser excluídos em qualquer perfil em que se encontrem.\n  No channel(s) have been selected: Nenhum canal foi selecionado\n  Add Selected To Profile: Adicionar selecionado ao perfil\n  Delete Selected: Excluir selecionados\n  Select None: Desfazer seleção\n  Select All: Selecionar todos\n  '{number} selected': '{number} selecionado(s)'\n  Other Channels: Outros canais\n  Subscription List: Lista de inscrições\n  '{profile} is now the active profile': '{profile} é agora o perfil ativo'\n  Your default profile has been changed to your primary profile: Seu perfil padrão foi alterado para seu perfil principal\n  Removed {profile} from your profiles: '{profile} foi removido dos seus perfis'\n  Your default profile has been set to {profile}: Seu perfil padrão foi definido como {profile}\n  Profile has been updated: Perfil atualizado\n  Profile has been created: Perfil criado\n  Your profile name cannot be empty: O nome do seu perfil não pode ficar vazio\n  Profile Filter: Filtrar por perfil\n  Profile Settings: Perfil\n  Toggle Profile List: Alternar lista de perfis\n  Profile Name: Nome do perfil\n  Edit Profile Name: Editar nome do perfil\n  Create Profile Name: Criar nome de perfil\n  Open Profile Dropdown: Abrir menu de perfis\n  Close Profile Dropdown: Fechar menu de perfis\nVersion {versionNumber} is now available!  Click for more details: A versão {versionNumber} já está disponível! Clique para mais detalhes\nA new blog is now available, {blogTitle}. Click to view more: 'Um novo post do blog está disponível: {blogTitle}. Clique para ver mais'\nDownload From Site: Baixar do site\nThe playlist has been reversed: A playlist foi invertida\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Este vídeo não está disponível devido à falta de formatos. Isto pode acontecer devido à indisponibilidade do país.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Quando habilitado, o FreeTube usará RSS em vez de seu método padrão para obter o feed de sua inscrição. O RSS é mais rápido e evita bloqueio de IP, mas não fornece certas informações como duração do vídeo, status ao vivo ou postagens\n    Fetch Automatically: Quando habilitado, o FreeTube buscará automaticamente seu feed de inscrições na inicialização e quando uma nova janela for aberta.\n  Player Settings:\n    Default Video Format: Define os formatos usados quando um vídeo é reproduzido. Formatos DASH podem reproduzir qualidades mais altas. Os formatos antigos são limitados a um máximo de 360p, mas usam menos largura de banda. Formatos de áudio são para transmissões sem vídeo.\n    Proxy Videos Through Invidious: Estabelece uma conexão ao Invidious para obter vídeos em vez de fazer uma conexão direta com o YouTube.\n    Scroll Playback Rate Over Video Player: Com o cursor sobre o vídeo, pressione e segure a tecla Ctrl (tecla Command no Mac) e role a roda do mouse para frente ou para trás para controlar a taxa de reprodução. Pressione e segure a tecla Ctrl (tecla Command no Mac) e clique com o botão esquerdo do mouse para retornar rapidamente à taxa de reprodução padrão (1x a menos que tenha sido alterada nas configurações).\n    Skip by Scrolling Over Video Player: Use o botão de rolagem do mouse para avançar ou retroceder o vídeo, estilo MPV.\n  General Settings:\n    Region for Trending: A região de tendências permite que você escolha os vídeos em alta do país que deseja exibir.\n    Invidious Instance: A instância Invidious à qual o FreeTube se conectará para chamadas de API.\n    Thumbnail Preference: Todas as miniaturas no FreeTube serão substituídas por um quadro do vídeo, desfocado ou oculto, em vez da miniatura padrão.\n    Fallback to Non-Preferred Backend on Failure: Quando sua API preferida tiver um problema, o FreeTube tentará automaticamente usar sua API não preferencial como método alternativo quando habilitada.\n    Preferred API Backend: Escolha o mecanismo de processamento que o FreeTube usa para obter os dados. A API local é um extrator integrado. A API Invidious requer um servidor Invidious para se conectar.\n    External Link Handling: \"Escolha o comportamento padrão quando um link que não pode ser aberto no FreeTube for clicado.\\nPor padrão, o FreeTube abrirá o link clicado em seu navegador padrão.\\n\"\n    Open Deep Links In New Window: Os URLs a partir do FreeTube, como por extensões de navegador de redirecionamento ou argumentos de linha de comando, são abertos em uma nova janela.\n  External Player Settings:\n    Custom External Player Arguments: Quaisquer argumentos de linha de comando personalizados, você deseja que seja passado para o player externo.\n    Ignore Warnings: Suprime os avisos para quando o player externo atual não suportar uma ação (por exemplo, reverter playlist, etc.).\n    Custom External Player Executable: Por padrão, o FreeTube assumirá que o player externo escolhido pode ser encontrado por meio da variável de ambiente PATH. Se necessário, um caminho personalizado pode ser definido aqui.\n    External Player: 'Ao escolher um player externo, será exibido um ícone na miniatura para abrir o vídeo (ou uma playlist, se for compatível) a partir do player externo. Atenção: as configurações do Invidious não afetam reproduções externas.'\n    DefaultCustomArgumentsTemplate: \"(Padrão: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Não envie nenhum argumento padrão ao player externo além do URL do vídeo (por exemplo, taxa de reprodução, URL da playlist, etc.). Argumentos personalizados ainda serão transmitidos.\n  Experimental Settings:\n    Replace HTTP Cache: Desabilita o cache HTTP baseado em disco do Electron e habilita um cache de imagem em memória personalizado. Levará ao aumento do uso de RAM.\n  Distraction Free Settings:\n    Hide Channels: Insira o ID de um canal para impedir que todos os vídeos, playlists e o próprio canal apareçam nas buscas, em alta, mais populares e recomendados. O ID do canal inserido deve ser uma correspondência completa e diferenciar maiúsculas de minúsculas.\n    Hide Subscriptions Live: Esta definição é substituída pela definição de toda a aplicação \"{appWideSetting}\", na seção \"{subsection}\" da \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Insira uma palavra, trecho de uma palavra ou frase (sem distinção entre maiúsculas e minúsculas) para ocultar todos os vídeos e playlists cujos títulos originais a contenham em todo o FreeTube, excluindo apenas histórico, suas playlists e vídeos dentro das playlists.\n    Hide Videos on Watch: Oculta vídeos já assistidos a partir das guias \"Vídeos\", \"Shorts\" e \"Ao Vivo\" nas páginas de \"Assinatura\" e \"Canal\". Isso não afeta a guia \"Início\" nas páginas de \"Canal\"\n  SponsorBlock Settings:\n    UseDeArrowTitles: Substituir títulos de vídeo por títulos enviados pelo usuário a partir do DeArrow.\n    UseDeArrowThumbnails: Substitua as miniaturas de vídeo pelas miniaturas do DeArrow.\nMore: Mais\nPlaying Next Video Interval: A reproduzir o próximo vídeo imediatamente. Clique para cancelar. | A reproduzir o próximo vídeo em {nextVideoInterval} segundo. Clique para cancelar. | A reproduzir o próximo vídeo em {nextVideoInterval} segundos. Clique para cancelar.\nUnknown YouTube url type, cannot be opened in app: Tipo de URL do YouTube desconhecida, não pode ser aberta no aplicativo\nOpen New Window: Abrir nova janela\nDefault Invidious instance has been cleared: A instância padrão Invidious foi excluída\nDefault Invidious instance has been set to {instance}: A instância padrão Invidious foi definida para {instance}\nSearch Bar:\n  Clear Input: Excluir texto\n  Remove: Remover\nExternal link opening has been disabled in the general settings: Abrir links externos está desabilitado nas configurações gerais\nAre you sure you want to open this link?: Tem certeza de que deseja abrir este link?\nNew Window: Nova janela\nChannels:\n  Channels: Canais\n  Title: Lista de canais\n  Search bar placeholder: Buscar canais\n  Empty: Sua lista de canais está vazia no momento.\n  Unsubscribe Prompt: Deseja cancelar sua inscrição de \"{channelName}\"?\n  Count: '{number} canais encontrados.'\nScreenshot Success: Captura de tela salva\nScreenshot Error: Falha na captura de tela. {error}\nPreferences: Preferências\nClipboard:\n  Copy failed: Falha ao copiar para a área de transferência\n  Cannot access clipboard without a secure connection: Não é possível acessar a área de transferência sem uma conexão segura\nChapters:\n  Chapters: Capítulos\n  Key Moments: Melhores momentos\nOk: OK\nHashtag:\n  This hashtag does not currently have any videos: Esta hashtag não tem atualmente nenhum vídeo\n  Hashtag: Hashtag\nChannel Hidden: '{channel} adicionado ao filtro de canais'\nGo to page: Ir para {page}\nChannel Unhidden: '{channel} removido do filtro de canais'\nTrimmed input must be at least N characters long: A entrada aparada deve ter pelo menos 1 caractere | A entrada aparada deve ter pelo menos {length} caracteres\nTag already exists: A tag \"{tagName}\" já existe\nClose Banner: Fechar banner\nAge Restricted:\n  This channel is age restricted: Este canal tem restrição de idade\n  This video is age restricted: Este vídeo tem restrição de idade\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nFeed:\n  Feed Last Updated: '{feedName}, atualizado em {date}'\n  Refresh Feed: Atualizar {subscriptionName}\nMoments Ago: momentos atrás\nYes, Delete: Sim, excluir\nYes, Restart: Sim, reiniciar\nYes, Open Link: Sim, abrir link\nCancel: Cancelar\nSearch character limit: Sua busca ultrapassou o limite de {searchCharacterLimit} caracteres\nSearch Listing:\n  Label:\n    Subtitles: Legendas\n    Closed Captions: Legendas (CC)\n    4K: 4K\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    3D: 3D\n    New: Novo\nKeys:\n  alt: Alt\n  arrowup: Seta para cima\n  arrowright: Seta para a direita\n  ctrl: Ctrl\n  arrowdown: Seta para baixo\n  arrowleft: Seta para a esquerda\n  shift: Shift\n  enter: Enter\n  plus: Plus\nshortcutJoinOperator: +\nRight-click or hold to see history: Clique com o botão direito ou mantenha pressionado para ver o histórico\nAutoplay Interruption Timer: Reprodução automática cancelada devido a {autoplayInterruptionIntervalHours} horas de inatividade\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nDescription:\n  Expand Description: '...Ler mais'\n  Collapse Description: Mostrar menos\nKeyboardShortcutPrompt:\n  Sections:\n    Video:\n      Playback: 'Vídeo: Reprodução'\n      General: 'Vídeo: Geral'\n    App:\n      Situational: 'Aplicativo: Situação'\n      General: 'Aplicativo: Geral'\n  Keyboard Shortcuts: Teclas de atalho\n  Navigate to Settings: Acessar a página de Configurações\n  Show Keyboard Shortcuts: Mostrar teclas de atalho\n  History Backward: Voltar uma página\n  History Forward: Avançar uma página\n  New Window: Criar uma nova janela\n  Fullscreen: Alternar modo tela cheia\n  Picture in Picture: Alternar modo Picture-in-Picture\n  Captions: Ativar ou desativar legendas\n  Stats: Mostrar estatísticas do vídeo\n  Increase Video Speed: Aumentar a velocidade do vídeo com base no intervalo da taxa de reprodução do vídeo\n  Decrease Video Speed: Diminuir a velocidade do vídeo com base no intervalo da taxa de reprodução do vídeo\n  Minimize Window: Minimizar janela\n  Zoom In: Ampliar\n  Close Window: Fechar janela\n  Focus Search: Focar na barra de busca\n  Search in New Window: Buscar em uma nova janela\n  Zoom Out: Diminuir\n  Refresh: Atualizar o feed com o conteúdo mais recente\n  Focus Secondary Search: Concentre-se na barra de busca secundária (se houver)\n  Play: Reproduzir ou pausar o vídeo\n  Large Fast Forward: Avançar 10 segundos / Avanço rápido do vídeo com base na taxa de reprodução do vídeo atual\n  Mute: Ativar ou desativar o áudio\n  Full Window: Alternar modo preenchimento de janela\n  Theatre Mode: Alternar modo Teatro\n  Take Screenshot: Tirar captura de tela\n  Toggle Developer Tools: Alternar modo ferramentas de desenvolvedor\n  Last Frame: Quadro anterior (enquanto pausado)\n  Small Fast Forward: Avanço rápido de X segundos com base no intervalo de avanço rápido e na taxa de reprodução do vídeo atual\n  Last Chapter: Último capítulo\n  Volume Down: Diminuir volume\n  Large Rewind: Voltar 10 segundos / Retroceder vídeo com base na taxa de reprodução do vídeo atual\n  Navigate to History: Acessar a página de Histórico\n  Small Rewind: Voltar X segundos com base no intervalo de retrocesso e na taxa de reprodução do vídeo atual\n  Next Frame: Próximo quadro (enquanto pausado)\n  Volume Up: Aumentar volume\n  Reset Zoom: Redefinir o nível de zoom / Escala da Interface do Usuário\n  Next Chapter: Próximo capítulo\n  Skip by Tenths: Pular vídeo por porcentagem (3 pulos até 30% da duração)\n  Home: Ir para o início do vídeo\n  End: Ir para o final do vídeo\n  Skip to Next Video: Pular para o próximo vídeo em uma playlist ou para o próximo vídeo recomendado\n  Skip to Previous Video: Pular para o vídeo anterior em uma playlist\nshortcutLabelSeparator: ｜\nCompact side navigation: Navegação lateral compacta\nExpand side navigation: Expandir navegação lateral\n"
  },
  {
    "path": "static/locales/pt-PT.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: Português\n\n# Webkit Menu Bar\nFile: Ficheiro\nQuit: Sair\nEdit: Editar\nUndo: Desfazer\nRedo: Refazer\nCut: Cortar\nCopy: Copiar\nPaste: Colar\nDelete: Eliminar\nSelect all: Selecionar tudo\nToggle Developer Tools: Comutar ferramentas de desenvolvimento\nActual size: Tamanho real\nZoom in: Ampliar\nZoom out: Reduzir\nToggle fullscreen: Comutar ecrã completo\nWindow: Janela\nMinimize: Minimizar\nClose: Fechar\nBack: Recuar\nForward: Avançar\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: Vídeos\n  Shorts: Curtos\n  Live: Em direto\n  Posts: Publicações\n  Sort By: Ordenar por\n\n  Counts:\n    Video Count: 1 vídeo | {count} vídeos\n    Subscriber Count: 1 subscritor | {count} subscritores\n    View Count: 1 visualização | {count} visualizações\n    Watching Count: 1 assistindo | {count} assistindo\n    Channel Count: 1 canal | {count} canais\n    Like Count: 1 curtida | {count} curtidas\n    Comment Count: 1 comentários | {count} comentários\nVersion {versionNumber} is now available!  Click for more details: A versão {versionNumber} está disponível! Clique aqui para mais informações.\nDownload From Site: Descarregar do site\nA new blog is now available, {blogTitle}. Click to view more: 'Está disponível um novo blogue, {blogTitle}. Clique para ver mais'\n\n# Search Bar\nSearch / Go to URL: Pesquisar / ir para o URL\n  # In Filter Button\nSearch Filters:\n  Search Filters: Filtros de pesquisa\n  Sort By:\n    Most Relevant: Mais relevantes\n    Rating: Avaliação\n    Upload Date: Data de publicação\n    View Count: Visualizações\n  Time:\n    Time: Intervalo de tempo\n    Any Time: Sempre\n    Last Hour: Última hora\n    Today: Hoje\n    This Week: Esta semana\n    This Month: Este mês\n    This Year: Este ano\n  Type:\n    Type: Tipo\n    All Types: Todos os tipos\n    Videos: Vídeos\n    Channels: Canais\n    #& Playlists\n    Movies: Filmes\n  Duration:\n    Duration: Duração\n    All Durations: Todas as durações\n    Short (< 4 minutes): Curta (< 4 minutos)\n    Long (> 20 minutes): Longa (> 20 minutos)\n  # On Search Page\n    Medium (4 - 20 minutes): Média (4 - 20 minutos)\n  Search Results: Resultados\n  Fetching results. Please wait: A procurar. Por favor aguarde\n  Fetch more results: Obter mais resultados\n  There are no more results for this search: Não existem mais resultados\n# Sidebar\n  Features:\n    Subtitles: Legendas\n    Features: Funcionalidades\n    HD: HD\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Direto\n    4K: 4K\n    Location: Localização\n    HDR: HDR\n    360 Video: Vídeo 360\n    VR180: VR180\n  Clear Filters: Limpar Filtros\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: Subscrições\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil contém um elevado número de subscrições. A forçar utilização de RSS para evitar que a sua rede seja bloqueada.\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': A sua lista de subscrições está vazia. Se quiser importar subscrições, pode aceder às definições de dados e selecionar Importar subscrições. Em alternativa, pode procurar os canais e efetuar a subscrição.\n  Load More Videos: Carregar mais vídeos\n  Error Channels: Canais com erros\n  Disabled Automatic Fetching: Desativou a atualização automática de subscrições. Recarregue as subscrições para as ver aqui.\n  Empty Channels: Os canais subscritos não têm, atualmente, quaisquer vídeos.\n  Subscriptions Tabs: Separadores de subscrições\n  All Subscription Tabs Hidden: Todos os separadores de subscrição estão ocultos. Para ver o conteúdo aqui, desoculte alguns separadores na secção \"{subsection}\" em \"{settingsSection}\".\n  Load More Posts: Carregar mais publicações\n  Empty Posts: Os canais subscritos não tem quaisquer publicações.\nTrending:\n  Trending: Tendências\n  Trending Tabs: Separadores de tendências\n  Gaming: Jogos\n  Sports: Desporto\nMost Popular: Mais populares\nPlaylists: Listas de reprodução\nUser Playlists:\n  Your Playlists: As suas listas de reprodução\n  Search bar placeholder: Procurar listas de reprodução\n  Empty Search Message: Não há vídeos nesta lista de reprodução que coincidam com a sua pesquisa\n  Are you sure you want to delete this playlist? This cannot be undone: Tem certeza de que pretende eliminar esta lista de reprodução? Isto não pode ser revertido.\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: O vídeo foi removido\n      Playlist has been updated.: A lista de reprodução foi atualizada.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Alguns vídeos da lista de reprodução ainda não foram carregados. Clique aqui continuar.\n      Playlist name cannot be empty. Please input a name.: O nome da lista de reprodução não pode estar vazio. Introduza um nome.\n      There was a problem with removing this video: Ocorreu um erro ao remover este vídeo\n      This video cannot be moved down.: Este vídeo não pode ser movido para baixo.\n      \"{videoCount} video(s) have been removed\": 1 vídeo foi removido | {videoCount} vídeos foram removidos\n      Playlist {playlistName} has been deleted.: A lista de reprodução {playlistName} foi eliminada.\n      This video cannot be moved up.: Este vídeo não pode ser movido para cima.\n      There was an issue with updating this playlist.: Ocorreu um erro ao atualizar esta lista de reprodução.\n      There were no videos to remove.: Não existiam vídeos para remover.\n      This playlist is protected and cannot be removed.: Esta lista de reprodução está protegida e não pode ser removida.\n      This playlist does not exist: Esta lista de reprodução não existe\n      This playlist is now used for quick bookmark: Esta playlist agora está sendo usado como marcador\n      Video has been removed. Click here to undo.: O vídeo foi removido. Clique aqui para desfazer.\n      Reverted to use {oldPlaylistName} for quick bookmark: Revertido para utilizar {oldPlaylistName} para o marcador rápido\n      This playlist is already being used for quick bookmark.: Esta lista de reprodução já está a ser usada como marcador rápido.\n      This playlist has a video with a duration error: Esta lista de reprodução contém pelo menos um vídeo que não tem uma duração. Será ordenada como se a sua duração fosse zero.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: A playlist agora é usada como marcador ao invés da {oldPlaylistName}. Clique aqui para desfazer\n    Search for Videos: Procurar vídeos\n  You have no playlists. Click on the create new playlist button to create a new one.: Não tem listas de reprodução. Clique no botão de criar uma nova lista de reprodução para criar uma.\n  Remove from Playlist: Remover da lista de reprodução\n  Save Changes: Guardar alterações\n  Sort By:\n    LatestCreatedFirst: Data de Criação (Mais Recente)\n    NameDescending: Z-A\n    LatestUpdatedFirst: Data de Atualização (Mais Recente)\n    NameAscending: A-Z\n    EarliestCreatedFirst: Data de Criação (Mais Antigo)\n    EarliestUpdatedFirst: Data de Atualização (Mais Antigo)\n    LatestPlayedFirst: Data de Reprodução (Mais Recente)\n    EarliestPlayedFirst: Data de Reprodução (Mais Antigo)\n  This playlist currently has no videos.: Esta lista de reprodução não tem vídeos atualmente.\n  Add to Playlist: Adicionar à lista de reprodução\n  Move Video Down: Mover vídeo para baixo\n  Playlist Name: Nome da lista de reprodução\n  Remove Watched Videos: Remover vistos\n  Move Video Up: Mover vídeo para cima\n  Cancel: Cancelar\n  Delete Playlist: Eliminar lista de reprodução\n  Create New Playlist: Criar nova lista de reprodução\n  Edit Playlist Info: Editar informação da lista de reprodução\n  Copy Playlist: Copiar lista de reprodução\n  Playlist Description: Descrição da lista de reprodução\n  AddVideoPrompt:\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: Ainda não selecionou uma lista de reprodução.\n    Select a playlist to add your N videos to: Selecione uma lista de reprodução à qual adicionar o seu vídeo | Selecione uma lista de reprodução à qual adicionar os seus {videoCount} vídeos\n    N playlists selected: '{playlistCount} selecionados'\n    Search in Playlists: Procurar nas listas de reprodução\n    Save: Guardar\n    Allow Adding Duplicate Video(s): Permitir duplicação de vídeos\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} vídeos serão adicionados'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} vídeos já foram adicionados'\n    Added {count} Times: Já adicionado | Adicionado {count} vezes\n  CreatePlaylistPrompt:\n    New Playlist Name: Nome da lista de reprodução\n    Create: Criar\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Já existe uma lista de reprodução com este nome. Por favor, escolha um nome diferente.\n      Playlist {playlistName} has been successfully created.: A lista de reprodução {playlistName} foi criada com sucesso.\n      There was an issue with creating the playlist.: Ocorreu um erro ao criar a lista de reprodução.\n  Remove from Favorites: Remover de {playlistName}\n  Enable Quick Bookmark With This Playlist: Habilitar marcador para esta playlist\n  Playlists with Matching Videos: Listas de reprodução coincidentes\n  Add to Favorites: Adicionar a {playlistName}\n  Quick Bookmark Enabled: Marcador rápido ativado\n  Remove Duplicate Videos: Remover duplicados\n  Export Playlist: Exportar lista de reprodução\n  The playlist has been successfully exported: Lista de reprodução exportada com sucesso\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Tem a certeza de que pretende remover 1 vídeo visualizado desta lista de reprodução? Esta remoção não pode ser revertida. | Tem a certeza de que pretende remover {playlistItemCount} vídeos visualizados desta lista de reprodução? Esta remoção não pode ser revertida.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Tem a certeza de que pretende remover 1 vídeo duplicado desta lista de reprodução? Esta remoção não pode ser revertida. | Tem a certeza de que pretende remover {playlistItemCount} vídeos duplicados desta lista de reprodução? Esta remoção não pode ser revertida.\n  Cannot delete the quick bookmark target playlist.: Não é possível eliminar a lista de reprodução de destino do marcador rápido.\n  TotalTimePlaylist: 'Duração total: {duration}'\n  Export list of URLs: Exportar lista de URLs\nHistory:\n  # On History Page\n  History: Histórico\n  Watch History: Histórico de visualizações\n  Your history list is currently empty.: O seu histórico está vazio.\n  Search bar placeholder: Procurar no histórico\n  Empty Search Message: Não há vídeos no histórico que coincidam com a sua pesquisa\n  Case Sensitive Search: Diferenciar maiúsculas e minúsculas\n  DateOldestHistory: Data de Visualização (Mais Antigo)\n  DateNewestHistory: Data de Visualização (Mais Recente)\nSettings:\n  # On Settings Page\n  Settings: Definições\n  The app needs to restart for changes to take effect. Restart and apply change?: Tem que reiniciar a aplicação para aplicar as alterações. Reiniciar e aplicar alterações?\n  General Settings:\n    General Settings: Geral\n    Check for Updates: Procurar atualizações\n    Check for Latest Blog Posts: Verificar se há novas publicações no blogue\n    Fallback to Non-Preferred Backend on Failure: Utilizar sistema de ligação secundário, em caso de falha\n    Enable Search Suggestions: Ativar sugestões de pesquisa\n    Default Landing Page: Página inicial\n    Locale Preference: Idioma\n    Preferred API Backend:\n      Preferred API Backend: API preferencial\n      Local API: API local\n      Invidious API: API Invidious\n    Video View Type:\n      Video View Type: Exibição dos vídeos\n      Grid: Grelha\n      List: Lista\n    Thumbnail Preference:\n      Thumbnail Preference: Preferências de miniaturas\n      Default: Padrão\n      Beginning: Início\n      Middle: Centro\n      End: Final\n      Blur: Desfocar\n      Hidden: Oculta\n    View all Invidious instance information: Mostrar toda a informação sobre esta instância Invidious\n    Region for Trending: Região para as tendências\n        #! List countries\n    System Default: Definido no sistema\n    Current instance will be randomized on startup: A instância, ao iniciar, será escolhida aleatoriamente\n    No default instance has been set: Não foi definida uma instância\n    The currently set default instance is {instance}: A instância padrão é {instance}\n    Current Invidious Instance: Instância Invidious atual\n    Clear Default Instance: Remover instância padrão\n    Set Current Instance as Default: Utilizar instância atual como padrão\n    External Link Handling:\n      No Action: Nenhuma ação\n      Ask Before Opening Link: Perguntar antes de abrir a hiperligação\n      Open Link: Abrir hiperligação\n      External Link Handling: Gestão de hiperligações externas\n    Auto Load Next Page:\n      Tooltip: Carrega as páginas e comentários automaticamente.\n      Label: Carregar seguinte automaticamente\n    Open Deep Links In New Window: Abrir URLs passados para o FreeTube numa nova janela\n    Minimize to system tray: Minimizar para o Tabuleiro do Sistema\n  Theme Settings:\n    Theme Settings: Tema\n    Match Top Bar with Main Color: Utilizar cor principal na barra superior\n    Expand Side Bar by Default: Expandir barra lateral por definição\n    Disable Smooth Scrolling: Desativar deslocação suave\n    UI Scale: Escala da interface\n    Base Theme:\n      Base Theme: Tema base\n      Black: Preto\n      Dark: Escuro\n      Light: Claro\n      Dracula: 'Drácula'\n      System Default: Definição do sistema\n      Catppuccin Mocha: Cappuccino mocha\n      Hot Pink: Rosa choque\n      Pastel Pink: Rosa pastel\n      Nordic: Nórdico\n      Solarized Light: Claro solar\n      Solarized Dark: Escuro solar\n      Catppuccin Frappe: Frapé de catppuccin\n      Gruvbox Dark: Gruvbox Escuro\n      Gruvbox Light: Luz Gruvbox\n      Everforest Dark Low: Everforest Dark baixo\n      Everforest Light Hard: Floresta perene Luz dura\n      Everforest Light Medium: Everforest Ligeiro Médio\n      Everforest Dark Hard: Floresta escura dura\n      Everforest Dark Medium: Everforest Dark médio\n      Everforest Light Low: Everforest Light baixo\n    Main Color Theme:\n      Main Color Theme: Cor principal\n      Red: Vermelho\n      Pink: Rosa\n      Purple: Roxo\n      Deep Purple: Roxo escuro\n      Indigo: Índigo\n      Blue: Azul\n      Light Blue: Azul claro\n      Cyan: Ciano\n      Teal: Azul esverdeado\n      Green: Verde\n      Light Green: Verde claro\n      Lime: Lima\n      Yellow: Amarelo\n      Amber: Âmbar\n      Orange: Laranja\n      Deep Orange: Laranja escuro\n      Dracula Cyan: 'Drácula ciano'\n      Dracula Green: 'Drácula verde'\n      Dracula Orange: 'Drácula laranja'\n      Dracula Pink: 'Drácula rosa'\n      Dracula Purple: 'Drácula roxo'\n      Dracula Red: 'Drácula vermelho'\n      Dracula Yellow: 'Drácula amarelo'\n      Catppuccin Mocha Rosewater: Cappuccino mocha rosewater\n      Catppuccin Mocha Flamingo: Cappuccino mocha flamingo\n      Catppuccin Mocha Pink: Cappuccino mocha rosa\n      Catppuccin Mocha Mauve: Cappuccino mocha mauve\n      Catppuccin Mocha Red: Cappuccino mocha vermelho\n      Catppuccin Mocha Maroon: Cappuccino mocha castanho\n      Catppuccin Mocha Peach: Cappuccino mocha pêssego\n      Catppuccin Mocha Yellow: Cappuccino mocha amarelo\n      Catppuccin Mocha Green: Cappuccino mocha verde\n      Catppuccin Mocha Teal: Cappuccino mocha azul esverdeado\n      Catppuccin Mocha Sky: Cappuccino mocha céu\n      Catppuccin Mocha Sapphire: Cappuccino mocha safira\n      Catppuccin Mocha Blue: Cappuccino mocha azul\n      Catppuccin Mocha Lavender: Cappuccino mocha lavanda\n      Solarized Orange: Laranja solar\n      Solarized Violet: Violeta solar\n      Solarized Green: Verde solar\n      Solarized Red: Vermelho solar\n      Solarized Magenta: Magenta solar\n      Solarized Blue: Azul solar\n      Solarized Cyan: Ciano solar\n      Solarized Yellow: Amarelo solar\n      Catppuccin Frappe Rosewater: Frapé de Catppuccin com água de rosas\n      Catppuccin Frappe Flamingo: Frapé de Catppuccin Flamingo\n      Catppuccin Frappe Pink: Frapé de Catppuccin com rosas\n      Catppuccin Frappe Mauve: Frapé de Catppuccin Mauve\n      Catppuccin Frappe Red: Frapé de Catppuccin vermelho\n      Catppuccin Frappe Maroon: Frapé de Catppuccin castanho\n      Catppuccin Frappe Peach: Frapé de Catppuccin pêssego\n      Catppuccin Frappe Yellow: Frapé de Catppuccin amarelo\n      Catppuccin Frappe Green: Frapé de Catppuccin verde\n      Catppuccin Frappe Teal: Frapé de Catppuccin verde-azulado\n      Catppuccin Frappe Sky: Frapé de Catppuccin céu\n      Catppuccin Frappe Sapphire: Frapé de Catppuccin safira\n      Catppuccin Frappe Blue: Frapé de Catppuccin azul\n      Catppuccin Frappe Lavender: Frapé de Catppuccin lavanda\n      Gruvbox Dark Orange: Gruvbox laranja escuro\n      Gruvbox Light Red: Gruvbox vermelho claro\n      Gruvbox Light Purple: Gruvbox violeta claro\n      Gruvbox Light Orange: Gruvbox laranja claro\n      Gruvbox Dark Green: Gruvbox verde escuro\n      Gruvbox Dark Blue: Gruvbox azul escuro\n      Gruvbox Dark Purple: Gruvbox roxo escuro\n      Gruvbox Dark Aqua: Gruvbox água escura\n      Gruvbox Light Blue: Gruvbox azul claro\n      Gruvbox Dark Yellow: Gruvbox amarelo escuro\n      Everforest Dark Green: Everforest Verde escuro\n      Everforest Light Blue: Everforest azul claro\n      Everforest Dark Aqua: Everestforest Dark Aqua\n      Everforest Dark Red: Everforest Vermelho escuro\n      Everforest Dark Orange: Everforest Laranja escuro\n      Everforest Dark Yellow: Everforest Amarelo escuro\n      Everforest Dark Blue: Azul escuro Everforest\n      Everforest Dark Purple: Everforest Dark Purple (púrpura escuro)\n      Everforest Light Red: Vermelho claro Everforest\n      Everforest Light Orange: Everforest Laranja claro\n      Everforest Light Yellow: Everforest Amarelo claro\n      Everforest Light Green: Verde claro Everforest\n      Everforest Light Aqua: Everforest Light Aquático\n      Everforest Light Purple: Everforest Púrpura claro\n    Secondary Color Theme: Cor secundária\n        #* Main Color Theme\n    Hide Side Bar Labels: Ocultar texto na barra lateral\n    Hide FreeTube Header Logo: Ocultar logotipo FreeTube no topo\n  Player Settings:\n    Player Settings: Reprodutor\n    Play Next Video: Reproduzir automaticamente os vídeos recomendados\n    Turn on Subtitles by Default: Ativar legendas por predefinição\n    Autoplay Videos: Reproduzir vídeos automaticamente\n    Proxy Videos Through Invidious: Utilizar Invidious com proxy\n    Autoplay Playlists: Reproduzir automaticamente vídeos da lista de reprodução\n    Enable Theatre Mode by Default: Ativar modo cinema por omissão\n    Default Volume: Volume padrão\n    Default Playback Rate: Velocidade de reprodução padrão\n    Default Video Format:\n      Default Video Format: Formato de vídeo padrão\n      Dash Formats: Formatos DASH\n      Legacy Formats: Formatos antigos\n      Audio Formats: Formatos de áudio\n    Default Quality:\n      Default Quality: Qualidade padrão\n      Auto: Automática\n      144p: 144p\n      240p: 240p\n      360p: 360p\n      480p: 480p\n      720p: 720p\n      1080p: 1080p\n      1440p: 1440p\n      4k: 4k\n      8k: 8k\n    Next Video Interval: Temporizador de contagem decrescente de reprodução automática\n    Fast-Forward / Rewind Interval: Tempo a avançar / recuar\n    Display Play Button In Video Player: Mostrar botão \"Reproduzir\" no reprodutor\n    Scroll Volume Over Video Player: Alterar volume com a roda do rato por cima do reprodutor\n    Screenshot:\n      File Name Label: Padrão para nome de ficheiro\n      Enable: Permitir capturas de ecrã\n      Format Label: Formato das capturas de ecrã\n      Quality Label: Qualidade da captura de ecrã\n      Ask Path: Perguntar onde guardar\n      Folder Label: Pasta para as capturas de ecrã\n      Folder Button: Selecionar pasta\n      Error:\n        Forbidden Characters: Caracteres proibidos\n        Empty File Name: Nome de ficheiro vazio\n      File Name Tooltip: 'Pode utilizar estas variáveis: %Y ano com 4 dígitos, %M mês com 2 dígitos, %D dia com 2 dígitos, %H hora com 2 dígitos, %N minuto com 2 dígitos, %S segundos com 2 dígitos, %T milissegundos com 3 dígitos, %s segundos do vídeo, %t milissegundos do vídeo com 3 dígitos, %i ID do vídeo.'\n    Max Video Playback Rate: Velocidade máxima de reprodução\n    Video Playback Rate Interval: Intervalo entre velocidades de reprodução\n    Scroll Playback Rate Over Video Player: Alterar velocidade de reprodução com a roda do rato\n    Enter Fullscreen on Display Rotate: Ativar modo de ecrã completo ao rodar o ecrã\n    Skip by Scrolling Over Video Player: Avançar ou recuar no vídeo com a roda do rato\n    Default Viewing Mode:\n      Theater: Teatro\n      Default Viewing Mode: Modo de visualização predefinido\n      Full Screen: Ecrã completo\n      Picture in Picture: Imagem sobre imagem\n      External Player: Reprodutor externo ({externalPlayerName})\n    Autoplay Interruption Timer: Temporizador de interrupção da reprodução automática\n  Privacy Settings:\n    Privacy Settings: Privacidade\n    Remember History: Memorizar histórico de visualizados\n    Save Watched Progress: Guardar progresso de reprodução\n    Clear Search Cache: Limpar cache de pesquisas\n    Are you sure you want to clear out your search cache?: Tem a certeza de que pretende limpar a sua cache de pesquisas?\n    Search cache has been cleared: Cache de pesquisas limpa\n    Remove Watch History: Limpar histórico de visualizações\n    Are you sure you want to remove your entire watch history?: Tem a certeza de que pretende limpar o histórico de visualizações?\n    Watch history has been cleared: Histórico de visualizações limpo\n    Remove All Subscriptions / Profiles: Remover todas as subscrições / perfis\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Tem a certeza de que pretende remover todas as suas subscrições e perfis? Esta ação não pode ser revertida.\n    Save Watched Videos With Last Viewed Playlist: Guardar vídeos vistos com a última lista de reprodução vista\n    Remove All Playlists: Remover todas as listas de reprodução\n    All playlists have been removed: Todas as listas de reprodução foram removidas\n    Are you sure you want to remove all your playlists?: Tem a certeza de que pretende remover todas as suas listas de reprodução?\n    Search history and cache have been cleared: O histórico de pesquisa e a cache foram limpos\n    Remember Search History: Memorizar histórico de pesquisa\n    Clear Search History and Cache: Limpar o histórico de pesquisa e a cache\n    Are you sure you want to clear out your search history and cache?: Tem a certeza de que pretende limpar o histórico de pesquisa e a cache?\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Nunca\n        Auto: Automático\n        Semi-auto: Semiautomático\n      Tooltip: 'Automático = Guarda sempre: ao sair da página do vídeo, quando o vídeo termina ou se ocorrer algum erro (por ex.: limite de taxa atingido ou sessão expirada). Semiautomático = Igual ao modo Automático, exceto ao sair da página do vídeo, permite guardar o progresso manualmente através do botão \"Guardar progresso de reprodução\", que se encontra em baixo do reprodutor.'\n  Subscription Settings:\n    Subscription Settings: Subscrição\n    Fetch Feeds from RSS: Obter subscrições através de RSS\n    Fetch Automatically: Obter fontes automaticamente\n    Confirm Before Unsubscribing: Impedir cancelamento acidental de subscrições\n    To: A\n    'Limit the number of videos displayed for each channel': Limitar o número de vídeos apresentados para cada canal\n  Distraction Free Settings:\n    Distraction Free Settings: Distrações\n    Hide Video Views: Ocultar visualizações\n    Hide Video Likes And Dislikes: Ocultar \"gostos\" em vídeos\n    Hide Channel Subscribers: Ocultar número de subscritores\n    Hide Comment Likes: Ocultar \"gostos\" em comentários\n    Hide Recommended Videos: Ocultar vídeos recomendados\n    Hide Trending Videos: Ocultar tendências\n    Hide Popular Videos: Ocultar vídeos populares\n    Hide Live Chat: Ocultar conversas em direto\n    Hide Active Subscriptions: Ocultar subscrições ativas\n    Hide Playlists: Ocultar listas de reprodução\n    Hide Video Description: Ocultar descrição dos vídeos\n    Hide Comments: Ocultar comentários\n    Hide Live Streams: Ocultar transmissões em direto\n    Hide Sharing Actions: Ocultar ações de partilha\n    Hide Videos on Watch: Ocultar vídeos visualizados\n    Hide Chapters: Ocultar capítulos\n    Hide Upcoming Premieres: Ocultar próximas estreias\n    Hide Channels: Ocultar vídeos dos canais\n    Hide Channels Placeholder: ID do canal\n    Display Titles Without Excessive Capitalisation: Mostrar títulos sem maiúsculas ou pontuação em excesso\n    Hide Featured Channels: Ocultar canais em destaque\n    Hide Channel Playlists: Ocultar separador \"Listas de reprodução\" nos canais\n    Hide Channel Shorts: Ocultar separador \"Curtos\" nos canais\n    Sections:\n      Side Bar: Barra lateral\n      Channel Page: Página do canal\n      Watch Page: Ver página\n      General: Geral\n      Subscriptions Page: Página de subscrições\n    Hide Channel Releases: Ocultar separador \"Lançamentos\" nos canais\n    Hide Channel Podcasts: Ocultar separador \"Podcasts\" nos canais\n    Hide Subscriptions Videos: Ocultar subscrições de vídeos\n    Hide Subscriptions Shorts: Ocultar subscrições de curtos\n    Hide Subscriptions Live: Ocultar subscrições de emissões em direto\n    Hide Profile Pictures in Comments: Ocultar imagens de perfil nos comentários\n    Hide Channels Already Exists: Este ID já existe\n    Hide Channels Disabled Message: Alguns canais foram bloqueados e não foram processados. A funcionalidade está bloqueada enquanto estiver a ocorrer a atualização dos ID.\n    Hide Channels API Error: Não foi possível obter o utilizador através do ID. Verifique se o ID indicado está correto.\n    Hide Channels Invalid: O ID do canal não é válido\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Palavra, fragmento de palavra ou frase\n    Hide Videos, Playlists and Channels Containing Text: Esconda videos e playlist contendo texto\n    Hide Channel Home: Ocultar o separador “Página inicial” do canal\n    Show Added Items: Mostrar itens adicionados\n    Hide Channel Courses: Ocultar o separador “Cursos” do canal\n    Hide Channel Posts: Ocultar separador de \"Publicações\" nos canais\n    Hide Subscriptions Posts: Ocultar Publicações de Subscrições\n  Data Settings:\n    Data Settings: Dados\n    Select Export Type: Selecione o tipo de exportação\n    Import Subscriptions: Importar subscrições\n    Export Subscriptions: Exportar subscrições\n    Export FreeTube: Exportar FreeTube\n    Export YouTube: Exportar YouTube\n    Export NewPipe: Exportar NewPipe\n    Import History: Importar histórico\n    Export History: Exportar histórico\n    Profile object has insufficient data, skipping item: O perfil tem dados em falta, a ignorar\n    All subscriptions and profiles have been successfully imported: Todas as subscrições e perfis foram importados com sucesso\n    All subscriptions have been successfully imported: Todas as subscrições foram importadas com sucesso\n    Invalid subscriptions file: Ficheiro de subscrições inválido\n    Invalid history file: Ficheiro de histórico inválido\n    Subscriptions have been successfully exported: As subscrições foram exportadas com sucesso\n    History object has insufficient data, skipping item: O histórico tem dados em falta, a ignorar\n    All watched history has been successfully imported: O histórico foi importado com sucesso\n    All watched history has been successfully exported: O histórico foi exportado com sucesso\n    Unable to read file: Não foi possível ler o ficheiro\n    Unable to write file: Não foi possível escrever o ficheiro\n    Unknown data key: Chave de dados desconhecida\n    How do I import my subscriptions?: Como importar as minhas subscrições?\n    Manage Subscriptions: Gerir subscrições\n    Import Playlists: Importar listas de reprodução\n    Export Playlists: Exportar listas de reprodução\n    Playlist insufficient data: Dados insuficientes para a lista de reprodução \"{playlist}\", a ignorar\n    All playlists has been successfully imported: Todas as listas de reprodução foram importadas com sucesso\n    All playlists has been successfully exported: Todas as listas de reprodução foram exportadas com sucesso\n    Subscription File: Ficheiro de subscrição\n    History File: Ficheiro de histórico\n    Playlist File: Ficheiro de lista de reprodução\n    Export Playlists For Older FreeTube Versions:\n      Label: Exportar listas de reprodução para versões mais antigas do FreeTube\n      Tooltip: \"Esta opção exporta os vídeos de todas as listas de reprodução para uma lista de reprodução chamada \\\"Favoritos\\\".\\nComo exportar e importar vídeos em listas de reprodução para uma versão mais antiga do FreeTube:\\n1. Exporte as suas listas de reprodução com esta opção ativada.\\n2. Elimine todas as listas de reprodução existentes usando a opção \\\"Remover todas as listas de reprodução\\\" em \\\"Definições de privacidade\\\".\\n3. Abra a versão mais antiga do FreeTube e importe as listas de reprodução.\"\n  Proxy Settings:\n    Proxy Settings: Proxy\n    Enable Tor / Proxy: Ativar Tor / proxy\n    Proxy Protocol: Protocolo do proxy\n    Proxy Host: Servidor do proxy\n    Proxy Port Number: Porta do proxy\n    Clicking on Test Proxy will send a request to: Carregar em \"Testar proxy\" irá enviar um pedido a\n    Test Proxy: Testar proxy\n    Your Info: A sua informação\n    Ip: IP\n    Country: País\n    Region: Região\n    City: Cidade\n    Error getting network information. Is your proxy configured properly?: Erro ao obter informações da rede. O seu proxy está configurado corretamente?\n    Proxy Warning: O FreeTube não tem um proxy incorporado, mas pode conectar-se a um proxy externo, como um que esteja a ser executado na sua máquina, como o Tor, ou um proxy externo, como um proxy SOCKS5 fornecido por algumas VPNs. Se estiver ativado, certifique-se de que o seu proxy / Tor está configurado corretamente, ou o FreeTube não conseguirá obter quaisquer dados.\n    Proxy Username: Nome de Utilizador da Proxy\n    Proxy Password: Palavra-passe da Proxy\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar se um anúncio for ignorado\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL da API SponsorBlock (padrão é https://sponsor.ajay.app)\n    Enable SponsorBlock: Ativar bloqueio da publicidade SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Show In Seek Bar: Mostrar na barra de progresso\n      Skip Option: Opção para ignorar\n      Auto Skip: Ignorar automaticamente\n      Prompt To Skip: Perguntar se quero ignorar\n      Do Nothing: Nada fazer\n    Category Color: Cor da categoria\n    UseDeArrowTitles: Utilizar títulos de vídeo DeArrow\n    UseDeArrowThumbnails: Usar 'DeArrow' para miniaturas\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL da API do gerador de miniaturas DeArrow (padrão: https://dearrow-thumb.ajay.app)'\n  External Player Settings:\n    Custom External Player Arguments: Argumentos do reprodutor externo\n    Custom External Player Executable: Executável do reprodutor externo\n    Ignore Unsupported Action Warnings: Ignorar avisos sobre ações inválidas\n    External Player: Reprodutor externo\n    External Player Settings: Reprodutores externos\n    Players:\n      None:\n        Name: Nenhum\n    Ignore Default Arguments: Ignorar argumentos padrão\n  Parental Control Settings:\n    Parental Control Settings: Controlo parental\n    Hide Search Bar: Ocultar barra de pesquisa\n    Hide Unsubscribe Button: Ocultar botão \"Cancelar subscrição\"\n    Show Family Friendly Only: Mostrar apenas \"Para famílias\"\n    Hide Uploader on Watch page: Ocultar Nome do Autor na página de Reprodução de Vídeo\n  Experimental Settings:\n    Experimental Settings: Experimentais\n    Warning: Estas definições são experimentais e podem provocar falhas se ativadas. É altamente recomendado fazer cópias de segurança. Use por sua conta e risco!\n    Replace HTTP Cache: Substituir cache HTTP\n  Password Dialog:\n    Password: Palavra-passe\n    Enter Password To Unlock: Indique a palavra-passe para desbloquear as definições\n  Password Settings:\n    Password Settings: Palavra-passe\n    Set Password To Prevent Access: Defina uma palavra-passe para impedir o acesso às definições\n    Set Password: Definir palavra-passe\n    Remove Password: Remover palavra-passe\n  Sort Settings Sections (A-Z): Ordenar definições (A-Z)\n  Return to Settings Menu: Voltar para as definições\nAbout:\n  #On About page\n  About: Acerca\n  Beta: Beta\n  Source code: Código-fonte\n  Downloads / Changelog: Descargas / alterações\n  GitHub releases: Versões do GitHub\n  Help: Ajuda\n  FreeTube Wiki: Wiki FreeTube\n  FAQ: FAQ\n  Report a problem: Reportar um problema\n  GitHub issues: Problemas no GitHub\n  Please check for duplicates before posting: Antes de reportar verifique se alguém já reportou o mesmo problema\n  Website: Página web\n  Blog: Blogue\n  Email: E-mail\n  Mastodon: Mastodon\n  Chat on Matrix: Conversa no Matrix\n  room rules: regras da sala de conversa\n  Translate: Traduzir\n  Credits: Créditos\n  these people and projects: estas pessoas e projetos\n  Donate: Doar\n  Discussions: Discussões\n  AGPLv3: AGPLv3\nProfile:\n  All Channels: Todos os canais\n  Profile Manager: Gestor de perfis\n  Create New Profile: Criar novo perfil\n  Edit Profile: Editar perfil\n  Color Picker: Cor\n  Custom Color: Cor personalizada\n  Profile Preview: Pré-visualização do perfil\n  Create Profile: Criar perfil\n  Update Profile: Atualizar perfil\n  Make Default Profile: Tornar no perfil padrão\n  Delete Profile: Eliminar perfil\n  Are you sure you want to delete this profile?: Tem a certeza de que pretende eliminar este perfil?\n  All subscriptions will also be deleted.: Todas as subscrições associadas a este perfil também serão eliminadas.\n  Your profile name cannot be empty: O nome do perfil não pode ficar vazio\n  Profile has been created: Perfil criado\n  Profile has been updated: Perfil atualizado\n  Your default profile has been set to {profile}: '{profile} é agora o seu perfil padrão'\n  Removed {profile} from your profiles: O perfil {profile} foi eliminado\n  Your default profile has been changed to your primary profile: O seu perfil padrão é agora o seu perfil principal\n  '{profile} is now the active profile': Está agora a ver as subscrições do perfil {profile}\n  Subscription List: Lista de subscrições\n  Other Channels: Outros canais\n  '{number} selected': '{number} selecionado'\n  Select All: Selecionar tudo\n  Select None: Cancelar seleção\n  Delete Selected: Eliminar seleção\n  Add Selected To Profile: Adicionar seleção ao perfil\n  No channel(s) have been selected: Nenhum canal foi selecionado\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Este é o seu perfil principal. Tem a certeza de que pretende eliminar os canais selecionados? Os canais serão eliminados de todos os perfis.\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Tem a certeza de que pretende eliminar os canais selecionados? Esta ação não vai eliminar os canais dos outros perfis.\n#On Channel Page\n  Profile Select: Seleção de perfil\n  Profile Filter: Filtro de perfil\n  Profile Settings: Perfil\n  Toggle Profile List: Alternar lista de perfis\n  Close Profile Dropdown: Fechar menu do perfil\n  Open Profile Dropdown: Abrir menu do perfil\n  Edit Profile Name: Editar nome do perfil\n  Create Profile Name: Criar nome do perfil\n  Profile Name: Nome do perfil\nChannel:\n  Subscribe: Subscrever\n  Unsubscribe: Cancelar subscrição\n  Channel has been removed from your subscriptions: O canal foi removido das suas subscrições\n  Removed subscription from {count} other channel(s): Subscrição removida de mais {count} canais\n  Added channel to your subscriptions: Canal adicionado às suas subscrições\n  Search Channel: Procurar canal\n  Your search results have returned 0 results: A pesquisa devolveu 0 resultados\n  Videos:\n    Videos: Vídeos\n    This channel does not currently have any videos: Atualmente, este canal não tem vídeos\n    Sort Types:\n      Newest: Recentes\n      Oldest: Antigos\n      Most Popular: Mais populares\n  Playlists:\n    Playlists: Listas de reprodução\n    This channel does not currently have any playlists: Este canal não tem, atualmente, quaisquer listas de reprodução\n    Sort Types:\n      Last Video Added: Último vídeo adicionado\n      Newest: Recentes\n      Oldest: Antigos\n  About:\n    About: Acerca\n    Channel Description: Descrição do canal\n    Featured Channels: Canais em destaque\n    Tags:\n      Tags: Etiquetas\n      Search for: Procurar por «{tag}»\n    Details: Detalhes\n    Joined: Aderiu a\n    Location: Localização\n  This channel does not exist: Este canal não existe\n  This channel does not allow searching: Este canal não permite pesquisas\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Este canal tem restrição de idade e, atualmente, não pode ser visto no Free Tube.\n  Channel Tabs: Separadores de canais\n  Posts:\n    This channel currently does not have any posts: Este canal não tem, atualmente, quaisquer publicações\n    Reveal Answers: Mostrar respostas\n    Hide Answers: Ocultar respostas\n    votes: '{votes} votos'\n    Video hidden by FreeTube: Freetube ocultou este vídeo\n    View Full Post: Ver publicação na íntegra\n    Viewing Posts Only Supported By Invidious: A visualização de publicações só é suportada pelo Invidious. Aceda ao separador Comunidade de um canal para ver o conteúdo sem o Invidious.\n  Live:\n    Live: Em direto\n    This channel does not currently have any live streams: Este canal não tem, atualmente, qualquer emissão em direto\n  Shorts:\n    This channel does not currently have any shorts: Este canal não tem, atualmente, qualquer vídeo curto\n  Releases:\n    Releases: Lançamentos\n    This channel does not currently have any releases: Este canal não tem, atualmente, quaisquer lançamentos\n  Podcasts:\n    This channel does not currently have any podcasts: Este canal não tem, atualmente, quaisquer podcasts\n    Podcasts: Podcasts\n  Home:\n    Home: Página inicial\n    View Playlist: Ver lista de reprodução\n  Courses:\n    This channel does not currently have any courses: Este canal não tem atualmente nenhum curso\n    Courses: cursos\nVideo:\n  Mark As Watched: Marcar como visto\n  Remove From History: Remover do histórico\n  Video has been marked as watched: O vídeo foi marcado como visto\n  Video has been removed from your history: O vídeo foi removido do histórico\n  Save Video: Guardar vídeo\n  Video has been saved: O vídeo foi guardado\n  Video has been removed from your saved list: O vídeo foi removido da lista de guardados\n  Open in YouTube: Abrir no YouTube\n  Copy YouTube Link: Copiar hiperligação do YouTube\n  Open YouTube Embedded Player: Abrir reprodutor YouTube nativo\n  Copy YouTube Embedded Player Link: Copiar hiperligação do reprodutor integrado do YouTube\n  Open in Invidious: Abrir no Invidious\n  Copy Invidious Link: Copiar hiperligação Invidious\n  Open Channel in YouTube: Abrir canal no YouTube\n  Copy YouTube Channel Link: Copiar hiperligação do canal do YouTube\n  Open Channel in Invidious: Abrir canal no Invidious\n  Copy Invidious Channel Link: Copiar hiperligação do canal do Invidious\n  Views: Visualizações\n  Watched: Visto\n  Autoplay: Reprodução automática\n  Starting soon, please refresh the page to check again: Irá começar brevemente. Recarregue a página para reanalisar\n# As in a Live Video\n  Live: Em direto\n  Live Now: Em direto agora\n  Live Chat: Conversa em direto\n  Enable Live Chat: Permitir conversa em direto\n  Live Chat is currently not supported in this build.: A conversa em direto não é permitida nesta versão.\n  Live chat is enabled. Chat messages will appear here once sent.: A conversa em direto está ativada. As mensagens vão aparecer aqui.\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': Atualmente, a conversa em direto não é suportada pela API Invidious. É necessária uma conexão direta ao YouTube.\n  Published:\n    In less than a minute: Em menos de um minuto\n  Published on: Publicado a\n  Streamed on: Transmitido a\n  Started streaming on: Transmissão iniciada em\n#& Videos\n  Previous: 'Anterior'\n  Next: 'Seguinte'\n  Reverse Playlist: Inverter lista de reprodução\n  Shuffle Playlist: Baralhar lista de reprodução\n  Loop Playlist: Repetir lista de reprodução\n  External Player:\n    Unsupported Actions:\n      looping playlists: repetir lista de reprodução\n      shuffling playlists: baralhar lista de reprodução\n      reversing playlists: inverter lista de reprodução\n      opening specific video in a playlist (falling back to opening the video): abrir um vídeo específico da lista (vai apenas abrir o vídeo)\n      opening playlists: abrir listas de reprodução\n      setting a playback rate: mudar velocidade de reprodução\n      starting video at offset: iniciar vídeo num tempo específico\n    UnsupportedActionTemplate: '{externalPlayer} não suporta: {action}'\n    OpeningTemplate: A abrir {videoOrPlaylist} em {externalPlayer}...\n    playlist: lista de reprodução\n    video: vídeo\n    OpenInTemplate: Abrir com {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Música fora de tópico\n    interaction: Interação\n    self-promotion: Auto-promoção\n    outro: Outro\n    intro: Introdução\n    sponsor: Patrocinador\n    recap: Recapitulação\n    filler: Preenchimento\n  Premieres: Estreias\n  Show Super Chat Comment: Mostrar comentário do Super Chat\n  Scroll to Bottom: Deslocar para baixo\n  Upcoming: Em breve\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': A conversa em direto não está disponível para esta emissão. Pode ter sido desativada pelo publicador.\n  Hide Channel: Ocultar canal\n  Unhide Channel: Mostrar canal\n  More Options: Mais opções\n#& Playlists\n  IP block: O YouTube bloqueou a visualização de vídeos no seu endereço IP. Tente mudar para uma VPN ou proxy diferente.\n  Player:\n    Playback will resume automatically when your connection comes back: A reprodução será retomada automaticamente quando a conexão for restabelecida.\n    Stats:\n      Player Dimensions: 'Dimensões do reprodutor: {width}x{height}'\n      Bitrate: Taxa de dados :{bitrate} kbps\n      Video ID: 'ID do vídeo: {videoId}'\n      Media Formats: 'Formatos multimédia: {formats}'\n      CodecsVideoAudioNoItags: 'Codificadores: {videoCodec} / {audioCodec}'\n      Stats: Estatísticas\n      Dropped Frames / Total Frames: 'Fotogramas eliminados: {droppedFrames} / Total de fotogramas: {totalFrames}'\n      CodecAudio: 'Codificador: {audioCodec} ({audioItag})'\n      Resolution: 'Resolução: {width}x{height}{''@''}{frameRate}'\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Largura de banda: {bandwidth} kbps'\n      Buffered: 'Armazenado em buffer: {bufferedPercentage}%'\n      CodecsVideoAudio: 'Codificadores: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n    Hide Stats: Ocultar estatísticas\n    TranslatedCaptionTemplate: '{language} (traduzido de \"{originalLanguage}\")'\n    Full Window: Ecrã completo\n    Exit Full Window: Sair de ecrã completo\n    Skipped segment: Segmento {segmentCategory} ignorado\n    You appear to be offline: Parece que não tem conexão à Internet.\n    Theatre Mode: Modo teatro\n    Exit Theatre Mode: Sair do modo teatro\n    Audio Tracks: Faixas de áudio\n    Autoplay is off: A reprodução automática está desativada\n    Autoplay is on: A reprodução automática está ativada\n    Take Screenshot: Tirar uma captura de ecrã\n    Show Stats: Mostrar estatísticas\n  MembersOnly: Os vídeos só para membros não podem ser visualizados com o FreeTube, uma vez que requerem um início de sessão do Google e uma inscrição paga no canal do autor do vídeo.\n  AgeRestricted: Os vídeos com restrições de idade não podem ser vistos com o FreeTube, uma vez que requerem o início de sessão no Google e a utilização de uma conta YouTube com idade verificada.\n  Unlisted: Não listado\n  DeArrow:\n    Show Modified Details: Mostrar detalhes modificados\n    Show Original Details: Mostrar detalhes originais\n  DRMProtected: Os vídeos protegidos por DRM não podem ser reproduzidos no FreeTube, uma vez que requerem componentes proprietários e de código fechado. Se quiser ver este vídeo, veja-o no sítio Web oficial do YouTube num navegador Web com DRM.\n  Save Watched Progress: Gravar progresso de visualização\n  Watched Progress Saved: O Progresso de Visualização foi gravado\nPlaylist:\n  #& About\n  View Full Playlist: Ver lista de reprodução completa\n  Last Updated On: Última atualização\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lista de reprodução\n  Sort By:\n    DateAddedOldest: Data de Adição (Mais Antigo)\n    DateAddedNewest: Data de Adição (Mais Recente)\n    AuthorAscending: Autor (A-Z)\n    VideoTitleDescending: Título (Z-A)\n    Custom: Personalizado\n    AuthorDescending: Autor (Z-A)\n    VideoTitleAscending: Título (A-Z)\n    PublishedOldest: Data de Publicação (Mais Antigo)\n    PublishedNewest: Data de Publicação (Mais Recente)\n    VideoDurationAscending: Duração (Mais Curto)\n    VideoDurationDescending: Duração (Mais Longo)\nChange Format:\n  Change Media Formats: Alterar formatos multimédia\n  Use Dash Formats: Utilizar formatos DASH\n  Use Legacy Formats: Utilizar formatos antigos\n  Use Audio Formats: Utilizar formatos de áudio\n  Dash formats are not available for this video: Os formatos DASH não estão disponíveis para este vídeo\n  Audio formats are not available for this video: Os formatos de áudio não estão disponíveis para este vídeo\n  Legacy formats are not available for this video: Os formatos antigos não estão disponíveis para este vídeo\nShare:\n  Share Video: Partilhar vídeo\n  Share Playlist: Partilhar lista\n  Include Timestamp: Incluir posição temporal\n  Copy Link: Copiar hiperligação\n  Open Link: Abrir hiperligação\n  Copy Embed: Copiar incorporado\n  Open Embed: Abrir incorporado\n  # On Click\n  Invidious URL copied to clipboard: URL Invidious copiado a para área de transferência\n  Invidious Embed URL copied to clipboard: URL Invidious incorporado copiado para a área de transferência\n  Invidious Channel URL copied to clipboard: URL do canal Invidious copiado para a área de transferência\n  YouTube URL copied to clipboard: URL do YouTube copiado a para a área de transferência\n  YouTube Embed URL copied to clipboard: URL do YouTube incorporado copiado para a área de transferência\n  YouTube Channel URL copied to clipboard: URL do canal do YouTube copiado para a área de transferência\n\n  Share Channel: Partilhar canal\nMini Player: Mini-reprodutor\nComments:\n  Comments: Comentários\n  Click to View Comments: Clicar para ver os comentários\n  Getting comment replies, please wait: A obter respostas ao comentário, por favor aguarde\n  There are no more comments for this video: Não há mais comentários para este vídeo\n  Hide Comments: Ocultar comentários\n  Top comments: Melhores comentários\n  Newest first: Mais recentes\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: Este vídeo não tem comentários\n  Load More Comments: Carregar mais comentários\n  Show More Replies: Mostrar mais respostas\n  Pinned by: Fixado por\n  Member: Membro\n  View {replyCount} replies: Ver {replyCount} respostas\n  Hearted: Favorito\n  Subscribed: Subscrito\n  There are no comments available for this post: Não existem comentários para esta publicação\nUp Next: Próximo\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: Escolha o sistema que o FreeTube usa para se ligar ao YouTube. A API local é um extrator incorporado. A API Invidious requer um servidor Invidious para fazer a ligação.\n    Fallback to Non-Preferred Backend on Failure: Se a sua API preferida tiver um problema, FreeTube tentará usar automaticamente a API secundária, caso esta opção esteja ativada.\n    Thumbnail Preference: Todas as miniaturas dos vídeos no FreeTube serão substituídas por um quadro borrado ou escondido do vídeo em vez da miniatura original.\n    Invidious Instance: A instância Invidious à qual o FreeTube se irá ligar para invocar a API.\n    Region for Trending: A região permite-lhe escolher de que país virão os vídeos na secção de tendências.\n    External Link Handling: \"Escolha o comportamento padrão quando uma hiperligação, que não pode ser aberta no FreeTube, é clicada.\\nPor definição, o FreeTube abrirá a hiperligação no seu navegador de Internet.\\n\"\n    Open Deep Links In New Window: Os URLs passados para o FreeTube, como por extensões de navegador de redirecionamento ou argumentos de linha de comando, são abertos numa nova janela.\n  Player Settings:\n    Proxy Videos Through Invidious: Estabelece uma conexão ao Invidious para obter vídeos em vez de fazer uma conexão direta ao YouTube.\n    Default Video Format: Define os formatos usados quando um vídeo é reproduzido. Os formatos DASH podem reproduzir em qualidades mais altas. Os formatos antigos estão limitados a um máximo de 360p, mas usam menos largura de banda. Os formatos de áudio são apenas para reproduções de áudio (sem vídeo).\n    Scroll Playback Rate Over Video Player: Com o cursor sobre o vídeo, prima e mantenha premida a tecla Ctrl (tecla Comando em Mac) e desloque a roda do rato para controlar a velocidade de reprodução. Prima e mantenha premida a tecla Ctrl (tecla Comando em Mac) e clique com o botão esquerdo do rato para voltar rapidamente à velocidade de reprodução padrão (1 a não ser que tenha sido alterada nas definições).\n    Skip by Scrolling Over Video Player: Utilizar roda do rato para avançar ou recuar o vídeo, estilo MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: Se ativa, o FreeTube irá obter as subscrições através de RSS em vez do método normal. O formato RSS é mais rápido e não é bloqueado pelo YouTube, mas não disponibiliza certas informações como, por exemplo, a duração dos vídeos, se são emissões em direto e publicações\n\n# Toast Messages\n    Fetch Automatically: Se ativado, o FreeTube irá obter automaticamente as subscrições ao iniciar e ao abrir uma nova janela.\n  External Player Settings:\n    Custom External Player Arguments: Quaisquer argumentos de linha de comando, que quiser passar ao reprodutor externo.\n    Ignore Warnings: Ignorar avisos quando o reprodutor externo escolhido não suporte uma ação (por exemplo, inverter listas de reprodução).\n    Custom External Player Executable: Por omissão, FreeTube assume que o reprodutor externo pode ser encontrado através da variável PATH. Se for preciso, pode escolher um caminho personalizado aqui.\n    External Player: Escolher um reprodutor externo mostra um ícone para abrir o vídeo (lista de reprodução, se suportado) nessa aplicação. Mas tenha em conta de que as definições Invidious não afetam os reprodutores externos.\n    DefaultCustomArgumentsTemplate: \"(Padrão: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: 'Não enviar quaisquer argumentos padrão ao reprodutor externo a não ser o URL (ex: velocidade de reprodução, URL da lista de reprodução...). Os argumentos personalizados serão enviados.'\n  Experimental Settings:\n    Replace HTTP Cache: Desativa a cache HTTP Electron e ativa uma cache de imagem na memória personalizada. Implica o aumento da utilização de memória RAM.\n  Distraction Free Settings:\n    Hide Channels: Introduza o ID de um canal para impedir que os vídeos, listas de reprodução e o próprio canal apareçam na pesquisa, tendências, mais populares e recomendados. O nome do canal introduzido tem que ser uma correspondência exata e diferencia maiúsculas de minúsculas.\n    Hide Subscriptions Live: Esta definição é substituída pela definição global \"{appWideSetting}\", existente na secção \"{subsection}\" de \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Introduza uma palavra, fragmento de palavra ou frase (sem distinção entre maiúsculas e minúsculas) para ocultar todos os vídeos e listas de reprodução cujos títulos originais a contenham em todo o FreeTube, excluindo apenas o histórico, as suas listas de reprodução e os vídeos dentro das listas de reprodução.\n    Hide Videos on Watch: Oculta os vídeos já reproduzidos dos separadores \"Vídeos\", \"Shorts\" e \"Em direto\" nas páginas \"Subscrições\" e \"Canais\". Não afeta o separador \"Início\" nas páginas \"Canais\"\n  SponsorBlock Settings:\n    UseDeArrowTitles: Substituir títulos de vídeo por títulos enviados pelo utilizador a partir do DeArrow.\n    UseDeArrowThumbnails: Substituir miniaturas do vídeo por miniaturas DeArrow.\nLocal API Error (Click to copy): Erro na API local (clique para copiar)\nInvidious API Error (Click to copy): Erro na API Invidious (clique para copiar)\nFalling back to Invidious API: Ocorreu um erro e a API Invidious será utilizada\nFalling back to Local API: Ocorreu um erro e a API local será utilizada\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Este vídeo não está disponível porque faltam formatos. Isto pode acontecer devido à indisponibilidade no seu país.\nLoop is now disabled: Repetição desativada\nLoop is now enabled: Repetição ativada\nShuffle is now disabled: Reprodução aleatória desativada\nShuffle is now enabled: Reprodução aleatória ativada\nPlaying Next Video: A reproduzir o vídeo seguinte\nPlaying Previous Video: A reproduzir o vídeo anterior\nPlaying next video in 5 seconds. Click to cancel.: A reproduzir o vídeo seguinte em 5 segundos. Clique para cancelar.\nCanceled next video autoplay: Reprodução automática cancelada\n'The playlist has ended. Enable loop to continue playing': 'A lista de reprodução chegou ao fim. Ative a repetição para continuar'\n\nYes: Sim\nNo: Não\nThe playlist has been reversed: A lista de reprodução foi invertida\nPlaying Next Video Interval: A reproduzir o vídeo seguinte imediatamente. Clique para cancelar. | A reproduzir o vídeo seguinte em {nextVideoInterval} segundo. Clique para cancelar. | A reproduzir o vídeo seguinte em {nextVideoInterval} segundos. Clique para cancelar.\nMore: Mais\nUnknown YouTube url type, cannot be opened in app: O tipo de URL YouTube é desconhecido e não pode ser aberto na aplicação\nOpen New Window: Abrir nova janela\nDefault Invidious instance has been cleared: A instância Invidious padrão foi removida\nDefault Invidious instance has been set to {instance}: A instância Invidious padrão foi definida para {instance}\nExternal link opening has been disabled in the general settings: A abertura de hiperligações externas foi desativada nas definições\nSearch Bar:\n  Clear Input: Limpar entrada\n  Remove: Remover\nAre you sure you want to open this link?: Tem a certeza de que deseja abrir esta hiperligação?\nNew Window: Nova janela\nChannels:\n  Channels: Canais\n  Title: Lista de canais\n  Search bar placeholder: Procurar canais\n  Count: '{number} canais encontrados.'\n  Empty: A lista de canais está vazia.\n  Unsubscribe Prompt: Tem a certeza de que pretende cancelar a subscrição em \"{channelName}\"?\nScreenshot Success: Captura de ecrã guardada\nScreenshot Error: Erro ao capturar o ecrã. {error}\nChapters:\n  Chapters: Capítulos\n  Key Moments: Momentos-chave\nPreferences: Preferências\nClipboard:\n  Copy failed: Falha ao copiar para a área de transferência\n  Cannot access clipboard without a secure connection: Não é possível aceder à área de transferência sem uma conexão segura\nOk: OK\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Esta 'hashtag' não tem quaisquer vídeos\nGo to page: Ir para {page}\nChannel Hidden: '{channel} adicionado ao filtro do canal'\nChannel Unhidden: '{channel} removido do filtro do canal'\nClose Banner: Fechar banner\nFeed:\n  Feed Last Updated: 'Última atualização de {feedName}: {date}'\n  Refresh Feed: Recarregar {subscriptionName}\nAge Restricted:\n  This video is age restricted: Este vídeo tem restrições de idade\n  This channel is age restricted: Este canal tem restrições de idade\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Legendas\n    Closed Captions: Legendas de áudio\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nova\n    3D: 3D\nSearch character limit: 'A pesquisa excede o limite de {searchCharacterLimit} caracteres permitidos'\nYes, Open Link: Sim, abrir hiperligação\nCancel: Cancelar\ncheckmark: ✓\nMoments Ago: há momentos\nYes, Delete: Sim, eliminar\nYes, Restart: Sim, reiniciar\nDisplay Label: '{label}: {value}'\nTag already exists: '\"{tagName}\" já existe'\nKeyboardShortcutPrompt:\n  Volume Down: Diminuir volume\n  Play: Alternar entre reprodução / pausa\n  Sections:\n    Video:\n      General: Vídeo: geral\n      Playback: Vídeo: reprodução\n    App:\n      Situational: 'Aplicação: situacional'\n      General: Aplicação: geral\n  Picture in Picture: Alternar o modo de imagem na imagem\n  Keyboard Shortcuts: Atalhos de teclado\n  Stats: Mostrar estatísticas do vídeo\n  Fullscreen: Alternar ecrã completo\n  Large Rewind: Retroceder 10 segundos / retroceder vídeo com base na velocidade de reprodução do vídeo atual\n  Large Fast Forward: Avançar 10 segundos / avanço rápido do vídeo com base na velocidade de reprodução do vídeo atual\n  Minimize Window: Minimizar janela\n  Close Window: Fechar janela\n  Toggle Developer Tools: Alternar ferramentas de programador\n  Reset Zoom: Repor o nível de ampliação / escala da interface\n  Zoom In: Ampliar\n  Zoom Out: Diminuir\n  Small Fast Forward: Avanço rápido de X segundos com base no intervalo de avanço rápido e na velocidade de reprodução de vídeo atual\n  Mute: Ativar ou desativar som\n  Decrease Video Speed: Diminuir a velocidade do vídeo com base no intervalo da velocidade de reprodução de vídeo\n  Increase Video Speed: Aumentar a velocidade do vídeo com base no intervalo da velocidade de reprodução de vídeo\n  Full Window: Alternar modo janela inteira\n  Next Frame: Fotograma seguinte (durante a pausa)\n  Small Rewind: Retroceder X segundos com base no intervalo de retrocesso e na velocidade de reprodução de vídeo atual\n  Last Chapter: Último capítulo\n  Next Chapter: Próximo capítulo\n  Show Keyboard Shortcuts: Mostrar atalhos de teclado\n  History Backward: Retroceder uma página\n  History Forward: Avançar uma página\n  New Window: Criar uma nova janela\n  Navigate to Settings: Navegar para a página Definições\n  Navigate to History: Navegar para a página Histórico\n  Refresh: Atualizar o feed com o conteúdo mais recente\n  Focus Secondary Search: Concentrar na barra de pesquisa secundária (se existir)\n  Captions: Ativar ou desativar legendas\n  Theatre Mode: Alternar modo teatro\n  Take Screenshot: Tirar uma captura de ecrã\n  Focus Search: Concentrar na barra de pesquisa\n  Search in New Window: Pesquisar numa nova janela\n  Last Frame: Fotograma anterior (durante a pausa)\n  Volume Up: Aumentar volume\n  Skip by Tenths: Avançar ou recuar o vídeo por percentagem (3 saltos para 30% da duração)\n  Home: Voltar ao início do vídeo\n  End: Avançar para o final do vídeo\n  Skip to Next Video: Avançar para o próximo vídeo da lista de reprodução atual ou para o próximo vídeo recomendado\n  Skip to Previous Video: Voltar para o vídeo anterior da lista de reprodução atual\nshortcutLabelSeparator: ｜\nKeys:\n  arrowdown: Seta para baixo\n  arrowright: Seta para a direita\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Mais\n  arrowleft: Seta para a esquerda\n  arrowup: Seta para cima\nAutoplay Interruption Timer: Reprodução automática cancelada devido a {autoplayInterruptionIntervalHours} horas de inatividade\nTrimmed input must be at least N characters long: A entrada cortada deve ter pelo menos 1 carácter | A entrada cortada deve ter pelo menos {length} caracteres\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: Clique com o botão direito do rato ou mantenha-o premido para ver o histórico\nDescription:\n  Expand Description: '...mais'\n  Collapse Description: Mostrar menos\n"
  },
  {
    "path": "static/locales/pt.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Português'\n\n# Webkit Menu Bar\nFile: 'Ficheiro'\nQuit: 'Sair'\nEdit: 'Editar'\nUndo: 'Desfazer'\nRedo: 'Refazer'\nCut: 'Cortar'\nCopy: 'Copiar'\nPaste: 'Colar'\nDelete: 'Eliminar'\nSelect all: 'Selecionar tudo'\nToggle Developer Tools: 'Comutar ferramentas de desenvolvimento'\nActual size: 'Tamanho real'\nZoom in: 'Ampliar'\nZoom out: 'Reduzir'\nToggle fullscreen: 'Alternar ecrã completo'\nWindow: 'Janela'\nMinimize: 'Minimizar'\nClose: 'Fechar'\nBack: 'Recuar'\nForward: 'Avançar'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Vídeos'\n  Shorts: Shorts\n  Live: Em direto\n  Posts: Publicações\n  Sort By: Ordenar por\n\n  Counts:\n    Channel Count: 1 canal | {count} canais\n    Video Count: 1 vídeo | {count} vídeos\n    Subscriber Count: 1 subscritor | {count} subscritores\n    View Count: 1 visualização | {count} visualizações\n    Watching Count: 1 espectadores | {count} espectadores\n    Like Count: 1 gosto | {count} gostos\n    Comment Count: 1 comentários | {count} comentários\nVersion {versionNumber} is now available!  Click for more details: 'A versão {versionNumber} está disponível! Clique aqui para mais informações.'\nDownload From Site: 'Descarregar do site'\nA new blog is now available, {blogTitle}. Click to view more: 'Está disponível um novo blogue, {blogTitle}. Clique para ver mais.'\n\n# Search Bar\nSearch / Go to URL: 'Pesquisar/Ir para o URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtros de pesquisa'\n  Sort By:\n    Most Relevant: 'Mais relevantes'\n    Rating: 'Avaliação'\n    Upload Date: 'Data de publicação'\n    View Count: 'Visualizações'\n  Time:\n    Time: 'Tempo'\n    Any Time: 'Sempre'\n    Last Hour: 'Última hora'\n    Today: 'Hoje'\n    This Week: 'Esta semana'\n    This Month: 'Este mês'\n    This Year: 'Este ano'\n  Type:\n    Type: 'Tipo'\n    All Types: 'Todos os tipos'\n    Videos: 'Vídeos'\n    Channels: 'Canais'\n    #& Playlists\n    Movies: Filmes\n  Duration:\n    Duration: 'Duração'\n    All Durations: 'Todas as durações'\n    Short (< 4 minutes): 'Curto (< 4 minutos)'\n    Long (> 20 minutes): 'Longo (> 20 minutos)'\n  # On Search Page\n    Medium (4 - 20 minutes): Médio (4 - 20 minutos)\n  Search Results: 'Resultados'\n  Fetching results. Please wait: 'A procurar. Por favor aguarde.'\n  Fetch more results: 'Mais resultados'\n# Sidebar\n  There are no more results for this search: Não existem mais resultados\n  Features:\n    Creative Commons: Creative Commons\n    Features: Funcionalidades\n    HD: HD\n    Subtitles: Legendas\n    3D: 3D\n    Location: Localização\n    Live: Em direto\n    4K: 4K\n    360 Video: Vídeo 360\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Limpar filtros\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Subscrições'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'A sua lista de subscrições está vazia. Se quiser importar subscrições, pode aceder às definições de dados e selecionar Importar subscrições. Em alternativa, pode procurar os canais e efetuar a subscrição.'\n  Load More Videos: Carregar mais vídeos\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Este perfil contém um elevado número de subscrições. A forçar utilização de RSS para evitar que a sua rede seja bloqueada.\n  Error Channels: Canais com erro\n  Empty Channels: Os canais subscritos não têm, atualmente, quaisquer vídeos.\n  Disabled Automatic Fetching: Desativou a atualização automática de subscrições. Recarregue as subscrições para as ver aqui.\n  Subscriptions Tabs: Separadores de subscrições\n  All Subscription Tabs Hidden: Todos os separadores de subscrição estão ocultos. Para ver o conteúdo aqui, desoculte alguns separadores na secção \"{subsection}\" em \"{settingsSection}\".\n  Load More Posts: Carregar mais publicações\n  Empty Posts: Os canais subscritos não tem, atualmente, quaisquer publicações.\nTrending:\n  Trending: 'Tendências'\n  Trending Tabs: Separadores de tendências\n  Gaming: Jogos\n  Sports: Esportes\nMost Popular: 'Mais populares'\nPlaylists: 'Listas de reprodução'\nUser Playlists:\n  Your Playlists: 'As minhas listas de reprodução'\n  Search bar placeholder: Procurar listas de reprodução\n  Empty Search Message: Não há vídeos nesta lista de reprodução que coincidam com a sua pesquisa\n  This playlist currently has no videos.: Esta lista de reprodução não tem, atualmente, quaisquer vídeos.\n  Create New Playlist: Criar nova lista de reprodução\n  Add to Playlist: Adicionar à lista de reprodução\n  Remove from Playlist: Remover da lista de reprodução\n  Playlist Name: Nome da lista de reprodução\n  Save Changes: Guardar alterações\n  Cancel: Cancelar\n  Copy Playlist: Copiar lista de reprodução\n  Remove Watched Videos: Remover vídeos reproduzidos\n  Delete Playlist: Eliminar lista de reprodução\n  Are you sure you want to delete this playlist? This cannot be undone: Tem certeza de que pretende eliminar esta lista de reprodução? A remoção não pode ser revertida.\n  Sort By:\n    LatestCreatedFirst: Data de criação (mais recente)\n    EarliestCreatedFirst: Data de criação (mais antiga)\n    EarliestUpdatedFirst: Data de atualização (mais antiga)\n    LatestPlayedFirst: Data de reprodução (mais recente)\n    EarliestPlayedFirst: Data de reprodução (mais antiga)\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestUpdatedFirst: Data de atualização (mais recente)\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: Este vídeo não pode ser movido para cima.\n      This video cannot be moved down.: Este vídeo não pode ser movido para baixo.\n      There was a problem with removing this video: Ocorreu um erro ao remover este vídeo\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Alguns vídeos da lista de reprodução ainda não foram carregados. Clique aqui para continuar.\n      Playlist has been updated.: A lista de reprodução foi atualizada.\n      \"{videoCount} video(s) have been removed\": 1 vídeo foi removido | {videoCount} vídeos foram removidos\n      There were no videos to remove.: Não existiam vídeos para remover.\n      Video has been removed: O vídeo foi removido\n      Playlist name cannot be empty. Please input a name.: O nome da lista de reprodução não pode estar vazio. Introduza um nome.\n      There was an issue with updating this playlist.: Ocorreu um erro ao atualizar esta lista de reprodução.\n      This playlist is protected and cannot be removed.: Esta lista de reprodução está protegida e não pode ser removida.\n      Playlist {playlistName} has been deleted.: A lista de reprodução {playlistName} foi eliminada.\n      This playlist does not exist: Esta lista de reprodução não existe\n      This playlist is now used for quick bookmark: Esta lista de reprodução é agora utilizada como marcador rápido.\n      This playlist is already being used for quick bookmark.: Esta lista de reprodução já está a ser usada como marcador rápido.\n      This playlist has a video with a duration error: Esta lista de reprodução contém, pelo menos, um vídeo sem duração. Será ordenada como se a sua duração fosse zero.\n      Reverted to use {oldPlaylistName} for quick bookmark: '{oldPlaylistName} é agora utilizada como marcador rápido'\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Esta lista de reprodução é agora usada como marcador ao invés de {oldPlaylistName}. Clique aqui para desfazer.\n      Video has been removed. Click here to undo.: O vídeo foi removido. Clique aqui para desfazer.\n    Search for Videos: Procurar vídeos\n  AddVideoPrompt:\n    Search in Playlists: Procurar nas listas de reprodução\n    Save: Guardar\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Vídeo (s) adicionados a 1 lista de reprodução| Vídeo (s) adicionados a {playlistCount} lista de reprodução\"\n      You haven't selected any playlist yet.: Ainda não selecionou uma lista de reprodução.\n    Select a playlist to add your N videos to: Selecione uma lista de reprodução à qual adicionar o seu vídeo | Selecione uma lista de reprodução à qual adicionar os seus {videoCount} vídeos\n    N playlists selected: '{playlistCount} selecionados'\n    Added {count} Times: Já adicionado | Adicionado {count} vezes\n    Allow Adding Duplicate Video(s): Permitir duplicação de vídeos\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} vídeos serão adicionados'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} vídeos já foram adicionados'\n  CreatePlaylistPrompt:\n    New Playlist Name: Nome da lista de reprodução\n    Create: Criar\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Já existe uma lista de reprodução com este nome. Por favor, escolha um nome diferente.\n      Playlist {playlistName} has been successfully created.: A lista de reprodução {playlistName} foi criada com sucesso.\n      There was an issue with creating the playlist.: Ocorreu um erro ao criar a lista de reprodução.\n  Move Video Up: Mover vídeo para cima\n  You have no playlists. Click on the create new playlist button to create a new one.: Não tem listas de reprodução. Clique em Criar nova lista de reprodução para criar uma.\n  Move Video Down: Mover vídeo para baixo\n  Edit Playlist Info: Editar info da lista de reprodução\n  Playlist Description: Descrição da lista de reprodução\n  Add to Favorites: Adicionar a {playlistName}\n  Remove from Favorites: Remover de {playlistName}\n  Enable Quick Bookmark With This Playlist: Ativar marcador rápido para esta lista de reprodução\n  Playlists with Matching Videos: Listas de reprodução coincidentes\n  Quick Bookmark Enabled: Marcador rápido ativado\n  Remove Duplicate Videos: Remover duplicados\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Tem a certeza de que pretende remover 1 vídeo reproduzido desta lista de reprodução? Esta ação não pode ser revertida. | Tem a certeza de que pretende remover {playlistItemCount} vídeos reproduzidos desta lista de reprodução? Esta ação não pode ser revertida.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Tem a certeza de que pretende remover 1 vídeo duplicado desta lista de reprodução? Esta remoção não pode ser revertida. | Tem a certeza de que pretende remover {playlistItemCount} vídeos duplicados desta lista de reprodução? Esta remoção não pode ser revertida.\n  Export Playlist: Exportar lista de reprodução\n  The playlist has been successfully exported: Lista de reprodução exportada com sucesso\n  Cannot delete the quick bookmark target playlist.: Não é possível eliminar a lista de reprodução de destino do marcador rápido.\n  TotalTimePlaylist: 'Duração total: {duration}'\n  Export list of URLs: Exportar lista de URLs\nHistory:\n  # On History Page\n  History: 'Histórico'\n  Watch History: 'Histórico de reprodução'\n  Your history list is currently empty.: 'O seu histórico está vazio.'\n  Search bar placeholder: Procurar no histórico\n  Empty Search Message: Não há vídeos no histórico que coincidam com a sua pesquisa\n  Case Sensitive Search: Diferenciar maiúsculas e minúsculas\n  DateOldestHistory: Data de reprodução (mais antiga)\n  DateNewestHistory: Data de reprodução (mais recente)\nSettings:\n  # On Settings Page\n  Settings: 'Definições'\n  General Settings:\n    General Settings: 'Geral'\n    Check for Updates: 'Procurar atualizações'\n    Check for Latest Blog Posts: 'Verificar se há novas publicações no blogue'\n    Fallback to Non-Preferred Backend on Failure: 'Utilizar sistema de ligação secundário, em caso de falha'\n    Enable Search Suggestions: 'Ativar sugestões de pesquisa'\n    Default Landing Page: 'Página inicial'\n    Locale Preference: 'Idioma'\n    Preferred API Backend:\n      Preferred API Backend: 'API preferencial'\n      Local API: 'API local'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Exibição dos vídeos'\n      Grid: 'Grelha'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferências de miniaturas'\n      Default: 'Padrão'\n      Beginning: 'Início'\n      Middle: 'Centro'\n      End: 'Final'\n      Hidden: Oculta\n      Blur: Desfocar\n    Region for Trending: 'Região para as tendências'\n        #! List countries\n    View all Invidious instance information: Mostrar toda a informação sobre esta instância Invidious\n    Clear Default Instance: Remover instância padrão\n    Set Current Instance as Default: Utilizar instância atual como padrão\n    Current instance will be randomized on startup: A instância, ao iniciar, será escolhida aleatoriamente\n    No default instance has been set: Não foi definida uma instância\n    The currently set default instance is {instance}: A instância padrão é {instance}\n    Current Invidious Instance: Instância Invidious atual\n    System Default: Definido no sistema\n    External Link Handling:\n      External Link Handling: Gestão de hiperligações externas\n      Open Link: Abrir hiperligação\n      Ask Before Opening Link: Perguntar antes de abrir a hiperligação\n      No Action: Nenhuma ação\n    Auto Load Next Page:\n      Label: Carregar seguinte automaticamente\n      Tooltip: Carrega as páginas e comentários automaticamente.\n    Open Deep Links In New Window: Abrir URLs passados para o FreeTube numa nova janela\n    Minimize to system tray: Minimizar para a bandeja\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Utilizar cor principal na barra superior'\n    Base Theme:\n      Base Theme: 'Tema base'\n      Black: 'Preto'\n      Dark: 'Escuro'\n      Light: 'Claro'\n      Dracula: 'Drácula'\n      System Default: Definição do sistema\n      Catppuccin Mocha: Cappuccino mocha\n      Pastel Pink: Rosa pastel\n      Hot Pink: Rosa choque\n      Nordic: Nórdico\n      Solarized Dark: Escuro solar\n      Solarized Light: Claro solar\n      Gruvbox Dark: Gruvbox Escuro\n      Gruvbox Light: Luz Gruvbox\n      Catppuccin Frappe: Frapé de catppuccin\n      Everforest Dark Hard: Everforest Escuro Duro\n      Everforest Dark Medium: Everforest Escuro Médio\n      Everforest Dark Low: Everforest Escuro Baixo\n      Everforest Light Hard: Everforest Light Duro\n      Everforest Light Medium: Everforest Light Médio\n      Everforest Light Low: Everforest Luz Baixa\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Cor principal'\n      Red: 'Vermelho'\n      Pink: 'Rosa'\n      Purple: 'Roxo'\n      Deep Purple: 'Roxo escuro'\n      Indigo: 'Índigo'\n      Blue: 'Azul'\n      Light Blue: 'Azul claro'\n      Cyan: 'Ciano'\n      Teal: 'Azul esverdeado'\n      Green: 'Verde'\n      Light Green: 'Verde claro'\n      Lime: 'Lima'\n      Yellow: 'Amarelo'\n      Amber: 'Âmbar'\n      Orange: 'Laranja'\n      Deep Orange: 'Laranja escuro'\n      Dracula Cyan: 'Drácula ciano'\n      Dracula Green: 'Drácula verde'\n      Dracula Orange: 'Drácula laranja'\n      Dracula Pink: 'Drácula rosa'\n      Dracula Purple: 'Drácula roxo'\n      Dracula Red: 'Drácula vermelho'\n      Dracula Yellow: 'Drácula amarelo'\n      Catppuccin Mocha Rosewater: Cappuccino mocha rosewater\n      Catppuccin Mocha Flamingo: Cappuccino mocha flamingo\n      Catppuccin Mocha Pink: Cappuccino mocha rosa\n      Catppuccin Mocha Mauve: Cappuccino mocha mauve\n      Catppuccin Mocha Red: Cappuccino mocha vermelho\n      Catppuccin Mocha Maroon: Cappuccino mocha castanho\n      Catppuccin Mocha Peach: Cappuccino mocha pêssego\n      Catppuccin Mocha Yellow: Cappuccino mocha amarelo\n      Catppuccin Mocha Green: Cappuccino mocha verde\n      Catppuccin Mocha Teal: Cappuccino mocha azul esverdeado\n      Catppuccin Mocha Sky: Cappuccino mocha céu\n      Catppuccin Mocha Sapphire: Cappuccino mocha safira\n      Catppuccin Mocha Blue: Cappuccino mocha azul\n      Catppuccin Mocha Lavender: Cappuccino mocha lavanda\n      Solarized Yellow: Amarelo solar\n      Solarized Orange: Laranja solar\n      Solarized Red: Vermelho solar\n      Solarized Magenta: Magenta solar\n      Solarized Violet: Violeta solar\n      Solarized Blue: Azul solar\n      Solarized Cyan: Ciano solar\n      Solarized Green: Verde solar\n      Catppuccin Frappe Sapphire: Frapé de Catppuccin safira\n      Gruvbox Light Red: Gruvbox vermelho claro\n      Catppuccin Frappe Red: Frapé de Catppuccin vermelho\n      Catppuccin Frappe Rosewater: Frapé de Catppuccin com água de rosas\n      Catppuccin Frappe Pink: Frapé de Catppuccin com rosas\n      Gruvbox Dark Green: Gruvbox verde escuro\n      Catppuccin Frappe Mauve: Frapé de Catppuccin Mauve\n      Catppuccin Frappe Lavender: Frapé de Catppuccin lavanda\n      Gruvbox Light Blue: Gruvbox azul claro\n      Catppuccin Frappe Maroon: Frapé de Catppuccin castanho\n      Catppuccin Frappe Blue: Frapé de Catppuccin azul\n      Gruvbox Dark Blue: Gruvbox azul escuro\n      Gruvbox Dark Yellow: Gruvbox amarelo escuro\n      Catppuccin Frappe Flamingo: Frapé de Catppuccin Flamingo\n      Gruvbox Dark Purple: Gruvbox roxo escuro\n      Gruvbox Dark Orange: Gruvbox laranja escuro\n      Gruvbox Light Orange: Gruvbox laranja claro\n      Catppuccin Frappe Peach: Frapé de Catppuccin pêssego\n      Catppuccin Frappe Yellow: Frapé de Catppuccin amarelo\n      Catppuccin Frappe Green: Frapé de Catppuccin verde\n      Catppuccin Frappe Teal: Frapé de Catppuccin verde-azulado\n      Catppuccin Frappe Sky: Frapé de Catppuccin céu\n      Gruvbox Dark Aqua: Gruvbox água escura\n      Gruvbox Light Purple: Gruvbox violeta claro\n      Everforest Light Red: Everforest Vermelho Claro\n      Everforest Dark Green: Everforest Verde Escuro\n      Everforest Light Purple: Everforest Roxo Claro\n      Everforest Dark Red: Everforest Vermelho Escuro\n      Everforest Dark Orange: Everforest Laranja Escuro\n      Everforest Dark Yellow: Everforest Amarelo Escuro\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Azul Escuro\n      Everforest Dark Purple: Everforest Roxo escuro\n      Everforest Light Orange: Everforest Laranja Claro\n      Everforest Light Yellow: Everforest Amarelo Claro\n      Everforest Light Green: Everforest Verde Claro\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Light Blue: Everforest Azul Claro\n    Secondary Color Theme: 'Cor secundária'\n        #* Main Color Theme\n    UI Scale: Escala da interface\n    Disable Smooth Scrolling: Desativar deslocação suave\n    Expand Side Bar by Default: Expandir barra lateral por definição\n    Hide Side Bar Labels: Ocultar texto na barra lateral\n    Hide FreeTube Header Logo: Ocultar logotipo FreeTube no topo\n  Player Settings:\n    Player Settings: 'Reprodutor'\n    Play Next Video: 'Reproduzir automaticamente os vídeos recomendados'\n    Turn on Subtitles by Default: 'Ativar legendas por predefinição'\n    Autoplay Videos: 'Reproduzir vídeos automaticamente'\n    Proxy Videos Through Invidious: 'Utilizar Invidious com proxy'\n    Autoplay Playlists: 'Reproduzir automaticamente vídeos da lista de reprodução'\n    Enable Theatre Mode by Default: 'Ativar modo cinema por omissão'\n    Default Volume: 'Volume padrão'\n    Default Playback Rate: 'Velocidade de reprodução padrão'\n    Default Video Format:\n      Default Video Format: 'Formato de vídeo padrão'\n      Dash Formats: 'Formatos DASH'\n      Legacy Formats: 'Formatos antigos'\n      Audio Formats: 'Formatos de áudio'\n    Default Quality:\n      Default Quality: 'Qualidade padrão'\n      Auto: 'Automática'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: Tempo a avançar/recuar\n    Next Video Interval: Temporizador de contagem decrescente de reprodução automática\n    Display Play Button In Video Player: Mostrar botão \"Reproduzir\" no reprodutor\n    Scroll Volume Over Video Player: Alterar volume com a roda do rato por cima do reprodutor\n    Scroll Playback Rate Over Video Player: Alterar velocidade de reprodução com a roda do rato\n    Max Video Playback Rate: Velocidade máxima de reprodução\n    Video Playback Rate Interval: Intervalo entre velocidades de reprodução\n    Screenshot:\n      Enable: Permitir capturas de ecrã\n      Format Label: Formato das capturas de ecrã\n      Quality Label: Qualidade da captura de ecrã\n      Folder Button: Selecionar pasta\n      File Name Label: Padrão para nome de ficheiro\n      Error:\n        Forbidden Characters: Caracteres proibidos\n        Empty File Name: Nome de ficheiro vazio\n      File Name Tooltip: 'Pode utilizar estas variáveis: %Y ano com 4 dígitos, %M mês com 2 dígitos, %D dia com 2 dígitos, %H hora com 2 dígitos, %N minuto com 2 dígitos, %S segundos com 2 dígitos, %T milissegundos com 3 dígitos, %s segundos do vídeo, %t milissegundos do vídeo com 3 dígitos, %i ID do vídeo.'\n      Folder Label: Pasta para as capturas de ecrã\n      Ask Path: Perguntar onde guardar\n    Enter Fullscreen on Display Rotate: Ativar modo de ecrã completo ao rodar o ecrã\n    Skip by Scrolling Over Video Player: Avançar ou recuar no vídeo com a roda do rato\n    Default Viewing Mode:\n      Full Screen: Ecrã completo\n      Picture in Picture: Imagem sobre imagem\n      External Player: Reprodutor externo ({externalPlayerName})\n      Default Viewing Mode: Modo de visualização predefinido\n      Theater: Teatro\n    Autoplay Interruption Timer: Temporizador de interrupção da reprodução automática\n  Privacy Settings:\n    Privacy Settings: 'Privacidade'\n    Remember History: 'Memorizar histórico de reprodução'\n    Save Watched Progress: 'Guardar progresso de reprodução'\n    Clear Search Cache: 'Limpar cache de pesquisas'\n    Are you sure you want to clear out your search cache?: 'Tem a certeza de que pretende limpar a sua cache de pesquisas?'\n    Search cache has been cleared: 'Cache de pesquisas limpa'\n    Remove Watch History: 'Limpar histórico de reprodução'\n    Are you sure you want to remove your entire watch history?: 'Tem a certeza de que pretende limpar o histórico de reproduções?'\n    Watch history has been cleared: 'Histórico de reproduções limpo'\n    Remove All Subscriptions / Profiles: 'Remover todas as subscrições / perfis'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Tem a certeza de que pretende remover todas as suas subscrições e perfis? Esta ação não pode ser revertida.'\n    Save Watched Videos With Last Viewed Playlist: Guardar vídeos reproduzidos com a última lista de reprodução\n    Remove All Playlists: Remover todas as listas de reprodução\n    All playlists have been removed: Todas as listas de reprodução foram removidas\n    Are you sure you want to remove all your playlists?: Tem a certeza de que pretende remover todas as suas listas de reprodução?\n    Search history and cache have been cleared: O histórico de pesquisa e a cache foram limpos\n    Are you sure you want to clear out your search history and cache?: Tem a certeza de que pretende limpar o histórico de pesquisa e a cache?\n    Remember Search History: Memorizar histórico de pesquisa\n    Clear Search History and Cache: Limpar o histórico de pesquisa e a cache\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automático\n        Semi-auto: Semiautomático\n        Never: Nunca\n      Tooltip: \"Automático = Guarda sempre: ao sair da página do vídeo, quando o vídeo termina ou se ocorrer um erro (por exemplo: limite de taxa atingido ou sessão expirada). Semiautomático = Igual ao modo Automático exceto ao sair da página do vídeo e permite guardar o progresso manualmente através do botão \\\"Guardar progresso de reprodução\\\", localizado abaixo do reprodutor.\"\n  Subscription Settings:\n    Subscription Settings: 'Subscrição'\n    Fetch Feeds from RSS: 'Obter subscrições através de RSS'\n    Fetch Automatically: Obter fontes automaticamente\n    Confirm Before Unsubscribing: Impedir cancelamento acidental de subscrições\n    To: A\n    'Limit the number of videos displayed for each channel': Limitar o número de vídeos apresentados para cada canal\n  Data Settings:\n    Data Settings: 'Dados'\n    Select Export Type: 'Selecione o tipo de exportação'\n    Import Subscriptions: 'Importar subscrições'\n    Export Subscriptions: 'Exportar subscrições'\n    Export FreeTube: 'Exportar FreeTube'\n    Export YouTube: 'Exportar YouTube'\n    Export NewPipe: 'Exportar NewPipe'\n    Import History: 'Importar histórico'\n    Export History: 'Exportar histórico'\n    Profile object has insufficient data, skipping item: 'O perfil tem dados em falta, a ignorar'\n    All subscriptions and profiles have been successfully imported: 'Todas as subscrições e perfis foram importados com sucesso'\n    All subscriptions have been successfully imported: 'Todas as subscrições foram importadas com sucesso'\n    Invalid subscriptions file: 'Ficheiro de subscrições inválido'\n    Invalid history file: 'Ficheiro de histórico inválido'\n    Subscriptions have been successfully exported: 'As subscrições foram exportadas com sucesso'\n    History object has insufficient data, skipping item: 'O histórico tem dados em falta, a ignorar'\n    All watched history has been successfully imported: 'O histórico de reprodução foi importado com sucesso'\n    All watched history has been successfully exported: 'O histórico de reprodução foi exportado com sucesso'\n    Unable to read file: 'Não foi possível ler o ficheiro'\n    Unable to write file: 'Não foi possível escrever o ficheiro'\n    Unknown data key: 'Chave de dados desconhecida'\n    How do I import my subscriptions?: 'Como importar as minhas subscrições?'\n    Manage Subscriptions: Gerir subscrições\n    Import Playlists: Importar listas de reprodução\n    Export Playlists: Exportar listas de reprodução\n    Playlist insufficient data: Dados insuficientes para a lista de reprodução \"{playlist}\", a ignorar\n    All playlists has been successfully imported: Todas as listas de reprodução foram importadas com sucesso\n    All playlists has been successfully exported: Todas as listas de reprodução foram exportadas com sucesso\n    Subscription File: Ficheiro de subscrição\n    History File: Ficheiro de histórico\n    Playlist File: Ficheiro de lista de reprodução\n    Export Playlists For Older FreeTube Versions:\n      Label: Exportar listas de reprodução para versões mais antigas do FreeTube\n      Tooltip: \"Esta opção exporta os vídeos de todas as listas de reprodução para uma lista de reprodução chamada \\\"Favoritos\\\".\\nComo exportar e importar vídeos em listas de reprodução para uma versão mais antiga do FreeTube:\\n1. Exporte as suas listas de reprodução com esta opção ativada.\\n2. Elimine todas as listas de reprodução existentes usando a opção \\\"Remover todas as listas de reprodução\\\" em \\\"Definições de privacidade\\\".\\n3. Abra a versão mais antiga do FreeTube e importe as listas de reprodução.\"\n\n    Search history file: Arquivo de histórico de pesquisa\n    Search history: Histórico de pesquisa\n    Import search history: Importar histórico de pesquisa\n    Export search history: Exportar histórico de pesquisa\n    All search history has been successfully imported: Histórico de pesquisa importado com sucesso\n    All search history has been successfully exported: Histórico de pesquisa exportado com sucesso\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificar se um anúncio for ignorado\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL da API SponsorBlock (padrão é https://sponsor.ajay.app)\n    Enable SponsorBlock: Ativar bloqueio da publicidade SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Opção para ignorar\n      Auto Skip: Ignorar automaticamente\n      Show In Seek Bar: Mostrar na barra de progresso\n      Prompt To Skip: Perguntar se quero ignorar\n      Do Nothing: Nada fazer\n    Category Color: Cor da categoria\n    UseDeArrowTitles: Utilizar títulos de vídeo DeArrow\n    UseDeArrowThumbnails: Usar 'DeArrow' para miniaturas\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL da API do gerador de miniaturas DeArrow (padrão: https://dearrow-thumb.ajay.app)'\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Erro ao obter informações da rede. O seu proxy está configurado corretamente?\n    City: Cidade\n    Region: Região\n    Country: País\n    Ip: IP\n    Your Info: A sua informação\n    Test Proxy: Testar proxy\n    Clicking on Test Proxy will send a request to: Carregar em \"Testar proxy\" irá enviar um pedido a\n    Proxy Port Number: Porta do proxy\n    Proxy Host: Servidor do proxy\n    Proxy Protocol: Protocolo do proxy\n    Enable Tor / Proxy: Ativar Tor / proxy\n    Proxy Settings: Proxy\n    Proxy Warning: O FreeTube não tem um proxy incorporado, mas pode conectar-se a um proxy externo, como um que esteja a ser executado na sua máquina, como o Tor, ou um proxy externo, como um proxy SOCKS5 fornecido por algumas VPNs. Se estiver ativado, certifique-se de que o seu proxy / Tor está configurado corretamente, ou o FreeTube não conseguirá obter quaisquer dados.\n    Proxy Username: Nome de utilizador do proxy\n    Proxy Password: Palavra-passe do proxy\n  Distraction Free Settings:\n    Hide Active Subscriptions: Ocultar subscrições ativas\n    Hide Live Chat: Ocultar conversas em direto\n    Hide Playlists: Ocultar listas de reprodução\n    Hide Popular Videos: Ocultar vídeos populares\n    Hide Trending Videos: Ocultar tendências\n    Hide Recommended Videos: Ocultar vídeos recomendados\n    Hide Comment Likes: Ocultar \"gostos\" em comentários\n    Hide Channel Subscribers: Ocultar número de subscritores\n    Hide Video Likes And Dislikes: Ocultar \"gostos\" em vídeos\n    Hide Video Views: Ocultar visualizações\n    Distraction Free Settings: Distrações\n    Hide Video Description: Ocultar descrição dos vídeos\n    Hide Sharing Actions: Ocultar ações de partilha\n    Hide Videos on Watch: 'Ocultar vídeos reproduzidos'\n    Hide Live Streams: Ocultar transmissões em direto\n    Hide Comments: Ocultar comentários\n    Hide Chapters: Ocultar capítulos\n    Hide Upcoming Premieres: Ocultar próximas estreias\n    Hide Channels: Ocultar vídeos dos canais\n    Hide Channels Placeholder: ID do canal\n    Display Titles Without Excessive Capitalisation: Mostrar títulos sem maiúsculas ou pontuação em excesso\n    Hide Featured Channels: Ocultar canais em destaque\n    Hide Channel Playlists: Ocultar separador \"Listas de reprodução\" nos canais\n    Hide Channel Shorts: Ocultar separador \"Shorts\" dos canais\n    Sections:\n      Side Bar: Barra lateral\n      Channel Page: Página do canal\n      Watch Page: Página de reprodução\n      General: Geral\n      Subscriptions Page: Página de subscrições\n    Hide Channel Podcasts: Ocultar separador \"Podcasts\" nos canais\n    Hide Channel Releases: Ocultar separador \"Lançamentos\" nos canais\n    Hide Subscriptions Videos: Ocultar subscrições de vídeos\n    Hide Subscriptions Shorts: Ocultar \"Shorts\" das subscrições\n    Hide Subscriptions Live: Ocultar subscrições em direto\n    Hide Profile Pictures in Comments: Ocultar imagens de perfil nos comentários\n    Hide Channels Invalid: O ID do canal não é válido\n    Hide Channels Disabled Message: Alguns canais foram bloqueados e não foram processados. A funcionalidade está bloqueada enquanto estiver a ocorrer a atualização dos ID.\n    Hide Channels Already Exists: Este ID já existe\n    Hide Channels API Error: Não foi possível obter o utilizador através do ID. Verifique se o ID indicado está correto.\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Palavra, fragmento de palavra ou frase\n    Hide Videos, Playlists and Channels Containing Text: Ocultar vídeos e listas que contenham este texto\n    Show Added Items: Mostrar itens adicionados\n    Hide Channel Home: Ocultar separador “Início” do canal\n    Hide Channel Courses: Ocultar separador \"Cursos\"\n    Hide Channel Posts: Ocultar o separador \"Publicações\" do canal\n    Hide Subscriptions Posts: Ocultar postagens de assinaturas\n  External Player Settings:\n    Custom External Player Arguments: Argumentos do reprodutor externo\n    Custom External Player Executable: Executável do reprodutor externo\n    Ignore Unsupported Action Warnings: Ignorar avisos sobre ações inválidas\n    External Player: Reprodutor externo\n    External Player Settings: Reprodutores externos\n    Players:\n      None:\n        Name: Nenhum\n    Ignore Default Arguments: Ignorar argumentos padrão\n  The app needs to restart for changes to take effect. Restart and apply change?: Tem que reiniciar a aplicação para aplicar as alterações. Reiniciar e aplicar alterações?\n  Parental Control Settings:\n    Hide Unsubscribe Button: Ocultar botão \"Cancelar subscrição\"\n    Show Family Friendly Only: Mostrar apenas \"Para famílias\"\n    Hide Search Bar: Ocultar barra de pesquisa\n    Parental Control Settings: Controlo parental\n    Hide Uploader on Watch page: Ocultar nome do autor na página de reprodução\n  Experimental Settings:\n    Replace HTTP Cache: Substituir cache HTTP\n    Experimental Settings: Experimentais\n    Warning: Estas definições são experimentais e podem provocar falhas se ativadas. É altamente recomendado fazer cópias de segurança. Use por sua conta e risco!\n  Password Dialog:\n    Enter Password To Unlock: Indique a palavra-passe para desbloquear as definições\n    Password: Palavra-passe\n  Password Settings:\n    Password Settings: Palavra-passe\n    Set Password To Prevent Access: Defina uma palavra-passe para impedir o acesso às definições\n    Set Password: Definir palavra-passe\n    Remove Password: Remover palavra-passe\n  Sort Settings Sections (A-Z): Ordenar definições (A-Z)\n  Return to Settings Menu: Voltar para as definições\nAbout:\n  #On About page\n  About: 'Acerca'\n  #& About\n  FAQ: FAQ\n  Blog: Blogue\n  Website: Página web\n  Email: E-mail\n  Donate: Doar\n  these people and projects: estas pessoas e projetos\n  Credits: Créditos\n  Translate: Traduzir\n  room rules: regras da sala\n  Chat on Matrix: Conversa no Matrix\n  Mastodon: Mastodon\n  Please check for duplicates before posting: Antes de reportar, verifique se alguém já reportou o mesmo problema\n  GitHub issues: Problemas no GitHub\n  Report a problem: Reportar um problema\n  FreeTube Wiki: Wiki FreeTube\n  Help: Ajuda\n  GitHub releases: Versões em GitHub\n  Downloads / Changelog: Descargas / alterações\n  Source code: Código-fonte\n  Beta: Beta\n  Discussions: Discussões\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licenciado nos termas da {licenseLink}\n  Please read the {roomRulesLink}: Por favor, leia as {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube apenas é possível com as participações de {creditsPageLink}\nProfile:\n  Profile Select: 'Seleção de perfil'\n  All Channels: 'Todos os canais'\n  Profile Manager: 'Gestor de perfis'\n  Create New Profile: 'Criar novo perfil'\n  Edit Profile: 'Editar perfil'\n  Color Picker: 'Cor'\n  Custom Color: 'Cor personalizada'\n  Profile Preview: 'Pré-visualização do perfil'\n  Create Profile: 'Criar perfil'\n  Update Profile: 'Atualizar perfil'\n  Make Default Profile: 'Tornar no perfil padrão'\n  Delete Profile: 'Eliminar perfil'\n  Are you sure you want to delete this profile?: 'Tem a certeza de que pretende eliminar este perfil?'\n  All subscriptions will also be deleted.: 'Todas as subscrições associadas a este perfil também serão eliminadas.'\n  Your profile name cannot be empty: 'O nome do perfil não pode ficar vazio'\n  Profile has been created: 'Perfil criado'\n  Profile has been updated: 'Perfil atualizado'\n  Your default profile has been set to {profile}: '{profile} é agora o seu perfil padrão'\n  Removed {profile} from your profiles: 'O perfil {profile} foi eliminado'\n  Your default profile has been changed to your primary profile: 'O seu perfil padrão é agora o seu perfil principal'\n  '{profile} is now the active profile': 'Está agora a ver as subscrições do perfil {profile}'\n  Subscription List: 'Lista de subscrições'\n  Other Channels: 'Outros canais'\n  '{number} selected': '{number} selecionado'\n  Select All: 'Selecionar tudo'\n  Select None: 'Cancelar seleção'\n  Delete Selected: 'Eliminar seleção'\n  Add Selected To Profile: 'Adicionar seleção ao perfil'\n  No channel(s) have been selected: 'Nenhum canal foi selecionado'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Este é o seu perfil principal. Tem a certeza de que pretende eliminar os canais selecionados? Os canais serão eliminados de todos os perfis.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Tem a certeza de que pretende eliminar os canais selecionados? Esta ação não vai eliminar os canais dos outros perfis.'\n#On Channel Page\n  Profile Filter: Filtro de perfil\n  Profile Settings: Perfil\n  Toggle Profile List: Alternar lista de perfis\n  Profile Name: Nome do perfil\n  Edit Profile Name: Editar nome do perfil\n  Create Profile Name: Criar nome do perfil\n  Open Profile Dropdown: Abrir menu do perfil\n  Close Profile Dropdown: Fechar menu do perfil\nChannel:\n  Subscribe: 'Subscrever'\n  Unsubscribe: 'Cancelar subscrição'\n  Channel has been removed from your subscriptions: 'O canal foi removido das suas subscrições'\n  Removed subscription from {count} other channel(s): 'Subscrição removida de mais {count} canais'\n  Added channel to your subscriptions: 'Canal adicionado às suas subscrições'\n  Search Channel: 'Procurar canal'\n  Your search results have returned 0 results: 'A pesquisa devolveu 0 resultados'\n  Videos:\n    Videos: 'Vídeos'\n    This channel does not currently have any videos: 'Atualmente, este canal não tem vídeos'\n    Sort Types:\n      Newest: 'Recentes'\n      Oldest: 'Antigos'\n      Most Popular: 'Mais populares'\n  Playlists:\n    Playlists: 'Listas de reprodução'\n    This channel does not currently have any playlists: 'Este canal não tem, atualmente, quaisquer listas de reprodução'\n    Sort Types:\n      Last Video Added: 'Último vídeo adicionado'\n      Newest: 'Recentes'\n      Oldest: 'Antigos'\n  About:\n    About: 'Acerca'\n    Channel Description: 'Descrição do canal'\n    Featured Channels: 'Canais em destaque'\n    Tags:\n      Tags: Etiquetas\n      Search for: Procurar por «{tag}»\n    Details: Detalhes\n    Joined: Aderiu a\n    Location: Localização\n  This channel does not exist: Este canal não existe\n  This channel does not allow searching: Este canal não permite pesquisas\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Este canal tem restrição de idade e, atualmente, não pode ser visto no Free Tube.\n  Channel Tabs: Separadores de canais\n  Posts:\n    This channel currently does not have any posts: Este canal não tem, atualmente, quaisquer publicações\n    Posts: Publicações\n    Hide Answers: Ocultar respostas\n    Reveal Answers: Mostrar respostas\n    votes: '{votes} votos'\n    Video hidden by FreeTube: Freetube ocultou este vídeo\n    View Full Post: Ver publicação na íntegra\n    Viewing Posts Only Supported By Invidious: A visualização de publicações só é suportada pelo Invidious. Aceda ao separador Comunidade de um canal para ver o conteúdo sem o Invidious.\n  Live:\n    Live: Em direto\n    This channel does not currently have any live streams: Este canal não tem, atualmente, qualquer emissão em direto\n  Shorts:\n    This channel does not currently have any shorts: Este canal não tem, atualmente, quaisquer \"Shorts\"\n  Releases:\n    Releases: Lançamentos\n    This channel does not currently have any releases: Este canal não tem, atualmente, quaisquer lançamentos\n  Podcasts:\n    Podcasts: Podcasts\n    This channel does not currently have any podcasts: Este canal não tem, atualmente, quaisquer podcasts\n  Home:\n    View Playlist: Ver lista de reprodução\n    Home: Início\n  Courses:\n    Courses: Cursos\n    This channel does not currently have any courses: Este canal não tem, atualmente, qualquer curso\nVideo:\n  Mark As Watched: 'Marcar como reproduzido'\n  Remove From History: 'Remover do histórico'\n  Video has been marked as watched: 'O vídeo foi marcado como reproduzido'\n  Video has been removed from your history: 'O vídeo foi removido do histórico'\n  Open in YouTube: 'Abrir no YouTube'\n  Copy YouTube Link: 'Copiar hiperligação do YouTube'\n  Open YouTube Embedded Player: 'Abrir reprodutor YouTube nativo'\n  Copy YouTube Embedded Player Link: 'Copiar hiperligação do reprodutor integrado do YouTube'\n  Open in Invidious: 'Abrir no Invidious'\n  Copy Invidious Link: 'Copiar hiperligação Invidious'\n  Views: 'Visualizações'\n  Loop Playlist: 'Repetir lista de reprodução'\n  Shuffle Playlist: 'Baralhar lista de reprodução'\n  Reverse Playlist: 'Inverter lista de reprodução'\n  Previous: 'Anterior'\n  Next: 'Seguinte'\n  Watched: 'Reproduzido'\n  Autoplay: 'Reprodução automática'\n  # As in a Live Video\n  Live: 'Em direto'\n  Live Now: 'Em direto agora'\n  Live Chat: 'Conversa em direto'\n  Enable Live Chat: 'Permitir conversa em direto'\n  Live Chat is currently not supported in this build.: 'A conversa em direto não é permitida nesta versão.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'A conversa em direto está ativada. As mensagens vão aparecer aqui.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Atualmente, a conversa em direto não é suportada pela API Invidious. É necessária uma ligação direta ao YouTube.'\n  Published:\n    In less than a minute: Em menos de um minuto\n  Published on: 'Publicado a'\n#& Videos\n  Starting soon, please refresh the page to check again: Irá começar brevemente. Recarregue a página para reanalisar\n  External Player:\n    Unsupported Actions:\n      opening playlists: abrir listas de reprodução\n      setting a playback rate: mudar velocidade de reprodução\n      starting video at offset: iniciar vídeo num tempo específico\n      looping playlists: repetir lista de reprodução\n      shuffling playlists: baralhar lista de reprodução\n      reversing playlists: inverter lista de reprodução\n      opening specific video in a playlist (falling back to opening the video): abrir um vídeo específico da lista (vai apenas abrir o vídeo)\n    UnsupportedActionTemplate: '{externalPlayer} não suporta: {action}'\n    OpeningTemplate: A abrir {videoOrPlaylist} em {externalPlayer}...\n    playlist: lista de reprodução\n    video: vídeo\n    OpenInTemplate: Abrir com {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Música fora de tópico\n    interaction: Interação\n    self-promotion: Auto-promoção\n    outro: Outro\n    intro: Introdução\n    sponsor: Patrocinador\n    recap: Recapitulação\n    filler: Preenchimento\n  Started streaming on: Transmissão iniciada em\n  Streamed on: Transmitido a\n  Audio:\n    Best: Melhor\n    High: Alta\n    Medium: Média\n    Low: Baixa\n  Copy Invidious Channel Link: Copiar hiperligação do canal do Invidious\n  Open Channel in Invidious: Abrir canal no Invidious\n  Copy YouTube Channel Link: Copiar hiperligação do canal do YouTube\n  Open Channel in YouTube: Abrir canal no YouTube\n  Video has been removed from your saved list: O vídeo foi removido da lista de guardados\n  Video has been saved: O vídeo foi guardado\n  Save Video: Guardar vídeo\n  Premieres: Estreias\n  Scroll to Bottom: Deslocar para baixo\n  Show Super Chat Comment: Mostrar comentário do Super Chat\n  Upcoming: Em breve\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': A conversa em direto não está disponível para esta emissão. Pode ter sido desativada pelo autor do vídeo.\n  Unhide Channel: Mostrar canal\n  Hide Channel: Ocultar canal\n  More Options: Mais opções\n  Player:\n    Theatre Mode: Modo teatro\n    Stats:\n      Media Formats: 'Formatos multimédia: {formats}'\n      Bitrate: Taxa de dados :{bitrate} kbps\n      Volume: 'Volume: {volumePercentage}%'\n      Bandwidth: 'Largura de banda: {bandwidth} kbps'\n      Resolution: 'Resolução: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensões do reprodutor: {width}x{height}'\n      Stats: Estatísticas\n      Video ID: 'ID do vídeo: {videoId}'\n      CodecAudio: 'Codificador: {audioCodec} ({audioItag})'\n      Buffered: 'Armazenado em buffer: {bufferedPercentage}%'\n      CodecsVideoAudio: 'Codificadores: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codificadores: {videoCodec} / {audioCodec}'\n      Dropped Frames / Total Frames: 'Fotogramas eliminados: {droppedFrames} / Total de fotogramas: {totalFrames}'\n    TranslatedCaptionTemplate: '{language} (traduzido de \"{originalLanguage}\")'\n    Audio Tracks: Faixas de áudio\n    Exit Theatre Mode: Sair do modo teatro\n    Full Window: Ecrã completo\n    Exit Full Window: Sair de ecrã completo\n    Take Screenshot: Tirar uma captura de ecrã\n    Show Stats: Mostrar estatísticas\n    Hide Stats: Ocultar estatísticas\n    You appear to be offline: Parece que não tem conexão à Internet.\n    Playback will resume automatically when your connection comes back: A reprodução será retomada automaticamente quando a conexão for restabelecida.\n    Skipped segment: Segmento {segmentCategory} ignorado\n    Autoplay is on: A reprodução automática está ativada\n    Autoplay is off: A reprodução automática está desativada\n  MembersOnly: Os vídeos só para membros não podem ser reproduzidos no FreeTube pois requerem um início de sessão Google e uma subscrição paga no canal do autor.\n  IP block: O YouTube bloqueou a reprodução de vídeos no seu endereço IP. Tente mudar para uma VPN ou proxy diferente.\n  AgeRestricted: Os vídeos com restrições de idade não podem ser reproduzidos no FreeTube pois requerem o início de sessão Google e a utilização de uma conta YouTube verificada.\n  Unlisted: Não listado\n#& Playlists\n  DeArrow:\n    Show Original Details: Mostrar detalhes originais\n    Show Modified Details: Mostrar detalhes modificados\n  DRMProtected: Os vídeos protegidos por DRM não podem ser reproduzidos no FreeTube pois requerem componentes proprietários e de código fechado. Se quiser ver este vídeo, veja-o no site oficial do YouTube num navegador Web com reprodução DRM.\n  Save Watched Progress: Guardar progresso de reprodução\n  Watched Progress Saved: Progresso guardado\nPlaylist:\n  #& About\n  View Full Playlist: 'Ver lista de reprodução completa'\n  Last Updated On: 'Última atualização'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Lista de reprodução\n  Sort By:\n    AuthorAscending: Autor (A-Z)\n    DateAddedNewest: Data de adição (mais recente)\n    DateAddedOldest: Data de adição (mais antiga)\n    AuthorDescending: Autor (Z-A)\n    VideoTitleAscending: Título (A-Z)\n    VideoTitleDescending: Título (Z-A)\n    Custom: Personalizado\n    VideoDurationDescending: Duração (mais longos)\n    VideoDurationAscending: Duração (mais curtos)\n    PublishedNewest: Data de publicação (mais recente)\n    PublishedOldest: Data de publicação (mais antiga)\nChange Format:\n  Change Media Formats: 'Alterar formatos multimédia'\n  Use Dash Formats: 'Utilizar formatos DASH'\n  Use Legacy Formats: 'Utilizar formatos antigos'\n  Use Audio Formats: 'Utilizar formatos de áudio'\n  Dash formats are not available for this video: 'Os formatos DASH não estão disponíveis para este vídeo'\n  Audio formats are not available for this video: 'Os formatos de áudio não estão disponíveis para este vídeo'\n  Legacy formats are not available for this video: Os formatos antigos não estão disponíveis para este vídeo\nShare:\n  Share Video: 'Partilhar vídeo'\n  Share Playlist: 'Partilhar lista'\n  Include Timestamp: 'Incluir posição temporal'\n  Copy Link: 'Copiar hiperligação'\n  Open Link: 'Abrir hiperligação'\n  Copy Embed: 'Copiar incorporado'\n  Open Embed: 'Abrir incorporado'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious copiado a para área de transferência'\n  Invidious Embed URL copied to clipboard: 'URL Invidious incorporado copiado para a área de transferência'\n  YouTube URL copied to clipboard: 'URL do YouTube copiado a para a área de transferência'\n  YouTube Embed URL copied to clipboard: 'URL do YouTube incorporado copiado para a área de transferência'\n  YouTube Channel URL copied to clipboard: URL do canal do YouTube copiado para a área de transferência\n  Invidious Channel URL copied to clipboard: URL do canal Invidious copiado para a área de transferência\n  Share Channel: Partilhar canal\n  Share Post: Compartilhar postagem\nMini Player: 'Mini-reprodutor'\nComments:\n  Comments: 'Comentários'\n  Click to View Comments: 'Clicar para ver os comentários'\n  Getting comment replies, please wait: 'A obter respostas ao comentário, por favor aguarde'\n  Hide Comments: 'Ocultar comentários'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Este vídeo não tem comentários'\n  Load More Comments: 'Carregar mais comentários'\n  There are no more comments for this video: Não há mais comentários para este vídeo\n  Show More Replies: Mostrar mais respostas\n  Newest first: Mais recentes\n  Top comments: Melhores comentários\n  Pinned by: Fixado por\n  Member: Membro\n  Hearted: Favorito\n  View {replyCount} replies: Ver 1 resposta | Ver {replyCount} respostas\n  Subscribed: Subscrito\n  There are no comments available for this post: Não existem comentários para esta publicação\n  Hide {replyCount} replies: Ocultar 1 resposta | Ocultar {replyCount} respostas\n  View 1 reply from {channelName}: Ver 1 resposta de {channelName}\n  View {replyCount} replies from {channelName} and others: Veja {replyCount} respostas de {channelName} e outros\nUp Next: 'Próximo'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Erro na API local (clique para copiar)'\nInvidious API Error (Click to copy): 'Erro na API Invidious (clique para copiar)'\nFalling back to Invidious API: 'Ocorreu um erro e a API Invidious será utilizada'\nFalling back to Local API: 'Ocorreu um erro e a API local será utilizada'\nLoop is now disabled: 'Repetição desativada'\nLoop is now enabled: 'Repetição ativada'\nShuffle is now disabled: 'Reprodução aleatória desativada'\nShuffle is now enabled: 'Reprodução aleatória ativada'\nThe playlist has been reversed: 'A lista de reprodução foi invertida'\nPlaying Next Video: 'A reproduzir o vídeo seguinte'\nPlaying Previous Video: 'A reproduzir o vídeo anterior'\nCanceled next video autoplay: 'Reprodução automática cancelada'\n'The playlist has ended. Enable loop to continue playing': 'A lista de reprodução chegou ao fim. Ative a repetição para continuar'\n\nYes: 'Sim'\nNo: 'Não'\nMore: Mais\nOpen New Window: Abrir nova janela\nDefault Invidious instance has been cleared: A instância Invidious padrão foi removida\nDefault Invidious instance has been set to {instance}: A instância Invidious padrão foi definida para {instance}\nPlaying Next Video Interval: A reproduzir o vídeo seguinte imediatamente. Clique para cancelar. | A reproduzir o vídeo seguinte em {nextVideoInterval} segundo. Clique para cancelar. | A reproduzir o vídeo seguinte em {nextVideoInterval} segundos. Clique para cancelar.\nUnknown YouTube url type, cannot be opened in app: O tipo de URL YouTube é desconhecido e não pode ser aberto na aplicação\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Este vídeo não está disponível porque faltam formatos. Isto pode acontecer devido à indisponibilidade no seu país.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Se ativa, FreeTube irá obter as subscrições via RSS em vez do método normal. O formato RSS é mais rápido e impede os bloqueio por IP, mas não disponibiliza certas informações como, por exemplo, a duração dos vídeos, se são emissões em direto e as publicações.\n    Fetch Automatically: Se ativa, FreeTube irá obter automaticamente as subscrições ao iniciar e se for aberta uma nova janela.\n  External Player Settings:\n    Custom External Player Arguments: Quaisquer argumentos de linha de comando, que quiser passar ao reprodutor externo.\n    Ignore Warnings: Ignorar avisos quando o reprodutor externo escolhido não suporte uma ação (por exemplo, inverter listas de reprodução).\n    Custom External Player Executable: Por omissão, FreeTube assume que o reprodutor externo pode ser encontrado através da variável PATH. Se for preciso, pode escolher um caminho personalizado aqui.\n    External Player: Escolher um reprodutor externo mostra um ícone para abrir o vídeo (lista de reprodução, se suportado) nessa aplicação. Mas tenha em conta de que as definições Invidious não afetam os reprodutores externos.\n    DefaultCustomArgumentsTemplate: \"(Padrão: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: 'Não enviar quaisquer argumentos padrão ao reprodutor externo a não ser o URL (ex: velocidade de reprodução, URL da lista de reprodução...). Os argumentos personalizados serão enviados.'\n  Player Settings:\n    Default Video Format: Define os formatos usados quando um vídeo é reproduzido. Os formatos DASH podem reproduzir qualidades mais altas. Os formatos antigos estão limitados a um máximo de 360p, mas usam menos largura de banda. Os formatos de áudio são apenas para emissões sem vídeo.\n    Proxy Videos Through Invidious: Estabelece uma conexão ao Invidious para obter vídeos em vez de fazer uma conexão direta ao YouTube.\n    Scroll Playback Rate Over Video Player: Com o cursor sobre o vídeo, mantenha premida a tecla Ctrl (Comando em Mac) e desloque a roda do rato para controlar a velocidade de reprodução. Mantenha premida a tecla Ctrl (Comando em Mac) e clique com o botão esquerdo do rato para voltar rapidamente à velocidade de reprodução padrão (1 a não ser que tenha sido alterada nas definições).\n    Skip by Scrolling Over Video Player: Utilizar roda do rato para avançar ou recuar o vídeo, estilo MPV.\n  General Settings:\n    Region for Trending: A região permite-lhe escolher de que país virão os vídeos na secção de tendências.\n    Invidious Instance: A instância Invidious à qual o FreeTube se irá ligar para invocar a API.\n    Thumbnail Preference: Todas as miniaturas dos vídeos no FreeTube serão substituídas por um fotograma do vídeo, borrado ou oculto em vez da miniatura original.\n    Fallback to Non-Preferred Backend on Failure: Se a sua API preferida tiver um problema, FreeTube tentará usar automaticamente a API secundária, caso esta opção esteja ativada.\n    Preferred API Backend: Escolha o sistema que o FreeTube usa para se ligar ao YouTube. A API local é um extrator incorporado. A API Invidious requer um servidor Invidious para fazer a ligação.\n    External Link Handling: \"Escolha o comportamento padrão quando uma hiperligação, que não pode ser aberta no FreeTube, é clicada.\\nPor definição, o FreeTube abrirá a hiperligação no seu navegador de Internet.\\n\"\n    Open Deep Links In New Window: Os URLs passados para o FreeTube, como por extensões de navegador de redirecionamento ou argumentos de linha de comando, são abertos numa nova janela.\n  Experimental Settings:\n    Replace HTTP Cache: Desativa a cache HTTP Electron e ativa uma cache de imagem na memória personalizada. Implica o aumento da utilização de memória RAM.\n  Distraction Free Settings:\n    Hide Channels: Introduza o ID de um canal para impedir que os vídeos, listas de reprodução e o próprio canal apareçam na pesquisa, tendências, mais populares e recomendados. O nome do canal introduzido tem que ser uma correspondência exata e diferencia maiúsculas de minúsculas.\n    Hide Subscriptions Live: Esta definição é substituída pela definição global \"{appWideSetting}\", existente na secção \"{subsection}\" de \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Introduza uma palavra, fragmento de palavra ou frase (sem distinção entre maiúsculas e minúsculas) para ocultar todos os vídeos e listas de reprodução cujos títulos originais a contenham em todo o FreeTube, excluindo apenas o histórico, as suas listas de reprodução e os vídeos dentro das listas de reprodução.\n    Hide Videos on Watch: Oculta os vídeos já reproduzidos nos separadores \"Vídeos\", \"Shorts\" e \"Em direto\" nas páginas \"Subscrição\" e \"Canal\". Não afeta o separador \"Início\" nas páginas \"Canal\".\n  SponsorBlock Settings:\n    UseDeArrowTitles: Substituir títulos de vídeo por títulos enviados pelo utilizador a partir do DeArrow.\n    UseDeArrowThumbnails: Substituir miniaturas do vídeo por miniaturas DeArrow.\nSearch Bar:\n  Clear Input: Limpar entrada\n  Remove: Remover\nAre you sure you want to open this link?: Tem a certeza de que deseja abrir esta ligação?\nExternal link opening has been disabled in the general settings: A abertura de hiperligações externas foi desativada nas definições\nScreenshot Success: Captura de ecrã guardada\nScreenshot Error: Erro ao capturar o ecrã. {error}\nNew Window: Nova janela\nChannels:\n  Count: '{number} canais encontrados.'\n  Empty: A lista de canais está vazia.\n  Search bar placeholder: Procurar canais\n  Channels: Canais\n  Title: Lista de canais\n  Unsubscribe Prompt: Tem a certeza de que pretende cancelar a subscrição de \"{channelName}\"?\nChapters:\n  Chapters: Capítulos\n  Key Moments: Momentos-chave\nClipboard:\n  Copy failed: Falha ao copiar para a área de transferência\n  Cannot access clipboard without a secure connection: Não é possível aceder à área de transferência sem uma conexão segura\nPreferences: Preferências\nOk: OK\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Esta 'hashtag' não tem quaisquer vídeos\nChannel Hidden: '{channel} adicionado ao filtro do canal'\nGo to page: Ir para {page}\nChannel Unhidden: '{channel} removido do filtro do canal'\nTag already exists: '\"{tagName}\" já existe'\nClose Banner: Fechar banner\nAge Restricted:\n  This channel is age restricted: Este canal tem restrições de idade\n  This video is age restricted: Este vídeo tem restrições de idade\nFeed:\n  Feed Last Updated: 'Última atualização de {feedName}: {date}'\n  Refresh Feed: Recarregar {subscriptionName}\nDisplay Label: '{label}: {value}'\nMoments Ago: há momentos\ncheckmark: ✓\nYes, Delete: Sim, eliminar\nYes, Open Link: Sim, abrir hiperligação\nCancel: Cancelar\nSearch character limit: 'A pesquisa excede o limite de {searchCharacterLimit} caracteres permitidos'\nYes, Restart: Sim, reiniciar\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Legendas\n    Closed Captions: Legendas de áudio\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Nova\n    3D: 3D\nKeyboardShortcutPrompt:\n  Close Window: Fechar janela\n  Reset Zoom: Repor nível de ampliação/escala da interface\n  Captions: Ativar ou desativar legendas\n  Large Rewind: Recuar 10 segundos/Recuo rápido do vídeo com base na velocidade de reprodução atual\n  Play: Alternar entre reprodução / pausa\n  Large Fast Forward: Avançar 10 segundos/Avanço rápido do vídeo com base na velocidade de reprodução atual\n  Sections:\n    App:\n      Situational: 'Aplicação: Situacional'\n      General: Aplicação: Geral\n    Video:\n      Playback: Vídeo: Reprodução\n      General: Vídeo: Geral\n  History Backward: Recuar uma página\n  Minimize Window: Minimizar janela\n  Zoom In: Ampliar\n  Skip by Tenths: Avançar ou recuar o vídeo em percentagem (3 saltos para 30% da duração)\n  Keyboard Shortcuts: Atalhos de teclado\n  Zoom Out: Diminuir\n  Toggle Developer Tools: Alternar ferramentas de programador\n  Full Window: Alternar modo de janela completa\n  Next Frame: Fotograma seguinte (durante a pausa)\n  Show Keyboard Shortcuts: Mostrar atalhos de teclado\n  Volume Up: Aumentar volume\n  Next Chapter: Capítulo seguinte\n  Volume Down: Diminuir volume\n  Focus Search: Focar na barra de pesquisa\n  Search in New Window: Pesquisar em nova janela\n  Last Chapter: Último capítulo\n  Increase Video Speed: Aumentar velocidade do vídeo com base no intervalo da velocidade de reprodução\n  Navigate to History: Ir para a página Histórico\n  Stats: Mostrar estatísticas do vídeo\n  Fullscreen: Alternar ecrã completo\n  Picture in Picture: Alternar o modo de imagem na imagem\n  Mute: Ativar ou desativar som\n  Theatre Mode: Alternar modo Teatro\n  Take Screenshot: Obter captura de ecrã\n  Last Frame: Fotograma anterior (durante a pausa)\n  Focus Secondary Search: Focar na barra de pesquisa secundária (se existir)\n  History Forward: Avançar uma página\n  New Window: Criar uma nova janela\n  Navigate to Settings: Ir para a página Definições\n  Refresh: Atualizar fonte com o conteúdo mais recente\n  Decrease Video Speed: Diminuir velocidade do vídeo com base no intervalo da velocidade de reprodução\n  Small Rewind: Recuar X segundos com base no intervalo de Recuo rápido e na velocidade de reprodução atual\n  Small Fast Forward: Avançar X segundos com base no intervalo de Avanço rápido e na velocidade de reprodução atual\n  Home: Procurar no início do vídeo\n  End: Procurar no final do vídeo\n  Skip to Next Video: Ir para o vídeo seguinte da lista de reprodução ou recomendações\n  Skip to Previous Video: Ir para o vídeo anterior da lista de reprodução\nshortcutLabelSeparator: ｜\nKeys:\n  arrowleft: Seta para a esquerda\n  arrowright: Seta para a direita\n  arrowup: Seta para cima\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Seta para baixo\n  plus: Mais\n  shift: Shift\n  enter: Enter\nDescription:\n  Expand Description: '...mais'\n  Collapse Description: Mostrar menos\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nRight-click or hold to see history: Clique com o botão direito do rato ou mantenha-o premido para ver o histórico\nTrimmed input must be at least N characters long: A entrada cortada deve ter pelo menos 1 carácter | A entrada cortada deve ter pelo menos {length} caracteres\nAutoplay Interruption Timer: Reprodução automática cancelada devido a {autoplayInterruptionIntervalHours} horas de inatividade\nshortcutJoinOperator: +\nCompact side navigation: Navegação lateral compacta\nExpand side navigation: Expandir navegação lateral\n"
  },
  {
    "path": "static/locales/ro.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Română'\n\n# Webkit Menu Bar\nFile: 'Filă'\nQuit: 'Ieșire'\nEdit: 'Editare'\nUndo: 'Anulare'\nRedo: 'Refacere'\nCut: 'Tăiați'\nCopy: 'Copiere'\nPaste: 'Lipire'\nDelete: 'Ștergeți'\nSelect all: 'Selectați toate'\nToggle Developer Tools: 'Comutați instrumentele pentru dezvoltatori'\nActual size: 'Mărimea actuală'\nZoom in: 'Mărire'\nZoom out: 'Micșorare'\nToggle fullscreen: 'Comutați ecranul complet'\nWindow: 'Fereastră'\nMinimize: 'Minimizare'\nClose: 'Închideți'\nBack: 'Înapoi'\nForward: 'Înainte'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videoclipuri'\n  Shorts: Shorturi\n  Live: Liveuri\n  Posts: Postări\n  Sort By: Sortează după\n  Counts:\n    Video Count: 1 videoclip | {count} videoclipuri\n    Subscriber Count: 1 abonat | {count} de abonați\n    View Count: 1 vizionare | {count} vizionări\n    Channel Count: 1 canal | {count} canale\n    Watching Count: 1 se uită | {count} se uită\n    Comment Count: 1 comentariu | {count} comentarii\n    Like Count: 1 apreciere | {count} aprecieri\nVersion {versionNumber} is now available!  Click for more details: 'Versiunea {versionNumber} este acum disponibilă!  Click pentru mai multe detalii'\nDownload From Site: 'Descărcați de pe site'\nA new blog is now available, {blogTitle}. Click to view more: 'Un nou blog este acum disponibil, {blogTitle}. Faceți clic pentru a vedea mai multe'\n\n# Search Bar\nSearch / Go to URL: 'Căutare / Accesați URL-ul'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtre de căutare'\n  Sort By:\n    Most Relevant: 'Cele mai relevante'\n    Rating: 'Evaluare'\n    Upload Date: 'Data încărcării'\n    View Count: 'Numărul de vizualizări'\n  Time:\n    Time: 'Timp'\n    Any Time: 'Oricând'\n    Last Hour: 'Ultima oră'\n    Today: 'Astăzi'\n    This Week: 'Săptămâna aceasta'\n    This Month: 'Luna aceasta'\n    This Year: 'Anul acesta'\n  Type:\n    Type: 'Tip'\n    All Types: 'Toate tipurile'\n    Videos: 'Videoclipuri'\n    Channels: 'Canale'\n    #& Playlists\n    Movies: Filme\n  Duration:\n    Duration: 'Durată'\n    All Durations: 'Toate duratele'\n    Short (< 4 minutes): 'Scurt (< 4 minute)'\n    Long (> 20 minutes): 'Lung (> 20 minute)'\n  # On Search Page\n    Medium (4 - 20 minutes): Mediu (4 - 20 minute)\n  Search Results: 'Rezultatele căutării'\n  Fetching results. Please wait: 'Se obțin rezultatele. Vă rugăm să așteptați'\n  Fetch more results: 'Obțineți mai multe rezultate'\n# Sidebar\n  There are no more results for this search: Nu mai există rezultate pentru această căutare\n  Features:\n    Features: Caracteristici\n    HD: HD\n    3D: 3D\n    Live: În direct\n    4K: 4K\n    Subtitles: Subtitrări\n    Location: Locație\n    HDR: HDR\n    VR180: VR180\n    360 Video: Video 360\n    Creative Commons: Creative Commons\n  Clear Filters: Șterge filtrele\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonamente'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Lista dvs. de abonamente este momentan goală. Dacă vreți să importați abonamente, vă puteți duce la setări de date și să selectați Importă Anonamente sau puteți căuta un canal și să vă abonați la el.'\n  Load More Videos: Încarcă mai mult\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Acest profil are un număr mare de abonamente.  Se forțează RSS pentru a evita limitarea vitezei\n  Error Channels: Canale cu erori\n  Empty Channels: Canalele la care sunteți abonat(ă) nu au în prezent clipuri video.\n  Disabled Automatic Fetching: Ați dezactivat preluarea automată a abonamentelor. Reîmprospătați abonamentele pentru a le vedea aici.\n  Subscriptions Tabs: Filele Abonamente\n  All Subscription Tabs Hidden: Toate filele de abonament sunt ascunse. Pentru a vedea conținutul aici, vă rugăm să afișați unele file din secțiunea \"{subsection}” din \"{settingsSection}”.\n  Empty Posts: Canalele tale abonate nu au momentan nicio postare.\n  Load More Posts: Încarcă mai multe postări\nTrending:\n  Trending: 'Tendințe'\n  Trending Tabs: File în tendințe\n  Gaming: Gaming\n  Sports: Sport\nMost Popular: 'Cele mai populare'\nPlaylists: 'Liste de redare'\nUser Playlists:\n  Your Playlists: 'Listele tale de redare'\n  Search bar placeholder: Căutați liste de redare\n  Empty Search Message: Nu există videoclipuri în această listă de redare care să corespundă căutării dvs\n  Move Video Down: Mutați videoclipul în jos\n  Enable Quick Bookmark With This Playlist: Activați marcajul rapid cu această listă de redare\n  Sort By:\n    NameDescending: Z-A\n    LatestCreatedFirst: Creat recent\n    NameAscending: A-Z\n    LatestUpdatedFirst: Actualizat recent\n    EarliestCreatedFirst: Cel mai devreme creat\n    LatestPlayedFirst: Redate recent\n    EarliestUpdatedFirst: Cea mai recentă actualizare\n    EarliestPlayedFirst: Cele mai recent redate\n  This playlist currently has no videos.: Această listă de redare nu are în prezent niciun videoclip.\n  You have no playlists. Click on the create new playlist button to create a new one.: Nu aveți liste de redare. Faceți clic pe butonul de creare a unei noi liste de redare pentru a crea una nouă.\n  Playlists with Matching Videos: Liste de redare cu videoclipuri corespunzătoare\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: Selectați o listă de redare la care să adăugați videoclipul dvs. | Selectați o listă de redare la care să adăugați videoclipurile {videoCount}\n    Added {count} Times: Deja adăugat | Adăugat {count} ori\n    Allow Adding Duplicate Video(s): Permiteți adăugarea de videoclipuri duplicat(e)\n    Save: Salvează\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videoclipuri vor fi adăugate'\n    Toast:\n      You haven't selected any playlist yet.: Nu ați selectat încă nicio listă de redare.\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n    N playlists selected: '{playlistCount} Selectat'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Videoclipuri deja adăugate'\n    Search in Playlists: Caută in listele de redare\n  Cancel: Anulare\n  Edit Playlist Info: Editați informațiile despre lista de redare\n  Copy Playlist: Copiați lista de redare\n  Remove Watched Videos: Eliminați videoclipurile vizionate\n  Create New Playlist: Creați o nouă listă de redare\n  Add to Playlist: Adăugați la lista de redare\n  Add to Favorites: Adaugă la {playlistName}\n  Remove from Favorites: Eliminați din {playlistName}\n  Move Video Up: Mutați videoclipul în sus\n  Remove from Playlist: Eliminați din lista de redare\n  Playlist Name: Numele listei de redare\n  Playlist Description: Descrierea listei de redare\n  Save Changes: Salvați modificările\n  Delete Playlist: Ștergeți lista de redare\n  Are you sure you want to delete this playlist? This cannot be undone: Sunteți sigur că doriți să ștergeți această listă de redare? Acest lucru nu poate fi anulat.\n  CreatePlaylistPrompt:\n    Toast:\n      Playlist {playlistName} has been successfully created.: Lista de redare {playlistName} a fost creată cu succes.\n      There was an issue with creating the playlist.: A existat o problemă la crearea listei de redare.\n      There is already a playlist with this name. Please pick a different name.: Există deja o listă de redare cu acest nume. Vă rugăm să alegeți un alt nume.\n    New Playlist Name: Numele noii liste de redare\n    Create: Creați\n  SinglePlaylistView:\n    Toast:\n      There was a problem with removing this video: A existat o problemă cu eliminarea acestui videoclip\n      This playlist is now used for quick bookmark: Această listă de redare este acum utilizată pentru marcaje rapide\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Această listă de redare este acum utilizată pentru marcajul rapid în loc de {oldPlaylistName}. Faceți clic aici pentru a anula\n      This video cannot be moved down.: Acest videoclip nu poate fi mutat în jos.\n      This video cannot be moved up.: Acest videoclip nu poate fi mutat în sus.\n      Video has been removed: Videoclipul a fost eliminat\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Unele videoclipuri din lista de redare nu sunt încă încărcate. Faceți clic aici pentru a copia oricum.\n      This playlist is protected and cannot be removed.: Această listă de redare este protejată și nu poate fi ștearsă.\n      Playlist {playlistName} has been deleted.: Lista de redare {playlistName} a fost ștearsă.\n      \"{videoCount} video(s) have been removed\": 1 videoclip a fost eliminat | {videoCount} videoclipuri au fost eliminate\n      There were no videos to remove.: Nu au existat videoclipuri care să fie eliminate.\n      Playlist name cannot be empty. Please input a name.: Numele listei de redare nu poate fi gol. Vă rugăm să introduceți un nume.\n      Playlist has been updated.: Lista de redare a fost actualizată.\n      This playlist does not exist: Această listă de redare nu există\n      There was an issue with updating this playlist.: A fost o problemă în actualizarea acestei liste de redare.\n      Reverted to use {oldPlaylistName} for quick bookmark: S-a revenit la {oldPlaylistName} pentru folosirea de marcaj rapid\n      Video has been removed. Click here to undo.: Videoclipul a fost scos. Apăsați aici ca să anulați.\n      This playlist has a video with a duration error: Această listă de redare conține cel puțin 1 videoclip care nu are durată, va fi sortat ca și cum durata ar fi fost zero.\n      This playlist is already being used for quick bookmark.: Această listă de redare este deja folosită pentru marcaj rapid.\n    Search for Videos: Căutați videoclipuri\n  Remove Duplicate Videos: Șterge videoclipurile duplicate\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Sunteți sigur(ă) că doriți să ștergeți 1 videoclip vizualizat din această lista de redare? Această acțiune este definitivă. | Sunteți sigur(ă) că doriți să ștergeți {playlistItemCount} videoclip vizualizat din această lista de redare? Această acțiune este definitivă.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Sunteți sigur că vrei să ștergeți 1 videoclip duplicat din această listă de redare? Această acțiune nu poate fi anulată. | Sunteți sigur că vreți să ștergeți {playlistItemCount} videoclipuri duplicate din această listă? Această acțiune nu poate fi anulată.\n  Export Playlist: Exportă această listă de redare\n  Cannot delete the quick bookmark target playlist.: Nu se poate șterge listă de redare țintă marcajului rapid.\n  The playlist has been successfully exported: Lista de redare a fost exportată cu succes\n  Quick Bookmark Enabled: Marcaj rapid activat\n  TotalTimePlaylist: 'Timp total: {duration}'\nHistory:\n  # On History Page\n  History: 'Istoric'\n  Watch History: 'Istoricul vizionărilor'\n  Your history list is currently empty.: 'Lista dvs. de istoric este momentan goală.'\n  Search bar placeholder: Căutare în istoric\n  Empty Search Message: Nu există videoclipuri în această listă de redare care să corespundă căutării dvs\n  Case Sensitive Search: ­Căutare sensibilă la majuscule\n  DateOldestHistory: Începând cu primul vizionat\n  DateNewestHistory: Începând cu ultimul vizionat\nSettings:\n  # On Settings Page\n  Settings: 'Setări'\n  General Settings:\n    General Settings: 'Setări generale'\n    Check for Updates: 'Căutați actualizări'\n    Check for Latest Blog Posts: 'Verificați pentru cele mai recente postări pe blog'\n    Fallback to Non-Preferred Backend on Failure: 'Revenire la backend-ul nepreferat în caz de eroare'\n    Enable Search Suggestions: 'Activați sugestiile de căutare'\n    Default Landing Page: 'Pagina de pornire implicită'\n    Locale Preference: 'Preferința de localizare'\n    Preferred API Backend:\n      Preferred API Backend: 'API Backend preferat'\n      Local API: 'API Local'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Tip de vizualizare video'\n      Grid: 'Grilă'\n      List: 'Listă'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferința de miniatură'\n      Default: 'Implicit'\n      Beginning: 'Început'\n      Middle: 'Mijloc'\n      End: 'Sfârșit'\n      Hidden: Ascuns\n      Blur: Estompa\n    Region for Trending: 'Regiunea tendințelor'\n        #! List countries\n    External Link Handling:\n      No Action: Nicio acțiune\n      Ask Before Opening Link: Întrebați înainte de a deschide linkul\n      Open Link: Deschideți linkul\n      External Link Handling: Gestionarea legăturilor externe\n    View all Invidious instance information: Vizualizați toate informațiile despre instanța Invidious\n    Clear Default Instance: Ștergeți instanța implicită\n    Set Current Instance as Default: Setați instanța curentă ca implicită\n    Current instance will be randomized on startup: Instanța curentă va fi aleatorie la pornire\n    No default instance has been set: Nu a fost setată nicio instanță implicită\n    The currently set default instance is {instance}: Instanța implicită setată în prezent este {instance}\n    Current Invidious Instance: Instanța actuală Invidious\n    System Default: Prestabilită de sistem\n    Auto Load Next Page:\n      Label: Încarcă următoarea pagină automat\n      Tooltip: Încarcă automat pagini și comentarii suplimentare.\n    Open Deep Links In New Window: Deschideți URL-urile transmise către FreeTube într-o fereastră nouă\n    Minimize to system tray: Minimizare în bara de sistem\n  Theme Settings:\n    Theme Settings: 'Setări temă'\n    Match Top Bar with Main Color: 'Potriviți bara de sus cu culoarea principală'\n    Base Theme:\n      Base Theme: 'Tema de bază'\n      Black: 'Neagră'\n      Dark: 'Întunecată'\n      Light: 'Luminoasă'\n      Dracula: 'Dracula'\n      System Default: Setări implicite\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastel Roz\n      Hot Pink: Hot Roz\n      Solarized Light: Lumină solarizată\n      Solarized Dark: Întuneric solarizat\n      Gruvbox Dark: Cutie de minerit Întunecat\n      Gruvbox Light: Caseta pentru minerit Light\n      Nordic: Nordic\n      Everforest Light Hard: Everforest deschis Greu\n      Everforest Dark Hard: Everforest închis Greu\n      Everforest Dark Medium: Everforest întuneric mediu\n      Everforest Dark Low: Everforest întuneric scăzut\n      Everforest Light Medium: Everforest Lumină Mediu\n      Everforest Light Low: Everforest Lumină scăzută\n      Catppuccin Frappe: Catnip Frappe\n    Main Color Theme:\n      Main Color Theme: 'Culoarea principală a temei'\n      Red: 'Roşu'\n      Pink: 'Roz'\n      Purple: 'Violet'\n      Deep Purple: 'Mov închis'\n      Indigo: 'Indigo'\n      Blue: 'Albastru'\n      Light Blue: 'Albastru deschis'\n      Cyan: 'Cyan'\n      Teal: 'Turcoaz'\n      Green: 'Verde'\n      Light Green: 'Verde deschis'\n      Lime: 'Verde lime'\n      Yellow: 'Galben'\n      Amber: 'Chihlimbar'\n      Orange: 'Portocaliu'\n      Deep Orange: 'Portocaliu închis'\n      Dracula Cyan: 'Albastru Dracula'\n      Dracula Green: 'Verde Dracula'\n      Dracula Orange: 'Porticaliu Dracula'\n      Dracula Pink: 'Roz Dracula'\n      Dracula Purple: 'Violet Dracula'\n      Dracula Red: 'Roșu Dracula'\n      Dracula Yellow: 'Galben Dracula'\n      Catppuccin Mocha Pink: Catppuccin Mocha Roz\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mov\n      Catppuccin Mocha Red: Catppuccin Mocha Roșu\n      Catppuccin Mocha Yellow: Catppuccin Mocha Galben\n      Catppuccin Mocha Green: Catppuccin Mocha Verde\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sky: Catppuccin Mocha Albastru\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Safir\n      Catppuccin Mocha Blue: Catppuccin Mocha Albastru\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavandă\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maro\n      Catppuccin Mocha Peach: Catppuccin Mocha Piersică\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Apă de Trandafiri\n      Solarized Violet: Violet solarizat\n      Solarized Cyan: Turcoaz solarizat\n      Solarized Red: Roșu solarizat\n      Solarized Green: Verde solarizat\n      Solarized Yellow: Galben solarizat\n      Solarized Blue: Albastru solarizat\n      Solarized Orange: Portocaliu solarizat\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Apa de trandafiri\n      Catppuccin Frappe Peach: Catppuccin Frappe Piersică\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavandă\n      Gruvbox Dark Yellow: Gruvbox Galben Închis\n      Gruvbox Dark Purple: Gruvbox Violet Închis\n      Gruvbox Dark Aqua: Gruvbox Aqua Închis\n      Gruvbox Dark Blue: Gruvbox Albastru Închis\n      Solarized Magenta: Magenta solarizat\n      Gruvbox Light Red: Gruvbox Roșu Deschis\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe roz\n      Catppuccin Frappe Mauve: Catppuccin Frappe mov\n      Catppuccin Frappe Red: Catppuccin Frappe Roșu\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maro\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Safir\n      Catppuccin Frappe Blue: Catppuccin Frappe Albastru\n      Gruvbox Dark Green: Gruvbox Verde Închis\n      Gruvbox Dark Orange: Gruvbox Portocaliu Închis\n      Gruvbox Light Blue: Gruvbox Albastru Deschis\n      Gruvbox Light Purple: Gruvbox Violet Deschis\n      Gruvbox Light Orange: Gruvbox Portocaliu Deschis\n      Everforest Dark Red: Everforest roșu închis\n      Everforest Dark Aqua: Everforest Aqua închis\n      Everforest Dark Orange: Everforest Portocaliu închis\n      Everforest Dark Yellow: Everforest galben închis\n      Everforest Dark Green: Everforest Verde închis\n      Everforest Dark Blue: Everforest Albastru închis\n      Catppuccin Frappe Yellow: Catppuccin Frappe Galben\n      Catppuccin Frappe Green: Catppuccin Frappe Verde\n      Catppuccin Frappe Teal: Turcoaz Catppuccin Frappe\n      Catppuccin Frappe Sky: Catppuccin Frappe cer\n      Everforest Dark Purple: Violet închis Everforest\n      Everforest Light Red: Roșu deschis Everforest\n      Everforest Light Orange: Portocaliu deschis Everforest\n      Everforest Light Yellow: Everforest galben deschis\n      Everforest Light Green: Everforest Verde deschis\n      Everforest Light Aqua: Aqua deschis Everforest\n      Everforest Light Blue: Everforest Albastru deschis\n      Everforest Light Purple: Everforest violet deschis\n    Secondary Color Theme: 'Culoarea secundară a temei'\n        #* Main Color Theme\n    UI Scale: Scala interfeței utilizatorului (UI)\n    Disable Smooth Scrolling: Dezactivați derularea lină\n    Expand Side Bar by Default: Extindeți bara laterală în mod implicit\n    Hide Side Bar Labels: Ascunde etichetele din bara laterală\n    Hide FreeTube Header Logo: Ascundeți logo-ul antetului FreeTube\n  Player Settings:\n    Player Settings: 'jucător'\n    Play Next Video: 'Redare automată videoclipuri recomandate'\n    Turn on Subtitles by Default: 'Activați subtitrări în mod implicit'\n    Autoplay Videos: 'Pornirea automată a videoclipurilor'\n    Proxy Videos Through Invidious: 'Videoclipuri prin proxy-ul Invidious'\n    Autoplay Playlists: 'Redare automată a videoclipurilor din lista de redare'\n    Enable Theatre Mode by Default: 'Activați modul teatru în mod implicit'\n    Default Volume: 'Volum implicit'\n    Default Playback Rate: 'Viteza de redare implicită'\n    Default Video Format:\n      Default Video Format: 'Format video implicit'\n      Dash Formats: 'Formate DASH'\n      Legacy Formats: 'Formate vechi'\n      Audio Formats: 'Formate audio'\n    Default Quality:\n      Default Quality: 'Calitate implicită'\n      Auto: 'Automat'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Fast-Forward / Rewind Interval: Intervalul de derulare înainte / înapoi\n    Next Video Interval: Temporizator de numărătoare inversă pentru redare automată\n    Display Play Button In Video Player: Afișați butonul de redare în playerul video\n    Scroll Volume Over Video Player: Derulați volumul peste playerul video\n    Screenshot:\n      Quality Label: Calitatea capturii de ecran\n      Ask Path: Întreabă pentru dosarul de salvare\n      Folder Label: Dosarul pentru capturi de ecran\n      Folder Button: Selectează dosar\n      File Name Label: Tiparul denumirii fișierelor\n      Error:\n        Forbidden Characters: Caractere interzise\n        Empty File Name: Denumiri de fișiere goale\n      File Name Tooltip: Puteți utiliza variabilele de mai jos. %Y Anul 4 cifre. %M Luna 2 cifre. %D Ziua 2 cifre. %H Ora 2 cifre. %N Minute 2 cifre. %S Secunda 2 cifre. %T Milisecundă 3 cifre. %s Secunda video. %t Milisecundă video 3 cifre. %i Video ID.\n      Enable: Activează captura de ecran\n      Format Label: Formatul capturii de ecran\n    Video Playback Rate Interval: Intervalul de redare video\n    Max Video Playback Rate: Viteza maximă de redare\n    Scroll Playback Rate Over Video Player: Schimbă viteza de redare cu ajutorul rotiței de scroll\n    Enter Fullscreen on Display Rotate: Intrați pe ecran complet pe afișaj Rotire\n    Skip by Scrolling Over Video Player: Omiteți derulând peste playerul video\n    Default Viewing Mode:\n      External Player: Player extern ({externalPlayerName})\n      Default Viewing Mode: Mod de vizualizare implicit\n      Theater: Teatru\n      Full Screen: Ecran complet\n      Picture in Picture: Imagine în imagine\n    Autoplay Interruption Timer: Temporizator de întrerupere a redării automate\n  Privacy Settings:\n    Privacy Settings: 'Confidențialitate'\n    Remember History: 'Amintiți-vă Istoricul vizionărilor'\n    Save Watched Progress: 'Salvați progresul de vizionare'\n    Clear Search Cache: 'Sterge Cache-ul Căutărilor'\n    Are you sure you want to clear out your search cache?: 'Sunteți sigur că doriți să ștergeți memoria cache de căutare?'\n    Search cache has been cleared: 'Memoria cache de căutare a fost ștearsă'\n    Remove Watch History: 'Eliminați istoricul vizionărilor'\n    Are you sure you want to remove your entire watch history?: 'Esti sigur ca doresti sa stergi intreg istoricul cautarilor tale ?'\n    Watch history has been cleared: 'Istoricul vizionărilor a fost șters'\n    Remove All Subscriptions / Profiles: 'Eliminați toate Abonamentele / Profilurile'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Sunteți sigur că doriți să eliminați toate abonamentele și profilurile?  Acest lucru nu poate fi anulat.'\n    Save Watched Videos With Last Viewed Playlist: Salvați videoclipurile vizionate cu ultima listă de redare vizualizată\n    Are you sure you want to remove all your playlists?: Sunteți sigur(ă) că doriț să ștergeți toate listele dvs. de redare?\n    Remove All Playlists: Eliminați toate listele de redare\n    All playlists have been removed: Toate listele de redare au fost eliminate\n    Search history and cache have been cleared: Istoricul căutărilor și memoria cache au fost șterse\n    Are you sure you want to clear out your search history and cache?: Sunteți sigur că doriți să ștergeți istoricul căutărilor și memoria cache?\n    Remember Search History: Reține istoricul căutărilor\n    Clear Search History and Cache: Ștergeți istoricul căutărilor și memoria cache\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Automat\n        Never: Niciodată\n        Semi-auto: Semi-automat\n      Tooltip: Automat = Salvează la fiecare ieșire de pe pagina video, când video-ul se termină și când apare o eroare (de exemplu, limitare de viteză sau sesiune de vizionare expirată). Semi-automat = Ca și Automat, cu excepția ieșirii de pe pagina video și permite salvarea progresului manual printr-un buton numit \"Salvează progresul vizionat\", aflat sub player-ul video.\n  Subscription Settings:\n    Subscription Settings: 'Abonament'\n    Fetch Feeds from RSS: 'Preluare de fluxuri din RSS'\n    Fetch Automatically: Preluați feedul automat\n    Confirm Before Unsubscribing: Confirmă înainte de dezabonare\n    'Limit the number of videos displayed for each channel': Limitați numărul de videoclipuri afișate pentru fiecare canal\n    To: la\n  Data Settings:\n    Data Settings: 'Date'\n    Select Export Type: 'Selectează tipul de export'\n    Import Subscriptions: 'Importă abonamente'\n    Export Subscriptions: 'Exportați abonamentele'\n    Export FreeTube: 'Exportați FreeTube'\n    Export YouTube: 'Exportați YouTube'\n    Export NewPipe: 'Exportați NewPipe'\n    Import History: 'Importați istoricul'\n    Export History: 'Exportați istoricul'\n    Profile object has insufficient data, skipping item: 'Obiectul de profil are date insuficiente, se omite elementul'\n    All subscriptions and profiles have been successfully imported: 'Toate abonamentele și profilurile au fost importate cu succes'\n    All subscriptions have been successfully imported: 'Toate abonamentele au fost importate cu succes'\n    Invalid subscriptions file: 'Fișier de abonamente invalid'\n    Invalid history file: 'Fișier istoric invalid'\n    Subscriptions have been successfully exported: 'Abonamentele au fost exportate cu succes'\n    History object has insufficient data, skipping item: 'Obiectul de istoric are date insuficiente, se omite elementul'\n    All watched history has been successfully imported: 'Tot istoricul de vizionări a fost importat cu succes'\n    All watched history has been successfully exported: 'Tot istoricul de vizionări a fost exportat cu succes'\n    Unable to read file: 'Nu se poate citi fișierul'\n    Unable to write file: 'Nu se poate scrie fișierul'\n    Unknown data key: 'Cheie de date necunoscută'\n    How do I import my subscriptions?: 'Cum îmi pot importa abonamentele?'\n    Manage Subscriptions: Gestionare abonamente\n    All playlists has been successfully imported: Toate listele de redare au fost importate cu succes\n    Import Playlists: Importați liste de redare\n    Export Playlists: Exportați liste de redare\n    Playlist insufficient data: Date insuficiente pentru lista de redare \"{playlist}\", se omite\n    All playlists has been successfully exported: Toate listele de redare au fost exportate cu succes\n    Playlist File: Fișier listă de redare\n    History File: Fișier istoric\n    Subscription File: Fișier abonament\n    Export Playlists For Older FreeTube Versions:\n      Label: Exportați liste de redare pentru versiunile FreeTube mai vechi\n      Tooltip: \"Această opțiune exportă videoclipurile din toate listele de redare într-o singură listă de redare numită 'Favorite'.\\nCum să exportați și să importați videoclipurile în listele de redare pentru o versiune mai veche a FreeTube:\\n1. Exportați-vă listele de redare cu această opțiune activată.\\n 2. Ștergeți toate listele de redare existente utilizând opțiunea Eliminați toate listele de redare din Setări de confidențialitate.\\n3. Lansați versiunea mai veche a FreeTube și importați listele de redare exportate.”\"\n  The app needs to restart for changes to take effect. Restart and apply change?: Aplicația trebuie repornită pentru ca modificările să intre în vigoare. Reporniți și aplicați modificările?\n  External Player Settings:\n    Custom External Player Arguments: Argumente personalizate pentru playerul extern\n    Custom External Player Executable: Executabilul personalizat al playerului extern\n    Ignore Unsupported Action Warnings: Ignorați avertismentele de acțiune nesuportată\n    External Player: Player extern\n    External Player Settings: Jucător extern\n    Players:\n      None:\n        Name: Fără\n    Ignore Default Arguments: Ignoră argumentele implicite\n  Distraction Free Settings:\n    Hide Active Subscriptions: Ascunde abonamentele active\n    Hide Live Chat: Ascunde discuția Live\n    Hide Playlists: Ascunde listele de redare\n    Hide Popular Videos: Ascunde videoclipurile populare\n    Hide Trending Videos: Ascundeți videoclipurile în tendințe\n    Hide Recommended Videos: Ascunde videoclipurile recomandate\n    Hide Comment Likes: Ascunde aprecierile comentariilor\n    Hide Channel Subscribers: Ascunde abonații canalului\n    Hide Video Likes And Dislikes: Ascunde like-urile și dislike-urile videoclipului\n    Hide Video Views: Ascunde vizualizările videoclipului\n    Distraction Free Settings: Fără distragere\n    Hide Video Description: Ascunde descrierea videoclipului\n    Hide Comments: Ascunde comentariile\n    Hide Live Streams: Ascunde stream-urile live\n    Hide Sharing Actions: Ascunde butoanele de sharing\n    Hide Videos on Watch: 'Ascunde videoclipurile la vizionare'\n    Hide Chapters: Ascundeți capitolele\n    Display Titles Without Excessive Capitalisation: Afișați titlurile fără majuscule și semne de punctuație excesive\n    Sections:\n      Subscriptions Page: Pagina de abonamente\n      Side Bar: Bara laterală\n      Channel Page: Pagina canalului\n      Watch Page: Pagina de vizionare\n      General: General\n    Hide Channel Podcasts: Ascunde fila „Podcasturi” canal\n    Hide Subscriptions Shorts: Ascundeți Abonamente Shorts\n    Hide Channel Releases: Ascunde fila „Versiuni” canal\n    Hide Subscriptions Videos: Ascundeți Abonamente Videoclipuri\n    Hide Subscriptions Live: Ascundeți Abonamente Live\n    Hide Channels: Ascundeți videoclipurile din canale\n    Hide Channel Shorts: Ascundeți fila \"Shorts\" a canalului\n    Hide Featured Channels: Ascundeți canalele recomandate\n    Hide Channels Placeholder: ID-ul canalului\n    Hide Channel Playlists: Ascunde fila „Playlisturi” de canal\n    Hide Upcoming Premieres: Ascundeți premierele viitoare\n    Hide Profile Pictures in Comments: Ascundeți imaginile de profil în comentarii\n    Hide Channels Already Exists: ID-ul Canalului există deja\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Cuvânt, fragment de cuvânt sau frază\n    Hide Videos, Playlists and Channels Containing Text: Ascundeți videoclipurile și listele de redare care conțin text\n    Hide Channel Home: Ascundeți fila \"Acasă\" a canalului\n    Hide Channels Disabled Message: Unele canale au fost blocate folosind ID și nu au fost procesate. Funcția este blocată în timp ce acele ID-uri se actualizează\n    Hide Channels Invalid: ID-ul canalului furnizat nu este valid\n    Show Added Items: Afișați articolele adăugate\n    Hide Channels API Error: Eroare la preluarea utilizatorului cu ID-ul furnizat. Vă rugăm să verificați din nou dacă ID-ul este corect.\n    Hide Channel Courses: Ascunde fila „Cursuri” a canalului\n    Hide Channel Posts: Ascunde tab-ul \"Postări\" al canalului\n    Hide Subscriptions Posts: Ascunde postările din abonații\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notificare atunci când segmentul sponsorului este sărit\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL-ul API-ului SponsorBlock (Cel implicit este https://sponsor.ajay.app)\n    Enable SponsorBlock: Activați SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Auto Skip: Sari automat\n      Skip Option: Sari peste această opțiune\n      Show In Seek Bar: Arată în bara de derulare\n      Prompt To Skip: Întreabă pentru a sării\n      Do Nothing: Nu fă nimic\n    Category Color: Culoarea categoriilor\n    UseDeArrowTitles: Utilizați titlurile video DeArrow\n    UseDeArrowThumbnails: Utilizați DeArrow pentru miniaturi\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': Url API DeArrow Thumbnail Generator (implicit este https://dearrow-thumb.ajay.app)\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Eroare la obținerea informațiilor despre rețea. Proxy-ul este configurat corect?\n    City: Oraș\n    Region: Regiune\n    Country: Țară\n    Ip: IP\n    Your Info: Informațiile tale\n    Clicking on Test Proxy will send a request to: Făcând clic pe Testați Proxy se va trimite o cerere către\n    Test Proxy: Testați Proxy\n    Proxy Port Number: Numărul portului Proxy\n    Proxy Host: Gazdă Proxy\n    Proxy Protocol: Protocol Proxy\n    Enable Tor / Proxy: Activați Tor / Proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube nu are un proxy încorporat, dar se poate conecta la un proxy extern, cum ar fi unul care rulează pe computer, cum ar fi Tor, sau un proxy extern, cum ar fi un proxy SOCKS5 furnizat de unele VPN-uri. Dacă este activat, asigurați-vă că proxy/Tor este configurat corect, altfel FreeTube nu va putea prelua date.\n  Parental Control Settings:\n    Hide Unsubscribe Button: Ascunde butonul de dezabonare\n    Parental Control Settings: Control parental\n    Show Family Friendly Only: Arata numai conținut family friendly\n    Hide Search Bar: Ascunde bara de căutare\n    Hide Uploader on Watch page: Ascunde autorul pe pagina de vizionare\n  Password Dialog:\n    Password: Parolă\n    Enter Password To Unlock: Introduceți parola pentru a debloca setările\n  Password Settings:\n    Remove Password: Eliminați parola\n    Password Settings: parolă\n    Set Password To Prevent Access: Setați o parolă pentru a împiedica accesul la setări\n    Set Password: Setați parola\n  Experimental Settings:\n    Warning: Aceste setări sunt experimentale, ele pot cauza blocări atunci când sunt activate. Este foarte recomandat să faceți copii de rezervă. Folosiți pe propria răspundere!\n    Replace HTTP Cache: Înlocuiți cache HTTP\n    Experimental Settings: experimental\n  Sort Settings Sections (A-Z): Setări Sortare Secțiuni (A-Z)\n  Return to Settings Menu: Întoarcere la Meniul de Setări\nAbout:\n  #On About page\n  About: 'Despre'\n  #& About\n  Mastodon: Mastodon\n  Email: E-mail\n  Donate: Donează\n  these people and projects: aceste persoane și proiecte\n  Credits: Credite\n  Translate: Traduceți\n  room rules: regulile camerei\n  Chat on Matrix: Chat pe Matrix\n  Blog: Blog\n  Website: Site web\n  Please check for duplicates before posting: Vă rugăm să verificați dacă există dubluri înainte de a posta\n  GitHub issues: Issues pe GitHub\n  Report a problem: Raportați o problemă\n  FAQ: Întrebări frecvente\n  FreeTube Wiki: FreeTube Wiki\n  Help: Ajutor\n  GitHub releases: Lansări GitHub\n  Downloads / Changelog: Descărcări / Jurnal de modificări\n  Source code: Codul sursă\n  Beta: Beta\n  Discussions: Discuții\n  AGPLv3: AGPLv3\nProfile:\n  Profile Select: 'Selectare profil'\n  All Channels: 'Toate canalele'\n  Profile Manager: 'Manager de profil'\n  Create New Profile: 'Creați un profil nou'\n  Edit Profile: 'Editare profil'\n  Color Picker: 'Alegător de culori'\n  Custom Color: 'Culoare personalizată'\n  Profile Preview: 'Previzualizare profil'\n  Create Profile: 'Creați un profil'\n  Update Profile: 'Actualizați profilul'\n  Make Default Profile: 'Faceți profilul implicit'\n  Delete Profile: 'Ștergeți profilul'\n  Are you sure you want to delete this profile?: 'Sunteți sigur că doriți să ștergeți acest profil?'\n  All subscriptions will also be deleted.: 'De asemenea, toate abonamentele vor fi șterse.'\n  Your profile name cannot be empty: 'Numele profilului nu poate fi gol'\n  Profile has been created: 'Profilul a fost creat'\n  Profile has been updated: 'Profilul a fost actualizat'\n  Your default profile has been set to {profile}: 'Profilul dvs. implicit a fost setat la {profile}'\n  Removed {profile} from your profiles: 'Ai eliminat {profile} din profilurile tale'\n  Your default profile has been changed to your primary profile: 'Profilul dvs. implicit a fost schimbat în profilul dvs. principal'\n  '{profile} is now the active profile': '{profile} este acum profilul activ'\n  Subscription List: 'Lista de abonamente'\n  Other Channels: 'Alte canale'\n  '{number} selected': '{number} selectat'\n  Select All: 'Selectați toate'\n  Select None: 'Selectați niciunul'\n  Delete Selected: 'Ștergeți selectat'\n  Add Selected To Profile: 'Adaugă selectate la profil'\n  No channel(s) have been selected: 'Nu a fost selectat niciun canal(e)'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Acesta este profilul dvs. principal.  Sunteți sigur că doriți să ștergeți canalele selectate?  Aceleași canale vor fi șterse în orice profil în care se regăsesc.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Sunteți sigur că doriți să ștergeți canalele selectate?  Acest lucru nu va șterge canalul din niciun alt profil.'\n#On Channel Page\n  Profile Filter: Filtru profil\n  Profile Settings: profil\n  Toggle Profile List: Comutați lista de profil\n  Create Profile Name: Creați numele profilului\n  Profile Name: Numele Profilului\n  Edit Profile Name: Editează Numele Profilului\n  Open Profile Dropdown: Deschideți meniul derulant Profil\n  Close Profile Dropdown: Închideți meniul derulant Profil\nChannel:\n  Subscribe: 'Abonați-vă'\n  Unsubscribe: 'Dezabonați-vă'\n  Channel has been removed from your subscriptions: 'Canalul a fost eliminat din abonamentele tale'\n  Removed subscription from {count} other channel(s): 'Abonament eliminat de pe {count} alt(e) canal(e)'\n  Added channel to your subscriptions: 'Adăugat canal la abonamentele tale'\n  Search Channel: 'Căutare canal'\n  Your search results have returned 0 results: 'Rezultatele căutării tale au returnat 0 rezultate'\n  Videos:\n    Videos: 'Videoclipuri'\n    This channel does not currently have any videos: 'Acest canal nu are în prezent niciun videoclip'\n    Sort Types:\n      Newest: 'Cele mai noi'\n      Oldest: 'Cele mai vechi'\n      Most Popular: 'Cele mai populare'\n  Playlists:\n    Playlists: 'Liste de redare'\n    This channel does not currently have any playlists: 'Acest canal nu are în prezent nici o listă de redare'\n    Sort Types:\n      Last Video Added: 'Ultimul video adăugat'\n      Newest: 'Cele mai noi'\n      Oldest: 'Cele mai vechi'\n  About:\n    About: 'Despre'\n    Channel Description: 'Descrierea canalului'\n    Featured Channels: 'Canale recomandate'\n    Joined: S-a alăturat pe\n    Location: Locație\n    Details: Detalii\n    Tags:\n      Search for: Căutați \"{tag}\"\n      Tags: Tags\n  Posts:\n    Posts: Postări\n    This channel currently does not have any posts: Acest canal nu are momentan nicio postare\n    Reveal Answers: Dezvăluie Răspunsuri\n    Hide Answers: Ascunde Răspunsurile\n    votes: '{votes} voturi'\n    View Full Post: Vezi postarea integrală\n    Video hidden by FreeTube: Videoclip ascuns de FreeTube\n    Viewing Posts Only Supported By Invidious: Vizualizarea postărilor este acceptată numai de Invidious. Mergeți la fila comunității unui canal pentru a vedea conținutul acolo fără Invidious.\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Acest canal are restricții de vârstă și momentan nu poate fi vizionat în FreeTube.\n  This channel does not exist: Acest canal nu există\n  This channel does not allow searching: Acest canal nu permite căutarea\n  Live:\n    Live: Live\n    This channel does not currently have any live streams: Acest canal nu are momentan niciun live stream\n  Shorts:\n    This channel does not currently have any shorts: Acest canal nu are momentan shorts\n  Podcasts:\n    Podcasts: Podcasturi\n    This channel does not currently have any podcasts: Acest canal nu are momentan nici un podcast\n  Releases:\n    Releases: Lansări\n    This channel does not currently have any releases: Acest canal nu are momentan nicio lansare\n  Channel Tabs: Filele canalului\n  Home:\n    Home: acasă\n    View Playlist: Vizualizați lista de redare\n  Courses:\n    Courses: Cursuri\n    This channel does not currently have any courses: Acest canal nu are momentan cursuri\nVideo:\n  Mark As Watched: 'Marcați ca vizionat'\n  Remove From History: 'Eliminați din istoric'\n  Video has been marked as watched: 'Video a fost marcat ca fiind vizionat'\n  Video has been removed from your history: 'Video a fost eliminat din istoric'\n  Open in YouTube: 'Deschideți în YouTube'\n  Copy YouTube Link: 'Copiați linkul YouTube'\n  Open YouTube Embedded Player: 'Deschideți playerul încorporat YouTube'\n  Copy YouTube Embedded Player Link: 'Copiați linkul playerului încorporat YouTube'\n  Open in Invidious: 'Deschideți în Invidious'\n  Copy Invidious Link: 'Copiați linkul Invidious'\n  Views: 'Vizionări'\n  Loop Playlist: 'Lista de redare în buclă'\n  Shuffle Playlist: 'Lista de redare aleatorie'\n  Reverse Playlist: 'Lista de redare inversă'\n  Previous: 'Înapoi'\n  Next: 'Înainte'\n  Watched: 'Vizionat'\n  Autoplay: 'Redare automată'\n  Starting soon, please refresh the page to check again: 'Începe în curând, vă rugăm să reîmprospătați pagina pentru a verifica din nou'\n  # As in a Live Video\n  Live: 'În direct'\n  Live Now: 'în direct acum'\n  Live Chat: 'Chat în direct'\n  Enable Live Chat: 'Activați Chatul Live'\n  Live Chat is currently not supported in this build.: 'Chatul Live nu este acceptat în această versiune.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Chatul live este activat.  Mesajele de chat vor apărea aici odată ce au fost trimise.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Chatul Live nu este acceptat în prezent cu API-ul Invidious.  Este necesară o conexiune directă la YouTube.'\n  Published:\n    In less than a minute: În mai puțin de un minut\n  Published on: 'Publicat pe'\n#& Videos\n  External Player:\n    Unsupported Actions:\n      opening playlists: deschiderea listelor de redare\n      setting a playback rate: setarea unei rate de redare\n      starting video at offset: pornire video la offset\n      looping playlists: liste de redare în buclă\n      shuffling playlists: amestecarea listelor de redare\n      reversing playlists: inversarea listelor de redare\n      opening specific video in a playlist (falling back to opening the video): deschiderea unui anumit videoclip dintr-o listă de redare (revenirea la deschiderea videoclipului)\n    UnsupportedActionTemplate: '{externalPlayer} nu acceptă: {action}'\n    OpeningTemplate: Se deschide {videoOrPlaylist} în {externalPlayer}...\n    playlist: listă de redare\n    video: video\n    OpenInTemplate: Deschideți în {externalPlayer}\n  Sponsor Block category:\n    music offtopic: Muzică offtopic\n    interaction: Interacțiune\n    self-promotion: Autopromovare\n    outro: Outro\n    intro: Introducere\n    sponsor: Sponsor\n    recap: Recapitulare\n    filler: Filler\n  Started streaming on: A început să transmită pe\n  Streamed on: Difuzat pe\n  Copy Invidious Channel Link: Copiați linkul canalului Invidious\n  Open Channel in Invidious: Canal deschis în Invidious\n  Copy YouTube Channel Link: Copiați linkul canalului YouTube\n  Open Channel in YouTube: Deschideți canalul în YouTube\n  Video has been removed from your saved list: Videoclipul a fost eliminat din lista ta de salvări\n  Video has been saved: Videoclipul a fost salvat\n  Save Video: Salvați video\n  Scroll to Bottom: Derulați până jos\n  Upcoming: Urmează\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Chatul live nu este disponibil pentru acest flux. Este posibil să fi fost dezactivat de persoana care a încărcat.\n  Premieres: Premiere\n  Show Super Chat Comment: Afișați comentariul Super Chat\n  Hide Channel: Ascunde canalul\n  Unhide Channel: Arată canalul\n#& Playlists\n  Player:\n    Theatre Mode: Modul teatru\n    Audio Tracks: Piese audio\n    Exit Theatre Mode: Ieșire din modul teatru\n    Autoplay is off: Redarea automată este oprită\n    Autoplay is on: Redarea automată este pornită\n    Take Screenshot: Faceți o captură de ecran\n    Stats:\n      Resolution: 'Rezoluție: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Dimensiuni player: {width}x{height}'\n      Dropped Frames / Total Frames: 'Cadre eliminate: {droppedFrames} / Total cadre: {totalFrames}'\n      CodecsVideoAudio: 'Codecuri: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codecuri: {videoCodec} / {audioCodec}'\n      Stats: Statistici\n      Video ID: 'ID videoclip: {videoId}'\n      Media Formats: 'Formate media: {formats}'\n      Bitrate: 'Rată de biți: {bitrate} kbps'\n      Volume: 'Volum: {volumePercentage}%'\n      Bandwidth: 'Lățime de bandă: {bandwidth} kbps'\n      Buffered: 'Descărcat: {bufferedPercentage}%'\n    Show Stats: Afișează statistici\n    Hide Stats: ascunde statistici\n    You appear to be offline: Pari a fi offline.\n    Playback will resume automatically when your connection comes back: Redarea se va relua automat când se reia conexiunea.\n    Skipped segment: Segment {segmentCategory} omis\n    TranslatedCaptionTemplate: '{language} (tradus din „{originalLanguage}”)'\n    Full Window: Fereastra plină\n    Exit Full Window: Ieșiți din fereastra completă\n  More Options: Mai multe opțiuni\n  AgeRestricted: Videoclipurile cu restricții de vârstă nu pot fi vizionate cu FreeTube, deoarece necesită autentificare la Google și utilizarea unui cont YouTube verificat în funcție de vârstă.\n  Unlisted: nelistate\n  MembersOnly: Videoclipurile destinate exclusiv membrilor nu pot fi vizionate cu FreeTube, deoarece necesită autentificare Google și abonament plătit la canalul persoanei care a încărcat.\n  DRMProtected: Videoclipurile protejate DRM nu pot fi redate în FreeTube, deoarece necesită componente proprietare, cu sursă închisă. Dacă doriți să vizionați acest videoclip, vizionați-l pe site-ul oficial YouTube într-un browser web compatibil DRM.\n  DeArrow:\n    Show Original Details: Afișați detaliile originale\n    Show Modified Details: Afișați detaliile modificate\n  IP block: YouTube a blocat adresa dvs. IP pentru a nu viziona videoclipuri. Vă rugăm să încercați să comutați la un alt VPN sau proxy.\n  Save Watched Progress: Salvează progresul vizionat\n  Watched Progress Saved: Progresul vizionat a fost salvat\nPlaylist:\n  #& About\n  View Full Playlist: 'Vezi lista de redare completă'\n  Last Updated On: 'Ultima actualizare la'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Listă de redare\n  Sort By:\n    AuthorAscending: Autor (A-Z)\n    PublishedOldest: Cel mai devreme publicat mai întâi\n    VideoTitleDescending: Titlu (Z-A)\n    DateAddedNewest: Cel mai recent adăugat primul\n    DateAddedOldest: Cel mai devreme adăugat primul\n    Custom: personalizat\n    VideoDurationDescending: Durată (cel mai lung mai întâi)\n    PublishedNewest: Cel mai recent publicat primul\n    VideoDurationAscending: Durată (cel mai scurt mai întâi)\n    VideoTitleAscending: Titlu (A-Z)\n    AuthorDescending: Autor (Z-A)\nChange Format:\n  Change Media Formats: 'Schimbați formatele video'\n  Use Dash Formats: 'Utilizați formate DASH'\n  Use Legacy Formats: 'Utilizați formate vechi'\n  Use Audio Formats: 'Utilizați formate audio'\n  Dash formats are not available for this video: 'Formatele DASH nu sunt disponibile pentru acest videoclip'\n  Audio formats are not available for this video: 'Formatele audio nu sunt disponibile pentru acest videoclip'\n  Legacy formats are not available for this video: Formatele vechi nu sunt disponibile pentru acest videoclip\nShare:\n  Share Video: 'Distribuire videoclipuri'\n  Share Playlist: 'Distribuie lista de redare'\n  Include Timestamp: 'Includeți timpul de începere'\n  Copy Link: 'Copiați linkul'\n  Open Link: 'Deschideți linkul'\n  Copy Embed: 'Copiați încorporarea'\n  Open Embed: 'Deschideți încorporarea'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious copiat în clipboard'\n  Invidious Embed URL copied to clipboard: 'URL de încorporare Invidious copiat în clipboard'\n  YouTube URL copied to clipboard: 'URL-ul YouTube copiat în clipboard'\n  YouTube Embed URL copied to clipboard: 'URL de încorporare YouTube copiat în clipboard'\n  YouTube Channel URL copied to clipboard: URL-ul canalului YouTube copiat în clipboard\n  Invidious Channel URL copied to clipboard: URL-ul Invidious al canalului a fost copiat în clipboard\n  Share Channel: Distribuie canalul\nMini Player: 'Mini Player'\nComments:\n  Comments: 'Comentarii'\n  Click to View Comments: 'Faceți clic pentru a vedea comentariile'\n  Getting comment replies, please wait: 'Se obțin răspunsurile comentariului, vă rugăm să așteptați'\n  There are no more comments for this video: 'Nu mai există niciun comentariu pentru acest videoclip'\n  Hide Comments: 'Ascundeți comentariile'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Nu există comentarii disponibile pentru acest videoclip'\n  Load More Comments: 'Încărcați mai multe comentarii'\n  Show More Replies: Afișați mai multe răspunsuri\n  Newest first: Cele mai noi primele\n  Top comments: Cele mai bune\n  Pinned by: Lipit de\n  Member: Membru\n  Hearted: Inima\n  View {replyCount} replies: '{replyCount} răspunsuri'\n  Subscribed: Abonat\n  There are no comments available for this post: Nu există comentarii disponibile pentru această postare\nUp Next: 'În continuare'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Eroare API locală (Faceți clic pentru a copia)'\nInvidious API Error (Click to copy): 'Eroare API Invidious (Faceți clic pentru a copia)'\nFalling back to Invidious API: 'Revenine la Invidious API'\nFalling back to Local API: 'Revenire la API-ul local'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Acest videoclip nu este disponibil din cauza lipsei de formate. Acest lucru se poate întâmpla din cauza indisponibilității țării.'\nLoop is now disabled: 'Bucla este acum dezactivată'\nLoop is now enabled: 'Bucla este acum activată'\nShuffle is now disabled: 'Amestecarea este acum dezactivată'\nShuffle is now enabled: 'Amestecarea este acum activată'\nThe playlist has been reversed: 'Lista de redare a fost inversată'\nPlaying Next Video: 'Se redă următorul videoclip'\nPlaying Previous Video: 'Se redă videoclipul anterior'\nCanceled next video autoplay: 'S-a anulat redarea automată a următorului videoclip'\n'The playlist has ended. Enable loop to continue playing': 'Lista de redare s-a încheiat.  Activați bucla pentru a continua redarea'\n\nYes: 'Da'\nNo: 'Nu'\nMore: Mai multe\nSearch Bar:\n  Clear Input: Ștergeți intrarea\n  Remove: Șterge\nAre you sure you want to open this link?: Sunteți sigur că doriți să deschideți acest link?\nOpen New Window: Deschide fereastră nouă\nDefault Invidious instance has been cleared: Instanța implicită Invidious a fost eliminată\nDefault Invidious instance has been set to {instance}: Instanța implicită Invidious a fost setată la {instance}\nPlaying Next Video Interval: Se redară următorul videoclip în cel mai scurt timp. Faceți clic pentru a anula. | Se redă următorul videoclip în {nextVideoInterval} secundă. Faceți clic pentru a anula. | Se redă următorul videoclip în {nextVideoInterval} secunde. Faceți clic pentru a anula.\nUnknown YouTube url type, cannot be opened in app: Tip url YouTube necunoscut, nu poate fi deschis în aplicație\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Atunci când este activat, FreeTube va utiliza RSS în locul metodei implicite de preluare a fluxului dvs. de abonament. RSS este mai rapid și previne blocarea IP, dar nu oferă anumite informații, cum ar fi durata videoclipului, starea live sau postările\n    Fetch Automatically: Când activat, FreeTube va prelua automat feed-ul de abonament la pornire și când se deschide o fereastră nouă.\n  External Player Settings:\n    Custom External Player Arguments: Orice argumente personalizate din linia de comandă, pe care doriți să le transmiteți playerului extern.\n    Ignore Warnings: Suprimarea avertismentelor în cazul în care playerul extern curent nu acceptă acțiunea curentă (de exemplu, inversarea listelor de redare etc.).\n    Custom External Player Executable: În mod implicit, FreeTube va presupune că playerul extern ales poate fi găsit prin intermediul variabilei de mediu PATH. Dacă este necesar, aici poate fi setată o cale personalizată.\n    External Player: Alegerea unui player extern va afișa o pictogramă, pentru a deschide videoclipul (playlist, dacă este acceptat) în playerul extern, pe thumbnail. Atenție, setările Invidious nu afectează playerele externe.\n    DefaultCustomArgumentsTemplate: \"(Implicit: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Nu trimiteți niciun argument implicit către playerul extern în afară de URL-ul video (de exemplu, rata de redare, URL-ul listei de redare etc.). Argumentele personalizate vor fi transmise în continuare.\n  Player Settings:\n    Default Video Format: Setați formatele utilizate la redarea unui videoclip. Formatele DASH pot reda calități superioare. Formatele tradiționale sunt limitate la maximum 360p, dar utilizează mai puțină lățime de bandă. Formatele audio sunt doar fluxuri audio.\n    Proxy Videos Through Invidious: Se va conecta la Invidious pentru a servi videoclipuri în loc să facă o conexiune directă la YouTube.\n    Scroll Playback Rate Over Video Player: În timp ce cursorul se află deasupra videoclipului, țineți apăsată tasta Control (tasta Command pe Mac) și derulați rotița mouse-ului înainte sau înapoi pentru a controla rata de redare. Țineți apăsată tasta Control (tasta Command pe Mac) și faceți clic cu butonul stâng al mouse-ului pentru a reveni rapid la rata de redare implicită (1x, cu excepția cazului în care aceasta a fost modificată în setări).\n    Skip by Scrolling Over Video Player: Utilizați rotița de derulare pentru a trece prin videoclip, stil MPV.\n  General Settings:\n    External Link Handling: \"Alegeți comportamentul implicit atunci când faceți clic pe un link care nu poate fi deschis în FreeTube.\\nÎn mod implicit, FreeTube va deschide linkul accesat în browserul dvs. implicit.\\n\"\n    Region for Trending: Regiunea de tendințe vă permite să alegeți ce videoclipuri în tendințe din fiecare țară doriți să fie afișate.\n    Invidious Instance: Instanța Invidious la care FreeTube se va conecta pentru apelurile API.\n    Thumbnail Preference: Toate miniaturile din FreeTube vor fi înlocuite cu un cadru al videoclipului, încețoșat sau ascuns în loc de miniatura implicită.\n    Fallback to Non-Preferred Backend on Failure: Atunci când API-ul preferat are o problemă, FreeTube va încerca automat să utilizeze API-ul nepreferat ca metodă de rezervă, atunci când este activat.\n    Preferred API Backend: Alegeți backend-ul pe care FreeTube îl folosește pentru a obține date. API-ul local este un extractor incorporat. API-ul Invidious necesită un server Invidious la care să vă conectați.\n    Open Deep Links In New Window: URL-urile transmise către FreeTube, cum ar fi prin redirecționarea extensiilor de browser sau a argumentelor din linia de comandă, sunt deschise într-o fereastră nouă.\n  Distraction Free Settings:\n    Hide Channels: Introduceți un ID de canal pentru a ascunde toate videoclipurile, listele de redare și canalul însuși de la apariția în căutare, tendințe, cele mai populare și recomandate. ID-ul canalului introdus trebuie să fie o potrivire completă și este sensibil la majuscule și minuscule.\n    Hide Subscriptions Live: Această setare este înlocuită de setarea \"{appWideSetting}” la nivel de aplicație, în secțiunea „{subsection}” din „{settingsSection}”\n    Hide Videos, Playlists and Channels Containing Text: Introduceți un cuvânt, un fragment de cuvânt sau o frază (fără a ține cont de majuscule) pentru a ascunde toate videoclipurile și listele de redare ale căror titluri originale conțin acest cuvânt în întregul FreeTube, excluzând doar Istoric, Listele dvs. de redare și videoclipurile din listele de redare.\n    Hide Videos on Watch: Ascunde videoclipurile vizionate din secțiunile Shorts, Live și Videoclipuri de pe paginile Abonamente și Canal. Aceasta nu afectează fila Acasă de pe paginile de canal\n  Experimental Settings:\n    Replace HTTP Cache: Dezactivează memoria cache HTTP bazată pe disc Electron și activează un cache de imagini personalizat în memorie. Va duce la o utilizare crescută a memoriei RAM.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Înlocuiți titlurile video cu titluri trimise de utilizator de la DeArrow.\n    UseDeArrowThumbnails: Înlocuiți miniaturile video cu miniaturi de la DeArrow.\nExternal link opening has been disabled in the general settings: Deschiderea linkurilor externe a fost dezactivată în setările generale\nNew Window: Fereastră nouă\nChannels:\n  Channels: Canale\n  Title: Listă de canale\n  Search bar placeholder: Caută canale\n  Count: '{number} canal(e) găsit(e).'\n  Empty: Lista ta de canale este goală.\n  Unsubscribe Prompt: Ești sigur că dorești să te dezabonezi de la \"{channelName}\"?\nScreenshot Success: Captură de ecran salvată\nScreenshot Error: Captura de ecran a eșuat {error}\nPreferences: Preferințe\nChapters:\n  Chapters: Capitole\n  Key Moments: Momente cheie\nClipboard:\n  Cannot access clipboard without a secure connection: Nu se poate accesa clipboard-ul fără o conexiune securizată\n  Copy failed: Copierea în clipboard a eșuat\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Acest hashtag nu are momentan niciun videoclip\nOk: OK\nGo to page: Mergeți la {page}\nClose Banner: Închideți bannerul\nAge Restricted:\n  This video is age restricted: Acest videoclip este restricționat în funcție de vârstă\n  This channel is age restricted: Acest canal este restricționat de vârstă\nChannel Hidden: '{channel} adăugat la filtrul de canal'\nTrimmed input must be at least N characters long: Intrarea tăiată trebuie să aibă cel puțin 1 caracter | Intrarea tăiată trebuie să aibă cel puțin {length} caractere\nTag already exists: Eticheta \"{tagName}\" există deja\nChannel Unhidden: '{channel} eliminat din filtrul de canale'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Subtitrări\n    Closed Captions: Subtitrări Complexe\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Noi\n    3D: 3D\nFeed:\n  Refresh Feed: Reîmprospătează {subscriptionName}\n  Feed Last Updated: '{feedName} ultima actualizare a fluxului: {date}'\nRight-click or hold to see history: Clic dreapta sau apasă lung pentru a vedea istoricul\nSearch character limit: Căutarea are mai mult de {searchCharacterLimit} caractere\nKeyboardShortcutPrompt:\n  Fullscreen: Comutați ecranul complet\n  Picture in Picture: Comutați modul Imagine în imagine\n  Play: Comutați redare/pauză\n  Full Window: Comutați fereastra completă\n  Theatre Mode: Comutați modul teatru\n  Take Screenshot: Faceți o captură de ecran\n  Mute: Comutați în modul fără sunet\n  Toggle Developer Tools: Comutați instrumentele pentru dezvoltatori\n  Captions: Activarea/Dezactivarea subtitrărilor\n  Navigate to History: Navigați la pagina Istoric\n  Large Rewind: Derulați înapoi 10 secunde / Derulați înapoi videoclipul în funcție de rata de redare video curentă\n  Keyboard Shortcuts: Comenzi rapide de la tastatură\n  Sections:\n    Video:\n      Playback: 'Video: Redare'\n      General: 'Video: General'\n    App:\n      General: 'Aplicație: General'\n      Situational: 'Aplicație: Situațional'\n  Show Keyboard Shortcuts: Afișați comenzile rapide de la tastatură\n  History Backward: Mergeți înapoi cu o pagină\n  History Forward: Mergi înainte cu o pagină\n  New Window: Creați o fereastră nouă\n  Navigate to Settings: Navigați la pagina Setări\n  Refresh: Actualizați feed-ul cu cel mai recent conținut\n  Focus Secondary Search: Concentrați-vă pe bara de căutare secundară (dacă există una)\n  Stats: Afișați statisticile video\n  Large Fast Forward: Înainte 10 secunde / Derulare rapidă pe baza vitezei actuale de redare video\n  Search in New Window: Căutare într-o fereastră nouă\n  Increase Video Speed: Creșteți viteza video în funcție de intervalul ratei de redare video\n  Small Rewind: Derulează înapoi X secunde pe baza intervalului de derulare înapoi și a vitezei actuale de redare video\n  Last Chapter: Ultimul capitol\n  Decrease Video Speed: Reducerea vitezei video în funcție de intervalul ratei de redare video\n  Volume Up: Creșterea volumului\n  Skip by Tenths: Salt prin video în funcție de procent (3 salturi la 30% din durată)\n  Focus Search: Concentrați-vă pe bara de căutare\n  Last Frame: Cadrul anterior (în timpul pauzei)\n  Next Frame: Următorul cadru (în timpul pauzei)\n  Small Fast Forward: Derulare rapidă X secunde pe baza intervalului de derulare rapidă și a vitezei actuale de redare video\n  Next Chapter: Capitolul următor\n  Zoom In: zoom in\n  Zoom Out: micșorați imaginea\n  Minimize Window: Miminizarea ferestrei\n  Close Window: Închideți fereastra\n  Reset Zoom: Resetați nivelul de zoom / scala UI\n  Volume Down: scăderea volumului\n  Home: Treci la începutul videoclipului\n  End: Treci la finalul videoclipului\n  Skip to Next Video: Treci la următorul videoclip din playlist sau la următorul videoclip recomandat\n  Skip to Previous Video: Treci la videoclipul anterior din playlist\nMoments Ago: acum câteva momente\nAutoplay Interruption Timer: Redarea automată anulată din cauza a {autoplayInterruptionIntervalHours} ore de inactivitate\nshortcutLabelSeparator: ｜\nCancel: Anulează\nDescription:\n  Expand Description: '...Mai mult'\n  Collapse Description: arata mai putin\nKeys:\n  arrowleft: Săgeată stânga\n  arrowup: sus Săgeată\n  enter: Introduceți\n  plus: plus\n  arrowright: dreapta Săgeată\n  shift: schimbare\n  alt: Alte\n  ctrl: ctrl\n  arrowdown: Săgeată în jos\ncheckmark: ✓\nYes, Delete: da, șterge\nYes, Open Link: Da, Link deschis\nDisplay Label: '{label}: {value}'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nYes, Restart: Da, repornire\nshortcutJoinOperator: +\n"
  },
  {
    "path": "static/locales/ru.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Файл'\nQuit: 'Выход'\nEdit: 'Редактировать'\nUndo: 'Отменить'\nRedo: 'Вернуть'\nCut: 'Вырезать'\nCopy: 'Копировать'\nPaste: 'Вставить'\nDelete: 'Удалить'\nSelect all: 'Выбрать все'\nToggle Developer Tools: 'Показать инструменты для разработчиков'\nActual size: 'Оригинальный масштаб'\nZoom in: 'Увеличить'\nZoom out: 'Уменьшить'\nToggle fullscreen: 'Во весь экран'\nWindow: 'Окно'\nMinimize: 'Свернуть'\nClose: 'Закрыть'\nBack: 'Назад'\nForward: 'Вперёд'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Видео'\n  Shorts: Шортс\n  Live: Трансляции\n  Posts: Записи\n  Sort By: Сортировать по\n\n# Search Bar\n  Counts:\n    Video Count: 1 видео | {count} видео\n    Subscriber Count: 1 подписчик | {count} подписчика(ов)\n    View Count: 1 просмотр | {count} просмотра(ов)\n    Watching Count: 1 смотрящий | {count} смотрящих\n    Channel Count: 1 канал | {count} канала(ов)\n    Comment Count: 1 комментарий | {count} комментариев\n    Like Count: 1 лайк | {count} лайков\nSearch / Go to URL: 'Поиск / Перейти по адресу'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Фильтры поиска'\n  Sort By:\n    Most Relevant: 'Наиболее актуальным'\n    Rating: 'Оценке'\n    Upload Date: 'Дате загрузки'\n    View Count: 'Количеству просмотров'\n  Time:\n    Time: 'Время'\n    Any Time: 'Любое время'\n    Last Hour: 'Последний час'\n    Today: 'Сегодня'\n    This Week: 'На этой неделе'\n    This Month: 'В этом месяце'\n    This Year: 'В этом году'\n  Type:\n    Type: 'Тип'\n    All Types: 'Все типы'\n    Videos: 'Видео'\n    Channels: 'Каналы'\n    #& Playlists\n    Movies: Фильмы\n  Duration:\n    Duration: 'Длительность'\n    All Durations: 'Любая длительность'\n    Short (< 4 minutes): 'Короткие (< 4 минут)'\n    Long (> 20 minutes): 'Длинные (> 20 минут)'\n  # On Search Page\n    Medium (4 - 20 minutes): Средние (4—20 мин)\n  Search Results: 'Результаты поиска'\n  Fetching results. Please wait: 'Получение результатов. Подождите'\n  Fetch more results: 'Получить больше результатов'\n# Sidebar\n  There are no more results for this search: Больше результатов по этому запросу нет\n  Features:\n    Features: Дополнительно\n    HD: HD\n    Subtitles: Субтитры\n    Creative Commons: Лицензии Creative Commons\n    3D: 3D\n    Live: Прямой эфир\n    4K: 4K\n    360 Video: 360 видео\n    Location: Местоположение\n    VR180: VR180\n    HDR: HDR\n  Clear Filters: Очистить фильтры\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Подписки'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'В настоящее время подписок нет. Если вы хотите импортировать свои подписки, вы можете перейти в Настройки Данных и выбрать Импорт Подписок или найти канал и подписаться на него.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Эта учётная запись имеет большое количество подписок. Принудительно используется RSS, чтобы избежать ограничения скорости\n  Load More Videos: Загрузить больше видео\n  Error Channels: Каналы с ошибками\n  Disabled Automatic Fetching: Вы отключили автоматическое получение подписок. Обновите подписки, чтобы отобразить результат.\n  Empty Channels: Ваши подписанные каналы в настоящее время не имеют видео.\n  Subscriptions Tabs: Вкладки подписок\n  All Subscription Tabs Hidden: Все вкладки подписок скрыты. Чтобы увидеть содержимое здесь, пожалуйста, раскройте некоторые вкладки в разделе «{subsection}» в «{settingsSection}».\n  Empty Posts: Ваши подписанные каналы в настоящее время не имеют записей.\n  Load More Posts: Загрузить больше записей\nTrending:\n  Trending: 'В тренде'\n  Trending Tabs: Вкладки В тренде\n  Gaming: Игры\n  Sports: Спорт\nMost Popular: 'Самые популярные'\nPlaylists: 'Плейлисты'\nUser Playlists:\n  Your Playlists: 'Ваши плейлисты'\n  Search bar placeholder: Поиск плейлистов\n  Empty Search Message: В этом плейлисте нет видео, соответствующих вашему запросу\n  This playlist currently has no videos.: В этом плейлисте нет видео.\n  Add to Playlist: Добавить в плейлист\n  Move Video Up: Передвинуть видео вверх\n  Move Video Down: Передвинуть видео вниз\n  Remove from Playlist: Удалить из плейлиста\n  Playlist Name: Название плейлиста\n  Copy Playlist: Скопировать плейлист\n  Delete Playlist: Удалить плейлист\n  Are you sure you want to delete this playlist? This cannot be undone: Вы действительно хотите удалить этот плейлист? Это действие нелья отменить.\n  Sort By:\n    NameAscending: А-Я\n    NameDescending: Я-А\n    EarliestCreatedFirst: Дата создания (Сначала старые)\n    LatestCreatedFirst: Дата создания (Сначала новые)\n    LatestUpdatedFirst: Дата обновления (сначала новые)\n    EarliestUpdatedFirst: Дата обновления (сначала старые)\n    LatestPlayedFirst: Дата воспроизведения (Сначала новые)\n    EarliestPlayedFirst: Дата воспроизведения (Сначала старые)\n  SinglePlaylistView:\n    Toast:\n      There was a problem with removing this video: Возникла проблема с удалением этого видео\n      Playlist name cannot be empty. Please input a name.: Название плейлиста не может быть пустым. Пожалуйста, вставьте название.\n      Playlist has been updated.: Плейлист обновлён.\n      \"{videoCount} video(s) have been removed\": 1 видео было удалено | {videoCount} видео было удалено\n      This playlist does not exist: Этот плейлист не существует\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Некоторые видео в плейлисте ещё не загружены. Нажмите сюда, чтобы всё равно скопировать.\n      There were no videos to remove.: Нет видео для удаления.\n      This playlist is protected and cannot be removed.: Этот плейлист защищён и не может быть удалён.\n      There was an issue with updating this playlist.: Возникли проблемы с обновлением плейлиста.\n      Playlist {playlistName} has been deleted.: Плейлист {playlistName} удалён.\n      This video cannot be moved up.: Это видео нельзя передвинуть вверх.\n      This video cannot be moved down.: Это видео нельзя передвинуть вниз.\n      Video has been removed: Видео было удалено\n      Reverted to use {oldPlaylistName} for quick bookmark: Плейлист {oldPlaylistName} снова используется для закладок\n      This playlist is now used for quick bookmark: Этот плейлист теперь используется для быстрого создания закладок\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Этот плейлист теперь используется для закладок вместо {oldPlaylistName}. Нажмите здесь, чтобы отменить\n      This playlist is already being used for quick bookmark.: Этот плейлист уже используется для быстрого создания закладок.\n      This playlist has a video with a duration error: Этот плейлист содержит хотя-бы одно видео без указанной продолжительности, он будет отсортирован как если бы их продолжительность была равна нулю.\n      Video has been removed. Click here to undo.: Видео было удалено. Нажмите здесь, чтобы отменить просмотр.\n    Search for Videos: Поиск видео\n  AddVideoPrompt:\n    N playlists selected: '{playlistCount} выбрано'\n    Search in Playlists: Поиск в плейлистах\n    Save: Сохранить\n    Toast:\n      You haven't selected any playlist yet.: Вы не выбрали ни одного плейлиста.\n      \"Video(s) added to {playlistCount} playlists\": \"Видео добавлено в 1 плейлист | Видео добавлено в {playlistCount} плейлиста(ов)\"\n    Select a playlist to add your N videos to: Выберите плейлист для добавления видео | Выберите плейлист для добавления {videoCount} видео\n    Added {count} Times: Уже добавлено | Добавлено {count} раз\n    Allow Adding Duplicate Video(s): Разрешить добавление дубликатов видео\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": 'Будет добавлено {videoCount} из {totalVideoCount} видео'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} видео уже добавлено'\n  CreatePlaylistPrompt:\n    Toast:\n      Playlist {playlistName} has been successfully created.: Плейлист {playlistName} успешно создан.\n      There is already a playlist with this name. Please pick a different name.: Уже есть плейлист с таким названием. Пожалуйста, выберите другое название.\n      There was an issue with creating the playlist.: Возникли проблемы с созданием плейлиста.\n    New Playlist Name: Новое название плейлиста\n    Create: Создать\n  Playlist Description: Описание плейлиста\n  Save Changes: Сохранить изменения\n  Edit Playlist Info: Изменить сведения о плейлисте\n  Remove Watched Videos: Удалить просмотренные видео\n  Cancel: Отмена\n  You have no playlists. Click on the create new playlist button to create a new one.: У вас нет плейлистов. Нажмите кнопку «Создать плейлист», чтобы добавить новый.\n  Create New Playlist: Создать новый плейлист\n  Add to Favorites: Добавить в {playlistName}\n  Remove from Favorites: Убрать из {playlistName}\n  Playlists with Matching Videos: Плейлисты с соответствующими видеороликами\n  Enable Quick Bookmark With This Playlist: Добавлять Закладки в этот плейлист\n  Quick Bookmark Enabled: Закладка включена\n  Cannot delete the quick bookmark target playlist.: Нельзя удалить плейлист, который используется для Закладок.\n  Remove Duplicate Videos: Удалить дубликаты видео\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Вы уверены, что хотите удалить 1 дублирующее видео из этого плейлиста? Это нельзя отменить. | Вы уверены, что хотите удалить {playlistItemCount} дубликатов видео из этого плейлиста? Это нельзя отменить.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Вы уверены, что хотите удалить 1 просмотренное видео из этого плейлиста? Это нельзя отменить. | Вы уверены, что хотите удалить {playlistItemCount} просмотренных видео из этого плейлиста? Это нельзя отменить.\n  Export Playlist: Экспортировать этот плейлист\n  The playlist has been successfully exported: Плейлист успешно экспортирован\n  TotalTimePlaylist: 'Общее время: {duration}'\n  Export list of URLs: Экспортировать список URL-адресов\nHistory:\n  # On History Page\n  History: 'История'\n  Watch History: 'Посмотреть историю'\n  Your history list is currently empty.: 'История просмотров в настоящее время пуста.'\n  Search bar placeholder: Поиск в Истории\n  Empty Search Message: В истории нет видео, соответствующих критериям поиска\n  Case Sensitive Search: Поиск с учетом регистра\n  DateNewestHistory: Дата просмотра (Сначала новые)\n  DateOldestHistory: Дата просмотра (Сначала старые)\nSettings:\n  # On Settings Page\n  Settings: 'Настройки'\n  General Settings:\n    General Settings: 'Общие'\n    Fallback to Non-Preferred Backend on Failure: 'Откатить к непредпочтительному движку при сбое'\n    Enable Search Suggestions: 'Включить поисковые предложения'\n    Default Landing Page: 'Страница по умолчанию'\n    Locale Preference: 'Язык приложения'\n    Preferred API Backend:\n      Preferred API Backend: 'Предпочитаемый движок API'\n      Local API: 'Локальный API'\n      Invidious API: 'Клиент Invidious API'\n    Video View Type:\n      Video View Type: 'Способ отображения видео'\n      Grid: 'Сеткой'\n      List: 'Списком'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Выбор миниатюры'\n      Default: 'По умолчанию'\n      Beginning: 'Начало'\n      Middle: 'Середина'\n      End: 'Конец'\n      Blur: Размыть\n      Hidden: Скрыть\n    Region for Trending: 'Регион для В тренде'\n        #! List countries\n    Check for Latest Blog Posts: Проверять последние записи в блоге\n    Check for Updates: Проверять наличие новых версий\n    View all Invidious instance information: Просмотреть все инстанции Invidious\n    System Default: Системные настройки по умолчанию\n    Clear Default Instance: Очистить инстанцию по умолчанию\n    Set Current Instance as Default: Установить текущую инстанцию по умолчанию\n    Current instance will be randomized on startup: Текущая инстанция при запуске будет выбрана случайно\n    No default instance has been set: Не установлена инстанция по умолчанию\n    The currently set default instance is {instance}: 'Текущая установленная инстанция по умолчанию: {instance}'\n    Current Invidious Instance: Текущая инстанция Invidious\n    External Link Handling:\n      No Action: Ничего не делать\n      Ask Before Opening Link: Спрашивать перед переходом по ссылке\n      Open Link: Переходить по ссылке\n      External Link Handling: Обращение со сторонними ссылками\n    Auto Load Next Page:\n      Label: Авто-загрузка следующей страницы\n      Tooltip: Автоматическая загрузка дополнительных страниц и комментариев.\n    Open Deep Links In New Window: Открыть URL-адреса, переданные в FreeTube, в новом окне\n    Minimize to system tray: Сворачивать в область уведомлений\n  Theme Settings:\n    Theme Settings: 'Внешний вид'\n    Match Top Bar with Main Color: 'Использовать основной цвет к верхней панели'\n    Base Theme:\n      Base Theme: 'Основная тема'\n      Black: 'Чёрная'\n      Dark: 'Тёмная'\n      Light: 'Светлая'\n      Dracula: 'Дракула'\n      System Default: Системная\n      Catppuccin Mocha: Катпучино Мока\n      Pastel Pink: Пастельно-розовый\n      Hot Pink: Ярко-розовый\n      Nordic: Северный\n      Solarized Dark: Solarized Тёмный\n      Solarized Light: Solarized Светлый\n      Gruvbox Dark: Gruvbox Темный\n      Gruvbox Light: Gruvbox Светлый\n      Catppuccin Frappe: Катпучино Фраппе\n      Everforest Dark Hard: Everforest Тёмный Глубокий\n      Everforest Dark Medium: Everforest Тёмный Средний\n      Everforest Dark Low: Everforest Тёмный Лёгкий\n      Everforest Light Hard: Everforest Светлый Глубокий\n      Everforest Light Medium: Everforest Светлый Средний\n      Everforest Light Low: Everforest Светлый Лёгкий\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Основной цвет темы'\n      Red: 'Красный'\n      Pink: 'Розовый'\n      Purple: 'Фиолетовый'\n      Deep Purple: 'Тёмно-фиолетовый'\n      Indigo: 'Индиго'\n      Blue: 'Синий'\n      Light Blue: 'Голубой'\n      Cyan: 'Бирюзовый'\n      Teal: 'Бирюзово-зелёный'\n      Green: 'Зелёный'\n      Light Green: 'Салатовый'\n      Lime: 'Лайм'\n      Yellow: 'Жёлтый'\n      Amber: 'Янтарный'\n      Orange: 'Оранжевый'\n      Deep Orange: 'Тёмно-оранжевый'\n      Dracula Cyan: 'Бирюзовый - Dracula'\n      Dracula Green: 'Зелёный - Dracula'\n      Dracula Orange: 'Оранжевый - Dracula'\n      Dracula Pink: 'Розовый - Dracula'\n      Dracula Purple: 'Фиолетовый - Dracula'\n      Dracula Red: 'Красный - Dracula'\n      Dracula Yellow: 'Жёлтый - Dracula'\n      Catppuccin Mocha Green: Зелёный - Catppuccin Mocha\n      Catppuccin Mocha Teal: Тёмно-бирюзовый - Catppuccin Mocha\n      Catppuccin Mocha Rosewater: Розовая вода - Catppuccin Mocha\n      Catppuccin Mocha Flamingo: Фламинго - Catppuccin Mocha\n      Catppuccin Mocha Pink: Розовый - Catppuccin Mocha\n      Catppuccin Mocha Mauve: Сиреневый - Catppuccin Mocha\n      Catppuccin Mocha Red: Красный - Catppuccin Mocha\n      Catppuccin Mocha Maroon: Бордовый - Catppuccin Mocha\n      Catppuccin Mocha Peach: Персиковый - Catppuccin Mocha\n      Catppuccin Mocha Yellow: Жёлтый - Catppuccin Mocha\n      Catppuccin Mocha Sky: Светло-голубой - Catppuccin Mocha\n      Catppuccin Mocha Sapphire: Сапфировый - Catppuccin Mocha\n      Catppuccin Mocha Blue: Синий - Catppuccin Mocha\n      Catppuccin Mocha Lavender: Лавандовый - Catppuccin Mocha\n      Solarized Yellow: Жёлтый - Solarized\n      Solarized Orange: Оранжевый - Solarized\n      Solarized Red: Красный - Solarized\n      Solarized Magenta: Пурпурный - Solarized\n      Solarized Blue: Синий - Solarized\n      Solarized Cyan: Бирюзовый - Solarized\n      Solarized Violet: Фиолетовый - Solarized\n      Solarized Green: Зелёный - Solarized\n      Gruvbox Dark Green: Зелёный - Gruvbox Dark\n      Gruvbox Dark Blue: Синий - Gruvbox Dark\n      Gruvbox Dark Purple: Фиолетовый - Gruvbox Dark\n      Gruvbox Dark Aqua: Аква - Gruvbox Dark\n      Gruvbox Light Red: Красный - Gruvbox Light\n      Gruvbox Light Blue: Синий - Gruvbox Light\n      Gruvbox Light Purple: Фиолетовый - Gruvbox Light\n      Gruvbox Light Orange: Оранжевый - Gruvbox Light\n      Gruvbox Dark Yellow: Жёлтый - Gruvbox Dark\n      Gruvbox Dark Orange: Оранжевый - Gruvbox Dark\n      Catppuccin Frappe Sky: Светло-голубой - Catppuccin Frappe\n      Catppuccin Frappe Teal: Тёмно-бирюзовый - Catppuccin Frappe\n      Catppuccin Frappe Yellow: Жёлтый - Catppuccin Frappe\n      Catppuccin Frappe Green: Зелёный - Catppuccin Frappe\n      Catppuccin Frappe Rosewater: Розовая Вода - Catppuccin Frappe\n      Catppuccin Frappe Flamingo: Фламинго - Catppuccin Frappe\n      Catppuccin Frappe Pink: Розовый - Catppuccin Frappe\n      Catppuccin Frappe Mauve: Сиреневый - Catppuccin Frappe\n      Catppuccin Frappe Red: Красный - Catppuccin Frappe\n      Catppuccin Frappe Maroon: Бордовый - Catppuccin Frappe\n      Catppuccin Frappe Peach: Персиковый - Catppuccin Frappe\n      Catppuccin Frappe Sapphire: Сапфировый - Catppuccin Frappe\n      Catppuccin Frappe Blue: Синий - Catppuccin Frappe\n      Catppuccin Frappe Lavender: Лавандовый - Catppuccin Frappe\n      Everforest Dark Aqua: Аква - Everforest Dark\n      Everforest Dark Green: Зелёный - Everforest Dark\n      Everforest Dark Red: Красный - Everforest Dark\n      Everforest Dark Orange: Оранжевый - Everforest Dark\n      Everforest Dark Yellow: Жёлтый - Everforest Dark\n      Everforest Dark Blue: Синий - Everforest Dark\n      Everforest Dark Purple: Фиолетовый - Everforest Dark\n      Everforest Light Red: Красный - Everforest Light\n      Everforest Light Orange: Оранжевый - Everforest Light\n      Everforest Light Yellow: Жёлтый - Everforest Light\n      Everforest Light Green: Зелёный - Everforest Light\n      Everforest Light Aqua: Аква - Everforest Light\n      Everforest Light Blue: Синий - Everforest Light\n      Everforest Light Purple: Фиолетовый - Everforest Light\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n    Secondary Color Theme: 'Дополнительный цвет темы'\n        #* Main Color Theme\n    UI Scale: Масштаб интерфейса\n    Expand Side Bar by Default: Расширить боковую панель\n    Disable Smooth Scrolling: Отключить плавную прокрутку\n    Hide Side Bar Labels: Скрыть надписи боковой панели\n    Hide FreeTube Header Logo: Скрыть значок FreeTube\n  Player Settings:\n    Player Settings: 'Проигрыватель'\n    Play Next Video: 'Автоматическое воспроизведение рекомендуемых видеороликов'\n    Turn on Subtitles by Default: 'Субтитры по умолчанию включены'\n    Autoplay Videos: 'Автовоспроизведение видео'\n    Proxy Videos Through Invidious: 'Смотреть видео через прокси Invidious'\n    Autoplay Playlists: 'Автовоспроизведение видео из плейлиста'\n    Enable Theatre Mode by Default: 'Включать режим широкого экрана'\n    Default Volume: 'Громкость по умолчанию'\n    Default Playback Rate: 'Скорость воспроизведения по умолчанию'\n    Default Video Format:\n      Default Video Format: 'Формат видео по умолчанию'\n      Dash Formats: 'DASH форматы'\n      Legacy Formats: 'Устаревшие форматы'\n      Audio Formats: 'Звуковые форматы'\n    Default Quality:\n      Default Quality: 'Качество по умолчанию'\n      Auto: 'Авто'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Scroll Volume Over Video Player: Прокрутка громкости поверх видеопроигрывателя\n    Next Video Interval: Таймер обратного отсчета для автопроигрывания\n    Display Play Button In Video Player: Отображать кнопку воспроизведения в видеопроигрывателе\n    Fast-Forward / Rewind Interval: Шаг перемотки вперёд/назад\n    Scroll Playback Rate Over Video Player: Прокрутка скорости воспроизведения поверх видеопроигрывателя\n    Max Video Playback Rate: Предельная скорость воспроизведения\n    Video Playback Rate Interval: Интервал скорости воспроизведения видео\n    Screenshot:\n      Ask Path: Спрашивать папку для сохранения\n      Error:\n        Forbidden Characters: Запрещенные символы\n        Empty File Name: Пустое имя файла\n      Format Label: Формат скриншотов\n      Folder Label: Папка для скриншотов\n      Folder Button: Выбрать папку\n      Enable: Включить скриншоты\n      Quality Label: Качество скриншотов\n      File Name Label: Шаблон имени файла\n      File Name Tooltip: Вы можете использовать эти переменные. %Y Год 4 цифры. %M Месяц 2 цифры. %D День 2 цифры. %H Час 2 цифры. %N Минуты 2 цифры. %S Секунды 2 цифры. %T Миллисекунды 3 цифры. %s Секунды видео. %t Миллисекунды видео 3 цифры. %i Идентификатор видео.\n    Enter Fullscreen on Display Rotate: Входить в полноэкранный режим при повороте дисплея\n    Skip by Scrolling Over Video Player: Пропустить, прокручивая видеопроигрыватель\n    Autoplay Interruption Timer: Таймер прерывания автопроигрывания\n    Default Viewing Mode:\n      Theater: Широкий экран\n      Default Viewing Mode: Режим просмотра по умолчанию\n      Full Screen: На весь экран\n      Picture in Picture: Картинка в картинке\n      External Player: Внешний проигрыватель ({externalPlayerName})\n  Subscription Settings:\n    Subscription Settings: 'Подписки'\n    Fetch Feeds from RSS: Загружать Ленты из RSS\n    Fetch Automatically: Автоматически загружать ленту\n    Confirm Before Unsubscribing: Запрашивать подтверждение перед отпиской\n\n    'Limit the number of videos displayed for each channel': Ограничить количество видео, отображаемых на каждом канале\n    To: В\n  Privacy Settings:\n    Watch history has been cleared: История просмотра очищена\n    Are you sure you want to remove your entire watch history?: Вы уверены, что хотите удалить всю историю просмотра?\n    Remove Watch History: Удалить историю просмотра\n    Search cache has been cleared: Поисковой кэш был очищен\n    Are you sure you want to clear out your search cache?: Выполнить очистку кэша поиска?\n    Clear Search Cache: Очистить кэш поиска\n    Save Watched Progress: Сохранять Прогресс Просмотра\n    Remember History: Сохранять Историю Просмотра\n    Privacy Settings: Конфиденциальность\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Вы уверены, что хотите удалить все подписки и профили? Это действие нельзя отменить.\n    Remove All Subscriptions / Profiles: Удалить все подписки/профили\n    Save Watched Videos With Last Viewed Playlist: Сохранять просмотренные видео в плейлист Недавно просмотренные\n    Are you sure you want to remove all your playlists?: Вы действительно хотите удалить все свои плейлисты?\n    All playlists have been removed: Все плейлисты были удалены\n    Remove All Playlists: Удалить все плейлисты\n    Clear Search History and Cache: Очистить историю поиска и кэш\n    Are you sure you want to clear out your search history and cache?: Вы уверены, что хотите очистить историю поиска и кэш?\n    Search history and cache have been cleared: История поиска и кэш были очищены\n    Remember Search History: Сохранять Историю Поиска\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Автоматически\n        Semi-auto: Полуавтоматически\n        Never: Никогда\n      Tooltip: Автоматически = Сохранение при каждом выходе со страницы с видео, когда видео закончилось и произошла ошибка (например, скорость просмотра ограничена, а сеанс просмотра истек). Полуавтоматически = Поддерживает автоматическое сохранение, за исключением выхода со страницы с видео, и может сохранять прогресс вручную с помощью кнопки \"Сохранить просмотренный прогресс\", расположенной под видеоплеером.\n  Data Settings:\n    How do I import my subscriptions?: Как импортировать подписки?\n    Unknown data key: Неизвестный ключ данных\n    Unable to write file: Невозможно записать файл\n    Unable to read file: Невозможно прочитать файл\n    All watched history has been successfully exported: Вся история просмотров успешно экспортирована\n    All watched history has been successfully imported: Вся история просмотров успешно импортирована\n    History object has insufficient data, skipping item: Объект истории имеет недостаточно данных, пропуск элемента\n    Subscriptions have been successfully exported: Подписки успешно экспортированы\n    Invalid history file: Неверный файл истории\n    Invalid subscriptions file: Неверный файл подписок\n    All subscriptions have been successfully imported: Все подписки успешно импортированы\n    All subscriptions and profiles have been successfully imported: Все подписки и профили успешно импортированы\n    Profile object has insufficient data, skipping item: Объект профиля имеет недостаточно данных, пропуск элемента\n    Export History: Экспортировать историю\n    Import History: Импортировать историю\n    Export NewPipe: Экспортировать NewPipe\n    Export YouTube: Экспортировать YouTube\n    Export FreeTube: Экспортировать FreeTube\n    Export Subscriptions: Экспортировать подписки\n    Import Subscriptions: Импортировать подписки\n    Select Export Type: Выбрать тип экспорта\n    Data Settings: Данные\n    Manage Subscriptions: Управление подписками\n    Import Playlists: Импортировать плейлисты\n    All playlists has been successfully exported: Все плейлисты успешно экспортированы\n    Export Playlists: Экспортировать плейлисты\n    All playlists has been successfully imported: Все плейлисты успешно импортированы\n    Playlist insufficient data: Недостаточно данных для плейлиста «{playlist}», пропуск элемента\n    Playlist File: Файл плейлистов\n    Subscription File: Файл подписок\n    History File: Файл истории\n    Export Playlists For Older FreeTube Versions:\n      Label: Экспортировать подборки для старых выпусков FreeTube\n      Tooltip: \"Эта настройка экспортирует видео из всех плейлистов в один с названием «Избранное».\\nКак экспортировать и импортировать видео в плейлистах для старых версий FreeTube:\\n1. Экспортируй свои плейлисты с этой включённой настройкой.\\n 2. Удали все свои существующие плейлисты, используя настройку удаления всех плейлистов под разделом Настройки Конфиденциальности.\\n3. Запусти старую версию Freetube и импортируй экспортированные ранее плейлисты.\"\n    Search history file: Файл истории поиска\n    Search history: История поиска\n    Import search history: Импортировать историю поиска\n    Export search history: Экспортировать историю поиска\n    All search history has been successfully imported: Вся история поиска успешно импортирована\n    All search history has been successfully exported: Вся история поиска успешно экспортирована\n  Distraction Free Settings:\n    Hide Live Chat: Скрыть чат прямой трансляции\n    Hide Popular Videos: Скрыть популярные видео\n    Hide Trending Videos: Скрыть Видео в Тренде\n    Hide Recommended Videos: Скрыть Рекомендуемые Видео\n    Distraction Free Settings: Ничего Лишнего\n    Hide Comment Likes: Скрыть Лайки Комментариев\n    Hide Channel Subscribers: Скрыть Количество Подписчиков\n    Hide Video Likes And Dislikes: Скрыть Лайки и Дизлайки\n    Hide Video Views: Скрыть Количество Просмотров\n    Hide Active Subscriptions: Скрыть действующие подписки\n    Hide Playlists: Скрыть плейлисты\n    Hide Live Streams: Скрыть прямые трансляции\n    Hide Sharing Actions: Скрыть действия Поделиться\n    Hide Videos on Watch: 'Скрывать видео после просмотра'\n    Hide Comments: Скрыть комментарии\n    Hide Video Description: Скрыть описание видео\n    Hide Chapters: Скрыть разделы\n    Hide Upcoming Premieres: Скрыть предстоящие премьеры\n    Hide Channels Placeholder: ID канала\n    Hide Channels: Скрыть видео с каналов\n    Display Titles Without Excessive Capitalisation: Отображать заголовки без сплошных заглавных букв и знаков препинания\n    Hide Featured Channels: Скрыть избранные каналы\n    Hide Channel Playlists: Скрыть вкладку \"Плейлисты\" канала\n    Hide Channel Shorts: Скрыть вкладку \"Шортс\" канала\n    Sections:\n      Side Bar: Боковая Панель\n      Channel Page: Страница Канала\n      Watch Page: Страница Просмотра\n      General: Основные\n      Subscriptions Page: Страница Подписок\n    Hide Channel Releases: Скрыть вкладку \"Релизы\" канала\n    Hide Subscriptions Videos: Скрыть видео из подписок\n    Hide Subscriptions Live: Скрыть трансляции из подписок\n    Hide Channel Podcasts: Скрыть вкладку \"Подкасты\" канала\n    Hide Subscriptions Shorts: Скрыть шортсы из подписок\n    Hide Profile Pictures in Comments: Скрыть изображения профилей в комментариях\n    Hide Channels Invalid: Указанный ID канала недействителен\n    Hide Channels Disabled Message: Некоторые каналы были заблокированы по ID и не были обработаны. Функция заблокирована, пока эти идентификаторы обновляются\n    Hide Channels Already Exists: ID канала уже существует\n    Hide Channels API Error: Ошибка при получении пользователя с предоставленным ID. Пожалуйста, проверьте еще раз, правильно ли указан ID.\n    Hide Videos, Playlists and Channels Containing Text: Скрыть видео и плейлисты, содержащие текст\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Слово, часть слова, или выражение\n    Hide Channel Home: Скрыть вкладку \"Главная\" канала\n    Show Added Items: Показать добавленные элементы\n    Hide Channel Courses: Скрыть вкладку «Курсы» канала\n    Hide Channel Posts: Скрыть вкладку \"Записи\" канала\n    Hide Subscriptions Posts: Скрывать записи в подписках\n  The app needs to restart for changes to take effect. Restart and apply change?: Чтобы изменения вступили в силу, необходимо перезапустить приложение. Перезапустить и применить изменения?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Ошибка при получении информации о сети. Правильно ли настроен ваш прокси-сервер?\n    Your Info: Ваша информация\n    Clicking on Test Proxy will send a request to: Нажмите «Протестировать прокси», чтобы отправить запрос на\n    Test Proxy: Тест прокси\n    Proxy Port Number: Порт прокси-сервера\n    Proxy Host: Адрес прокси-сервера\n    Proxy Protocol: Протокол прокси\n    City: Город\n    Region: Регион\n    Country: Страна\n    Ip: Ip\n    Enable Tor / Proxy: Включить Tor/Прокси\n    Proxy Settings: Прокси\n    Proxy Warning: FreeTube не имеет встроенного прокси, но может подключаться к внешнему прокси, например, к запущенному на вашей машине Tor или к внешнему прокси, например, SOCKS5, предоставляемому некоторыми VPN. Если он включен, убедитесь, что Ваш прокси/Tor настроен правильно, иначе FreeTube не сможет получить данные.\n    Proxy Username: Имя пользователя прокси\n    Proxy Password: Пароль прокси\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Уведомлять о пропущенном сегменте\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': Адрес SponsorBlock API (По умолчанию https://sponsor.ajay.app)\n    Enable SponsorBlock: Включить SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Опция пропуска\n      Prompt To Skip: Предлагать пропустить\n      Auto Skip: Автопропуск\n      Show In Seek Bar: Показать сегмент\n      Do Nothing: Ничего не делать\n    Category Color: Цвет категории\n    UseDeArrowTitles: Использовать заголовки видео DeArrow\n    UseDeArrowThumbnails: Использовать миниатюры видео DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL-адрес DeArrow API для генерации миниатюр (по умолчанию https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Аргументы внешнего проигрывателя\n    Custom External Player Executable: Исполняемый файл внешнего проигрывателя\n    Ignore Unsupported Action Warnings: Пропускать предупреждения о неподдерживаемых действиях\n    External Player: Внешний проигрыватель\n    External Player Settings: Внешний проигрыватель\n    Players:\n      None:\n        Name: Нет\n    Ignore Default Arguments: Не учитывать аргументы по умолчанию\n  Parental Control Settings:\n    Show Family Friendly Only: Показывать только семейный контент\n    Parental Control Settings: Родительский Контроль\n    Hide Unsubscribe Button: Скрыть кнопку отписки\n    Hide Search Bar: Скрыть строку поиска\n    Hide Uploader on Watch page: Скрыть канал на странице просмотра\n  Experimental Settings:\n    Experimental Settings: Эксперименты\n    Replace HTTP Cache: Заменить HTTP-кэш\n    Warning: Экспериментальные настройки. При их включении возможны ошибки. Настоятельно рекомендуется делать резервные копии. Используйте на свой страх и риск!\n  Password Dialog:\n    Password: Пароль\n    Enter Password To Unlock: Введите пароль для разблокировки настроек\n  Password Settings:\n    Password Settings: Пароль\n    Set Password To Prevent Access: Установите пароль для предотвращения доступа к настройкам\n    Set Password: Установить пароль\n    Remove Password: Удалить пароль\n  Sort Settings Sections (A-Z): Сортировка разделов настроек (A-Z)\n  Return to Settings Menu: Вернуться в Настройки\n  SABR:\n    Label: Включить SABR как движок DASH\n    Tooltip: SABR станет единственным движком DASH в будущих версиях и не сможет быть отключён. Этот переключатель предусмотрен на случай, если ранняя реализация будет содержать неустранимые ошибки.\nAbout:\n  #On About page\n  About: 'О приложении'\n  #& About\n#On Channel Page\n  Donate: Пожертвовать\n  these people and projects: этим людям и проектам\n  Credits: Участники\n  Translate: Перевод\n  room rules: правила комнаты\n  Chat on Matrix: Чат на Matrix\n  Mastodon: Mastodon\n  Email: Электронная почта\n  Blog: Блог\n  Website: Сайт\n  Report a problem: Сообщить о проблеме\n  FAQ: ЧАВО\n  FreeTube Wiki: Вики FreeTube\n  Help: Помощь\n  GitHub releases: Релизы на GitHub\n  Downloads / Changelog: Скачать / Список изменений\n  Source code: Исходный код\n  Beta: Бета\n  Please check for duplicates before posting: Перед публикацией проблемы, проверьте нет ли дубликатов\n  GitHub issues: Проблемы на GitHub\n  Discussions: Обсуждения\n  AGPLv3: Лицензия AGPLv3\n  Licensed under the {licenseLink}: Лицензируется на условиях {licenseLink}\n  Please read the {roomRulesLink}: Пожалуйста, прочтите {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube стал возможен благодаря {creditsPageLink}\nChannel:\n  Subscribe: 'Подписаться'\n  Unsubscribe: 'Отписаться'\n  Search Channel: 'Поиск на канале'\n  Your search results have returned 0 results: 'По вашему запросу ничего не найдено'\n  Videos:\n    Videos: 'Видео'\n    This channel does not currently have any videos: 'На этом канале в настоящее время нет видео'\n    Sort Types:\n      Newest: 'Новым'\n      Oldest: 'Старым'\n      Most Popular: 'Самым популярным'\n  Playlists:\n    Playlists: 'Плейлисты'\n    This channel does not currently have any playlists: 'На этом канале в настоящее время нет плейлистов'\n    Sort Types:\n      Last Video Added: 'Последнему добавленному видео'\n      Newest: 'Новым'\n      Oldest: 'Старым'\n  About:\n    About: 'О канале'\n    Channel Description: 'Описание канала'\n    Featured Channels: 'Избранные каналы'\n    Tags:\n      Tags: Метки\n      Search for: Поиск по «{tag}»\n    Details: Подробности\n    Joined: Дата присоединения\n    Location: Расположение\n  Added channel to your subscriptions: Канал добавлен в ваши подписки\n  Removed subscription from {count} other channel(s): Подписка удалена с {count} другого(их) канала(ов)\n  Channel has been removed from your subscriptions: Канал был удалён из подписок\n  This channel does not exist: Этого канала не существует\n  This channel does not allow searching: Этот канал не позволяет выполнять поиск\n  Channel Tabs: Вкладки каналов\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Этот канал ограничен по возрасту и в настоящее время не может быть просмотрен во FreeTube.\n  Posts:\n    This channel currently does not have any posts: На этом канале в настоящее время нет никаких записей\n    votes: 'Голосов: {votes}'\n    Hide Answers: Скрыть ответы\n    Reveal Answers: Раскрыть ответы\n    Video hidden by FreeTube: Видео скрыто FreeTube'ом\n    Viewing Posts Only Supported By Invidious: Просмотр постов поддерживается только в Invidious. Перейдите на вкладку \"Сообщество\" канала, чтобы просматривать контент там без Invidious.\n    View Full Post: Просмотреть полный пост\n  Live:\n    Live: Трансляции\n    This channel does not currently have any live streams: На этом канале в настоящее время нет прямых трансляций\n  Shorts:\n    This channel does not currently have any shorts: На этом канале пока что нет шортс\n  Podcasts:\n    Podcasts: Подкасты\n    This channel does not currently have any podcasts: На этом канале пока нет подкастов\n  Releases:\n    Releases: Релизы\n    This channel does not currently have any releases: На этом канале пока нет ни одного музыкального релиза\n  Home:\n    Home: Главная\n    View Playlist: Просмотреть плейлист\n  Courses:\n    Courses: Курсы\n    This channel does not currently have any courses: На этом канале в настоящее время нет курсов\nVideo:\n  Mark As Watched: 'Отметить как просмотренное'\n  Remove From History: 'Удалить из истории'\n  Video has been marked as watched: 'Видео было отмечено как просмотренное'\n  Video has been removed from your history: 'Видео было удалено из истории просмотров'\n  Open in YouTube: 'Открыть в YouTube'\n  Copy YouTube Link: 'Скопировать ссылку YouTube'\n  Open YouTube Embedded Player: 'Открыть встроенный проигрыватель YouTube'\n  Copy YouTube Embedded Player Link: 'Скопировать ссылку на встроенный проигрыватель YouTube'\n  Open in Invidious: 'Открыть в Invidious'\n  Copy Invidious Link: 'Скопировать ссылку Invidious'\n  Views: 'Просмотров'\n  Watched: 'Просмотрено'\n  # As in a Live Video\n  Live: 'Трансляция'\n  Live Now: 'Трансляция'\n  Live Chat: 'Чат трансляции'\n  Enable Live Chat: 'Включить чат трансляции'\n  Live Chat is currently not supported in this build.: 'В настоящее время чат трансляции в этой версии не поддерживается.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Чат трансляции включён. Сообщения чата будут отображаться здесь после отправки.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Чат трансляции в настоящее время не поддерживается Invidious API. Требуется прямое подключение к YouTube.'\n  Published:\n    In less than a minute: Меньше чем через минуту\n  Published on: 'Размещено'\n#& Videos\n  Autoplay: Автовоспроизведение\n  Previous: Назад\n  Next: Следующее\n  Reverse Playlist: Обратный порядок плейлиста\n  Shuffle Playlist: Перемешать плейлист\n  Loop Playlist: Повторять плейлист\n  Starting soon, please refresh the page to check again: Скоро начнется, обновите страницу, чтобы проверить ещё раз\n  Copy Invidious Channel Link: Скопировать ссылку на канал Invidious\n  Open Channel in Invidious: Открыть канал в Invidious\n  Copy YouTube Channel Link: Скопировать ссылку на канал YouTube\n  Open Channel in YouTube: Открыть канал в YouTube\n  Streamed on: Транслировано\n  Started streaming on: Трансляция начата на\n  Video has been removed from your saved list: Видео было удалено из списка сохранённых\n  Video has been saved: Видео было добавлено в сохранённые\n  Save Video: Добавить видео в сохранённые\n  Sponsor Block category:\n    music offtopic: Сегмент без музыки\n    interaction: Напоминание\n    self-promotion: Самореклама\n    outro: Концовка\n    intro: Вступление\n    sponsor: Спонсор\n    recap: Краткое содержание\n    filler: Отвлечение\n  External Player:\n    Unsupported Actions:\n      looping playlists: повторение плейлистов\n      shuffling playlists: перемешивание плейлистов\n      reversing playlists: реверсирование плейлистов\n      opening specific video in a playlist (falling back to opening the video): открытие определённого видео в плейлисте (возврат к открытию видео)\n      opening playlists: открытие плейлистов\n      setting a playback rate: настройка скорости воспроизведения\n      starting video at offset: начинать видео со смещением\n    UnsupportedActionTemplate: '{externalPlayer} не поддерживает: {action}'\n    OpeningTemplate: Открытие {videoOrPlaylist} в {externalPlayer}...\n    playlist: плейлист\n    video: видео\n    OpenInTemplate: Открыть в {externalPlayer}\n  Premieres: Премьеры\n  Show Super Chat Comment: Показать комментарий «Супер Чата»\n  Scroll to Bottom: Прокрутить вниз\n  Upcoming: Предстоящее\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Чат прямой трансляции недоступен. Возможно, он был отключён владельцем канала.\n  Hide Channel: Скрыть канал\n  Unhide Channel: Показать канал\n  More Options: Больше настроек\n  Player:\n    TranslatedCaptionTemplate: '{language} (переведено с \"{originalLanguage}\")'\n    Stats:\n      CodecsVideoAudioNoItags: 'Кодеки: {videoCodec} / {audioCodec}'\n      CodecAudio: 'Кодек: {audioCodec} ({audioItag})'\n      Stats: Статистики\n      Video ID: 'ID Видео: {videoId}'\n      Media Formats: 'Медиа Форматы: {formats}'\n      Buffered: 'Буферизовано: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Пропущенные кадры: {droppedFrames} / Всего кадров: {totalFrames}'\n      CodecsVideoAudio: 'Кодеки: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Resolution: 'Разрешение: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Разрешение проигрывателя: {width}x{height}'\n      Bitrate: 'Битрейт: {bitrate} кбит/с'\n      Volume: 'Громкость: {volumePercentage}%'\n      Bandwidth: 'Пропускная способность: {bandwidth} кбит/с'\n    You appear to be offline: Похоже, вы Оффлайн.\n    Skipped segment: Пропущен {segmentCategory} сегмент\n    Playback will resume automatically when your connection comes back: Воспроизведение будет возобновлено автоматически, когда соединение будет восстановлено.\n    Audio Tracks: Аудиодорожки\n    Theatre Mode: Широкий экран\n    Exit Theatre Mode: Выйти из широкого экрана\n    Full Window: Полноэкранный Режим\n    Exit Full Window: Выйти из Полноэкранного Режима\n    Take Screenshot: Сделать Снимок Экрана\n    Show Stats: Показать Статистику\n    Hide Stats: Скрыть Статистику\n    Autoplay is on: Автопроигрывание включено\n    Autoplay is off: Автопроигрывание выключено\n  IP block: YouTube заблокировал ваш IP-адрес для просмотра видео. Пожалуйста, попробуйте переключиться на другой VPN или прокси.\n  MembersOnly: Видео только для подписчиков нельзя смотреть на FreeTube, так как для них требуется вход в Google и платная подписка на автора канала.\n  Unlisted: Отсутствует в списках\n  AgeRestricted: Видео с возрастными ограничениями нельзя смотреть через FreeTube, так как для этого требуется вход в Google и использование подтвержденной учетной записи YouTube.\n  DeArrow:\n    Show Original Details: Показать стандартные свойства\n    Show Modified Details: Показать модифицированные свойства\n#& Playlists\n  DRMProtected: Видео, защищенное DRM, не может быть воспроизведено в FreeTube, так как оно требует использования проприетарных компонентов с закрытым исходным кодом. Если вы хотите посмотреть это видео, пожалуйста, смотрите его на официальном сайте YouTube в веб-браузере с поддержкой DRM.\n  Save Watched Progress: Сохранение прогресса просмотренного видео\n  Watched Progress Saved: Прогресс просмотренного видео сохранён\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Оставшееся время preroll-рекламы: {remindingTimeSeconds} сек'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Оставшееся время задержки SABR: {remindingTimeSeconds} сек'\n  Popout Live Chat: Вынести чат в отдельное окно\nPlaylist:\n  #& About\n  View Full Playlist: 'Посмотреть весь плейлист'\n  Last Updated On: 'Последнее обновление'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Плейлист\n  Sort By:\n    AuthorAscending: Автор (А-Я)\n    AuthorDescending: Автор (Я-А)\n    DateAddedNewest: Дата добавления (Сначала новые)\n    DateAddedOldest: Дата добавления (Сначала старые)\n    VideoTitleAscending: Название (А-Я)\n    VideoTitleDescending: Название (Я-А)\n    Custom: Пользовательский\n    VideoDurationAscending: Продолжительность (Кратчайшие)\n    VideoDurationDescending: Продолжительность (Длиннейшие)\n    PublishedNewest: Дата публикации (Сначала новые)\n    PublishedOldest: Дата публикации (Сначала старые)\nChange Format:\n  Change Media Formats: 'Изменить форматы видео'\n  Use Dash Formats: 'Использовать форматы DASH'\n  Use Legacy Formats: 'Использовать устаревшие форматы'\n  Use Audio Formats: 'Использовать звуковые форматы'\n  Audio formats are not available for this video: Звуковые форматы недоступны для этого видео\n  Dash formats are not available for this video: Форматы DASH недоступны для этого видео\n  Legacy formats are not available for this video: Устаревшие форматы недоступны для этого видео\nShare:\n  Share Video: 'Поделиться видео'\n  Share Playlist: 'Поделиться плейлистом'\n  Copy Link: 'Скопировать ссылку'\n  Open Link: 'Открыть ссылку'\n  Copy Embed: 'Скопировать встраиваемые'\n  Open Embed: 'Открыть встраиваемые'\n  # On Click\n  Invidious URL copied to clipboard: 'Адрес Invidious скопирован в буфер обмена'\n  Invidious Embed URL copied to clipboard: 'Адрес Invidious Embed скопирован в буфер обмена'\n  YouTube URL copied to clipboard: 'Адрес YouTube скопирован в буфер обмена'\n  YouTube Embed URL copied to clipboard: 'Адрес YouTube Embed скопирован в буфер обмена'\n  Include Timestamp: Включить отметку времени\n  YouTube Channel URL copied to clipboard: Адрес канала YouTube скопирован в буфер обмена\n  Invidious Channel URL copied to clipboard: Адрес канала Invidious скопирован в буфер обмена\n  Share Channel: Поделиться каналом\n  Share Post: Поделиться записью\nMini Player: 'Мини-проигрыватель'\nComments:\n  Comments: 'Комментарии'\n  Click to View Comments: 'Нажмите, чтобы просмотреть комментарии'\n  Getting comment replies, please wait: 'Получение ответов на комментарии, пожалуйста, подождите'\n  Hide Comments: 'Скрыть комментарии'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'К этому видео нет комментариев'\n  Load More Comments: 'Загрузить больше комментариев'\n  There are no more comments for this video: К этому видео больше нет комментариев\n  Newest first: Новым\n  Top comments: Лучшим комментариям\n  Show More Replies: Показать больше ответов\n  Pinned by: Закреплено\n  Member: Участник\n  View {replyCount} replies: Смотреть 1 ответ | Смотреть {replyCount} ответа(ов)\n  Hearted: С сердечком\n  Subscribed: Подписан(а)\n  There are no comments available for this post: Для этой записи нет доступных комментариев\n  Hide {replyCount} replies: Скрыть 1 ответ | Скрыть {replyCount} ответа(ов)\n  View 1 reply from {channelName}: Смотреть 1 ответ от {channelName}\n  View {replyCount} replies from {channelName} and others: Смотреть {replyCount} ответа(ов) от {channelName} и других\nUp Next: 'Следующий'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Ошибка локального набора функций (Нажмите, чтобы скопировать)'\nInvidious API Error (Click to copy): 'Ошибка набора функций Invidious (Нажмите, чтобы скопировать)'\nFalling back to Invidious API: 'Возврат к набору функций Invidious'\nFalling back to Local API: 'Возврат к локальному набору функций'\nLoop is now disabled: 'Повторение теперь отключено'\nLoop is now enabled: 'Повторение теперь включено'\nShuffle is now disabled: 'Перемешивание теперь отключено'\nShuffle is now enabled: 'Перемешивание теперь включено'\nPlaying Next Video: 'Воспроизведение следующего видео'\nPlaying Previous Video: 'Воспроизведение предыдущего видео'\nCanceled next video autoplay: 'Отменено автовоспроизведение следующего видео'\n'The playlist has ended. Enable loop to continue playing': 'Плейлист закончился. Включите повторение, чтобы продолжить воспроизведение'\n\nYes: 'Да'\nNo: 'Нет'\nLocale Name: Русский\nProfile:\n  '{profile} is now the active profile': Теперь {profile} активный профиль\n  Your default profile has been changed to your primary profile: Профиль по умолчанию был изменен на ваш основной\n  Profile has been updated: Профиль был обновлён\n  Removed {profile} from your profiles: Теперь {profile} удалён из профилей\n  Your default profile has been set to {profile}: Теперь {profile} установлен профилем по умолчанию\n  Profile has been created: Профиль был создан\n  Your profile name cannot be empty: Имя профиля не может быть пустым\n  All subscriptions will also be deleted.: Все подписки также будут удалены.\n  Are you sure you want to delete this profile?: Хотите удалить этот профиль?\n  Delete Profile: Удалить профиль\n  Make Default Profile: Сделать профилем по умолчанию\n  Update Profile: Обновить профиль\n  Create Profile: Создать профиль\n  Profile Preview: Предпросмотр профиля\n  Custom Color: Свой цвет\n  Color Picker: Выбор цвета\n  Edit Profile: Изменить профиль\n  Create New Profile: Создать новый профиль\n  Profile Manager: Менеджер профилей\n  All Channels: Все каналы\n  Profile Select: Выбор профиля\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Хотите удалить выбранные каналы? Это не приведёт к удалению каналов из любого другого профиля.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Это ваш основной профиль.  Вы уверены, что хотите удалить выбранные каналы?  Те же каналы будут удалены из любого профиля, в котором они находятся.\n  No channel(s) have been selected: Не выбран(ы) канал(ы)\n  Add Selected To Profile: Добавить выбранное в профиль\n  Delete Selected: Удалить выбранное\n  Select None: Отменить выделение\n  Select All: Выбрать все\n  '{number} selected': Выбрано {number}\n  Other Channels: Другие каналы\n  Subscription List: Подписки\n  Profile Filter: Фильтр профилей\n  Profile Settings: Профиль\n  Toggle Profile List: Переключить список профилей\n  Create Profile Name: Создать название профия\n  Profile Name: Название профиля\n  Edit Profile Name: Изменить название профиля\n  Close Profile Dropdown: Закрыть выпадающий список профилей\n  Open Profile Dropdown: Открыть выпадающий список профилей\nThe playlist has been reversed: Порядок плейлиста был обёрнут\nA new blog is now available, {blogTitle}. Click to view more: Теперь доступен новый блог, {blogTitle}. Нажмите, чтобы посмотреть больше\nDownload From Site: Скачать с сайта\nVersion {versionNumber} is now available!  Click for more details: Версия {versionNumber} теперь доступна!  Нажмите для получения более подробной информации\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Это видео недоступно из-за отсутствия форматов. Это может произойти из-за региональных ограничений.\nTooltips:\n  General Settings:\n    Thumbnail Preference: Все заставки на FreeTube будут заменены снимком из видео, размытым или скрытым, вместо заставки по умолчанию.\n    Invidious Instance: Образец Invidious, к которому FreeTube будет подключаться для вызовов набора функций.\n    Fallback to Non-Preferred Backend on Failure: Если у вашего предпочитаемого набора функций есть проблема, FreeTube автоматически попытается использовать ваш нежелательный набор функций в качестве запасного метода, если он включен.\n    Preferred API Backend: Выберите движок, который FreeTube будет использовать для получения данных. Локальный набор функций — это встроенный экстрактор. Набор функций Invidious требует подключения к серверу Invidious.\n    Region for Trending: Регион трендов позволяет выбрать, в какой стране будут отображаться трендовые видео.\n    External Link Handling: \"Выберите действие при нажатии на ссылку, которая не может быть открыта во FreeTube.\\nПо умолчанию, FreeTube откроет ссылку в браузере по умолчанию.\\n\"\n    Open Deep Links In New Window: URL-адреса, передаваемые FreeTube, например, с помощью расширений браузера или аргументов командной строки, открываются в новом окне.\n  Subscription Settings:\n    Fetch Feeds from RSS: Если эта настройка включена, FreeTube будет получать вашу ленту подписок с помощью RSS, вместо метода по умолчанию. RSS работает быстрее и предотвращает блокировку IP, но не предоставляет определённую информацию, такую как продолжительность видео , статус прямого эфира или публикации\n    Fetch Automatically: Если эта функция включена, FreeTube будет автоматически загружать ленту вашей подписки при запуске и при открытии нового окна.\n  Player Settings:\n    Default Video Format: Устанавливает форматы, используемые при воспроизведении видео. Формат DASH может воспроизводить более высокое качество. Устаревшие форматы ограничены пределом в 360p, но используют меньшую пропускную способность. Звуковые форматы — только звуковые потоки.\n    Proxy Videos Through Invidious: Будет подключаться к Invidious для показа видео вместо прямого подключения к YouTube.\n    Scroll Playback Rate Over Video Player: Пока указатель мыши находится над видео, нажмите и удерживайте клавишу Control (клавиша Command на Mac) и прокрутите колесо мыши вперед или назад, чтобы изменять скорость воспроизведения. Нажмите и удерживайте клавишу Control (клавиша Command на Mac) и щелкните левой кнопкой мыши, чтобы быстро вернуться к обычной скорости воспроизведения (1x, если она не была изменена в настройках).\n    Skip by Scrolling Over Video Player: Используйте колесо прокрутки, чтобы пропустить видео в стиле MPV.\n  External Player Settings:\n    Custom External Player Arguments: Любые пользовательские аргументы командной строки, которые вы хотите передать внешнему проигрывателю.\n    Ignore Warnings: Скрыть предупреждения, когда текущий внешний проигрыватель не поддерживает текущее действие (например, обратный порядок плейлистов и т.д.).\n    Custom External Player Executable: По умолчанию FreeTube будет считать, что выбранный внешний проигрыватель можно найти через переменную окружения PATH. При необходимости здесь можно задать собственный путь.\n    External Player: При выборе внешнего проигрывателя на миниатюре появится значок, позволяющий открыть видео (плейлист, если поддерживается) во внешнем проигрывателе. Внимание, настройки Invidious не применяются ко внешним проигрывателям.\n    DefaultCustomArgumentsTemplate: \"(По умолчанию: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: 'Не передавать никаких аргументов внешнему проигрывателю по умолчанию, кроме адреса видео (напр.: частота проигрывания, адрес плейлиста и т. д.). Пользовательские аргументы всё ещё будут передаваться.'\n  Experimental Settings:\n    Replace HTTP Cache: Отключает дисковый HTTP-кэш Electron и включает пользовательский кэш изображений в памяти. Приведёт к увеличению использования оперативной памяти.\n  Distraction Free Settings:\n    Hide Channels: Введите ID канала, чтобы скрыть все видео, плейлисты и сам канал от появления в результатах поиска, трендах, самых популярных и рекомендуемых. Введенный ID канала должен полностью совпадать и чувствителен к регистру.\n    Hide Subscriptions Live: Эта настройка переопределена общей настройкой «{appWideSetting}», в подразделе «{subsection}» раздела «{settingsSection}»\n    Hide Videos, Playlists and Channels Containing Text: 'Вставьте слово, часть слова, или выражение (вне зависимости от регистра), чтобы скрыть все видео и плейлисты, в чьих названиях содержится что-либо вставленное сюда; за исключением только: истории, плейлистов и видео в плейлистах.'\n    Hide Videos on Watch: Скрывает просмотренные видео из вкладок Видео, Шортс и Трансляции на страницах подписок и индивидуальных каналов. Это не влияет на Главную вкладку на страницах каналов\n  SponsorBlock Settings:\n    UseDeArrowTitles: Заменить пользовательски-размещённые заголовки на заголовки, предоставляемые «DeArrow».\n    UseDeArrowThumbnails: Заменить миниатюры видео на миниатюры от DeArrow.\nMore: Больше\nPlaying Next Video Interval: Воспроизведение следующего видео без задержки. Нажмите для отмены. | Воспроизведение следующего видео через {nextVideoInterval} сек. Нажмите для отмены. | Воспроизведение следующего видео через {nextVideoInterval} сек. Нажмите для отмены.\nUnknown YouTube url type, cannot be opened in app: Неизвестный тип адреса YouTube, невозможно открыть в приложении\nOpen New Window: Открыть новое окно\nDefault Invidious instance has been cleared: Образец Invidious по умолчанию очищен\nDefault Invidious instance has been set to {instance}: Образец Invidious по умолчанию установлен на {instance}\nExternal link opening has been disabled in the general settings: Открытие внешних ссылок отключено в настройках\nSearch Bar:\n  Clear Input: Очистить\n  Remove: Удалить\nAre you sure you want to open this link?: Вы действительно хотите открыть эту ссылку?\nScreenshot Success: Сохраненный скриншот\nScreenshot Error: Не удалось сделать скриншот. {error}\nNew Window: Новое окно\nChannels:\n  Title: Список каналов\n  Count: '{number} канал(ов) найдено.'\n  Empty: Ваш список каналов на данный момент пуст.\n  Channels: Каналы\n  Search bar placeholder: Поиск каналов\n  Unsubscribe Prompt: Вы уверены, что хотите отписаться от «{channelName}»?\nClipboard:\n  Copy failed: Не удалось скопировать в буфер обмена\n  Cannot access clipboard without a secure connection: Невозможно получить доступ к буферу обмена без защищенного соединения\nChapters:\n  Chapters: Разделы\n  Key Moments: Ключевые моменты\nPreferences: Предпочтения\nOk: Хорошо\nHashtag:\n  Hashtag: Распределительная метка\n  This hashtag does not currently have any videos: Этой распределительной метки пока нет ни у одного видео\nChannel Unhidden: '{channel} удалён из канального фильтровщика'\nChannel Hidden: '{channel} добавлен в канальный фильтровщик'\nAge Restricted:\n  This channel is age restricted: Канал с возрастным ограничением\n  This video is age restricted: Видео с возрастным ограничением\nTag already exists: «{tagName}» метка уже существует\nSearch character limit: Поисковый запрос превышает лимит в {searchCharacterLimit} символов\nMoments Ago: несколько минут назад\nYes, Delete: Да, удалить\nYes, Restart: Да, перезагрузка\nYes, Open Link: Да, открыть ссылку\nCancel: Отмена\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nGo to page: Перейти на {page}\nClose Banner: Закрыть баннер\nFeed:\n  Feed Last Updated: 'Последнее обновление ленты {feedName}: {date}'\n  Refresh Feed: Обновить {subscriptionName}\nTrimmed input must be at least N characters long: Обрезанный ввод должен быть длиной не менее 1 символа | Обрезанный ввод должен быть длиной не менее {length} символов\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Субтитры\n    Closed Captions: Субтитры\n    8K: 8К\n    VR180: VR180\n    360 Video: 360°\n    New: Новинка\n    3D: 3D\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Стрелка вниз\n  arrowleft: Стрелка влево\n  arrowright: Стрелка вправо\n  arrowup: Стрелка вверх\n  shift: Shift\n  enter: Enter\n  plus: Плюс\nRight-click or hold to see history: ПКМ или удерживать чтобы посмотреть историю\nKeyboardShortcutPrompt:\n  Captions: Включение/выключение титров\n  Focus Secondary Search: Сосредоточьтесь на вторичной строке поиска (если она есть)\n  Picture in Picture: Переключение режима картинка в картинке\n  Large Rewind: Перемотка на 10 секунд / Перемотка видео на основе текущей скорости воспроизведения видео\n  Play: Переключение воспроизведения/паузы\n  Large Fast Forward: Перемотка на 10 секунд вперед / ускоренная перемотка видео на основе текущей скорости воспроизведения видео\n  Mute: Отключить звук\n  Sections:\n    App:\n      Situational: 'Приложение: Ситуационный'\n      General: 'Приложение: Общее'\n    Video:\n      Playback: 'Видео: Воспроизведение'\n      General: 'Видео: Общее'\n  Show Keyboard Shortcuts: Показать сочетания клавиш\n  History Backward: Перейти на одну страницу\n  Keyboard Shortcuts: Ярлыки клавиатуры\n  History Forward: Переместить одну страницу\n  New Window: Создать новое окно\n  Navigate to Settings: Перейдите на страницу Настройки\n  Navigate to History: Перейдите на страницу История\n  Refresh: Обновляйте ленту с последними материалами\n  Stats: Показать статистику видео\n  Fullscreen: Переключить полноэкранный режим\n  Close Window: Закрыть окно\n  Volume Down: Уменьшить громкость\n  Last Frame: Предыдущий кадр (при паузе)\n  Last Chapter: Последняя глава\n  Next Chapter: Следующая глава\n  Small Rewind: Перемотать назад на X секунд на основе интервала перемотки и текущей скорости воспроизведения видео\n  Small Fast Forward: Перемотать вперед на X секунд на основе интервала быстрой перемотки и текущей скорости воспроизведения видео\n  Decrease Video Speed: Уменьшить скорость воспроизведения видео на основе интервала скорости воспроизведения\n  Increase Video Speed: Увеличить скорость воспроизведения видео на основе интервала скорости воспроизведения\n  Full Window: Переключить на полноэкранный режим\n  Theatre Mode: Переключить широкий экран\n  Toggle Developer Tools: Включить/выключить инструменты разработчика\n  Reset Zoom: Сбросить уровень масштабирования\n  Zoom In: Увеличить масштаб\n  Zoom Out: Уменьшить масштаб\n  Focus Search: Перевести фокус на строку поиска\n  Next Frame: Следующий кадр (при паузе)\n  Volume Up: Увеличить громкость\n  Take Screenshot: Сделать снимок экрана\n  Minimize Window: Свернуть окно\n  Search in New Window: Выполнить поиск в отдельном окне\n  Skip by Tenths: Пропустить видео на определённый процент (3 пропуска для 30%)\n  End: Перейти к концу видео\n  Home: Перейти к началу видео\n  Skip to Next Video: Перейти к следующему видео в плейлисте или в списке рекомендуемых видео\n  Skip to Previous Video: Перейти к следующему видео в плейлисте\nDescription:\n  Expand Description: '...больше'\n  Collapse Description: Показать меньше\nAutoplay Interruption Timer: Автоигра отменена из-за {autoplayInterruptionIntervalHours} часов бездействия\nshortcutLabelSeparator: ｜\nCompact side navigation: Свернуть боковую панель\nExpand side navigation: Развернуть боковую панель\n"
  },
  {
    "path": "static/locales/sat.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ᱥᱟᱱᱛᱟᱲᱤ'\n\n# Webkit Menu Bar\nFile: 'ᱨᱮᱫᱽ'\nQuit: 'ᱵᱟᱹᱫ'\nEdit: 'ᱥᱟᱯᱲᱟᱣ'\nUndo: 'ᱞᱟᱹᱪᱷᱞᱟ'\nRedo: 'ᱫᱩᱦᱲᱟᱹ ᱫᱚᱦᱚ'\nCut: 'ᱜᱮᱫᱽ'\nCopy: 'ᱱᱚᱠᱚᱞ'\nPaste: 'ᱞᱟᱴᱷᱟ'\nDelete: 'ᱢᱮᱴᱟᱣ'\nSelect all: 'ᱡᱷᱚᱛᱚ ᱪᱚᱭᱚᱱ ᱢᱮᱸ'\nSearch Filters: {}\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\n  Player Settings: {}\nChannel:\n  Videos: {}\nTooltips: {}\nNew Window: ᱱᱟᱶᱟ ᱣᱤᱱᱰᱚ\nKeyboardShortcutPrompt:\n  Zoom Out: ᱢᱟᱨᱟᱝ ᱠᱷᱚᱱ ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ\n  Zoom In: ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ\nActual size: ᱴᱷᱤᱠ ᱢᱟᱨᱟᱝ ᱛᱮᱫ\nProfile:\n  Select All: ᱡᱷᱚᱛᱚ ᱪᱚᱭᱚᱱ ᱢᱮᱸ\nZoom in: ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ\nZoom out: ᱢᱟᱨᱟᱝ ᱠᱷᱚᱱ ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ\n"
  },
  {
    "path": "static/locales/si.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'සිංහල'\n\n# Webkit Menu Bar\nFile: 'ගොනුව'\nQuit: 'ඉවත් වන්න'\nEdit: 'සංස්කරණය කරන්න'\nUndo: 'පෙරසේ'\nRedo: 'පසුසේ'\nCut: 'කපන්න'\nCopy: 'පිටපත්'\nPaste: 'අලවන්න'\nDelete: 'මකන්න'\nSelect all: 'සියල්ල තෝරන්න'\nActual size: 'සැබෑ ප්‍රමාණය'\nZoom in: 'විශාලනය'\nZoom out: 'කුඩාලනය'\nMinimize: 'හකුලන්න'\nClose: 'වසන්න'\nBack: 'ආපසු'\nVersion {versionNumber} is now available!  Click for more details: '{versionNumber}\n  අනුවාදය දැන් ලබා ගත හැකිය!  වැඩි විස්තර සඳහා ඔබන්න'\nDownload From Site: 'අඩවියෙන් බාගන්න'\nSearch / Go to URL: 'සොයන්න / ඒ.ස.නි.(URL) වෙත යන්න'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'පෙරහන් සොයන්න'\n  Time:\n    Today: 'අද'\n    This Week: 'මෙම සතිය'\n    This Month: 'මෙම මාසය'\n    This Year: 'මෙම අවුරුද්ද'\n  Type:\n    Type: 'වර්ගය'\n    All Types: 'සියලුම වර්ග'\n    Videos: 'වීඩියෝ'\n    Channels: 'නාලිකා'\n    #& Playlists\n  Duration:\n    Duration: 'කාල සීමාව'\n    All Durations: 'සියලුම කාල සීමාවන්'\n    Short (< 4 minutes): 'කෙටි (විනාඩි <4)'\n    Long (> 20 minutes): 'දීර්ඝ (විනාඩි > 20)'\n  # On Search Page\n  Search Results: 'සෙවුම් ප්‍රතිඵල'\n  Fetching results. Please wait: 'ප්‍රතිඵල ගෙනෙමින්. කරුණාකර රැඳී සිටින්න'\n  Fetch more results: 'තවත් ප්‍රතිඵල ගෙනෙන්න'\n# Sidebar\n  There are no more results for this search: මෙම සෙවීම සඳහා තවත් ප්‍රතිඵල නැත\nSubscriptions:\n    # On Subscriptions Page\n  Load More Videos: තව දෘශ්‍යක පූරනය කරන්න\nHistory:\n  # On History Page\n  History: 'ඉතිහාසය'\n  Watch History: 'නැරඹීම් ඉතිහාසය'\nSettings:\n  # On Settings Page\n  Settings: 'සැකසුම්'\n  General Settings:\n    General Settings: 'සාමාන්‍ය සැකසුම්'\n    Check for Updates: 'යාවත්කාල බලන්න'\n    Preferred API Backend:\n      Local API: 'ස්ථානීය යෙ.ක්‍ර. අ.මු. (API)'\n      Invidious API: 'ඉන්වීඩියස් යෙ.ක්‍ර. අ.මු. (API)'\n  Theme Settings:\n    Base Theme:\n      Black: 'කළු'\n      Dark: 'අඳුරු'\n  Player Settings: {}\nChannel:\n  Playlists: {}\n  Videos:\n    Videos: වීඩියෝ\nMore: තව\nOpen New Window: නව කවුළුව විවෘත කරන්න\nGlobal:\n  Videos: වීඩියෝ\n  Live: සජීවී\n  Sort By: අනුපිළිවෙළට සකසන්න\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\nNew Window: නව කවුළුව\nProfile:\n  Select All: සියල්ල තෝරන්න\nKeyboardShortcutPrompt:\n  Zoom In: විශාලනය\n  Zoom Out: කුඩාලනය\n"
  },
  {
    "path": "static/locales/sk.yaml",
    "content": "# Webkit Menu Bar\nFile: 'Súbor'\nQuit: 'Ukončiť'\nEdit: 'Upraviť'\nUndo: 'Vrátiť späť'\nRedo: 'Znovu vykonať'\nCut: 'Vystrihnúť'\nCopy: 'Kopírovať'\nPaste: 'Vložiť'\nDelete: 'Vymazať'\nSelect all: 'Vybrať všetko'\nToggle Developer Tools: 'Prepnúť vývojárske nástroje'\nActual size: 'Aktuálna veľkosť'\nZoom in: 'Priblížiť'\nZoom out: 'Oddialiť'\nToggle fullscreen: 'Prepnúť na celú obrazovku'\nWindow: 'Okno'\nMinimize: 'Minimalizovať'\nClose: 'Zatvoriť'\nBack: 'Dozadu'\nForward: 'Dopredu'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videá'\n\n# Search Bar\n  Counts:\n    Video Count: 1 video | {count} videí\n    Subscriber Count: 1 odberateľ | {count} odberateľov\n    Channel Count: 1 kanál | {count} kanálov\n    View Count: 1 zobrazenie | {count} zobrazení\n    Watching Count: 1 sledujúci | {count} sledujúcich\n    Like Count: 1 lajk | {count} lajkov\n    Comment Count: 1 komentár | {count} komentárov\n  Live: Naživo\n  Posts: Príspevky\n  Shorts: Krátke\n  Sort By: 'Triediť podľa'\nSearch / Go to URL: 'Hľadať / Ísť na URL adresu'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Vyhľadávacie filtre'\n  Sort By:\n    Most Relevant: 'Najdôležitejšie'\n    Rating: 'Hodnotenie'\n    Upload Date: 'Dátum nahrávania'\n    View Count: 'Počet pozeraní'\n  Time:\n    Time: 'Čas'\n    Any Time: 'Kedykoľvek'\n    Last Hour: 'Posledná hodina'\n    Today: 'Dnes'\n    This Week: 'Tento týždeň'\n    This Month: 'Tento mesiac'\n    This Year: 'Tento rok'\n  Type:\n    Type: 'Typ'\n    All Types: 'Všetky typy'\n    Videos: 'Videá'\n    Channels: 'Kanály'\n    #& Playlists\n    Movies: Filmy\n  Duration:\n    Duration: 'Trvanie'\n    All Durations: 'Všetky trvania'\n    Short (< 4 minutes): 'Krátke (menej ako 4 minúty)'\n    Long (> 20 minutes): 'Dlhé (viac ako 20 minút)'\n  # On Search Page\n    Medium (4 - 20 minutes): Stredné (4 až 20 minút)\n  Search Results: 'Výsledky vyhľadávania'\n  Fetching results. Please wait: 'Načítavanie výsledkov. Čakajte, prosím'\n  Fetch more results: 'Načítať viac výsledkov'\n# Sidebar\n  There are no more results for this search: Pre toto vyhľadávanie nie sú ďalšie výsledky\n  Features:\n    Subtitles: Titulky\n    Features: Vlastnosti\n    HD: HD\n    Creative Commons: Creative Commons\n    3D: 3D\n    4K: 4K\n    360 Video: 360 Video\n    Location: Umiestnenie\n    Live: Naživo\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Vyčistiť filtre\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Odbery'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Váš zoznam odberov je momentálne prázdny. Ak chcete importovať svoje odbery, prejdite do časti Nastavenia údajov a vyberte možnosť Importovať odbery alebo môžete vyhľadať kanál a prihlásiť sa na jeho odber.'\n  Load More Videos: Načítať viac videí\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Tento profil má veľký počet odberov.  Vynútenie RSS, aby sa zabránilo obmedzeniu rýchlosti\n  Empty Channels: Vaše odoberané kanály momentálne nemajú žiadne videá.\n  Load More Posts: Načítať ďalšie príspevky\n  Subscriptions Tabs: Karty s odbermi\n  All Subscription Tabs Hidden: Všetky karty odberov sú skryté. Ak tu chcete vidieť obsah, odkryte niektoré karty v sekcii \"{subsection}\" v časti \"{settingsSection}\".\n  Error Channels: Kanály s chybami\n  Empty Posts: Vaše odoberané kanály momentálne nemajú žiadne príspevky.\n  Disabled Automatic Fetching: Vypli ste automatické načítanie odberov. Obnovte odbery, aby ste ich tu videli.\nTrending:\n  Trending: 'Trendy'\n  Trending Tabs: Karty trendov\n  Gaming: Hry\n  Sports: Šport\nMost Popular: 'Najpopulárnejšie'\nPlaylists: 'Playlisty'\nUser Playlists:\n  Your Playlists: 'Vaše playlisty'\n  You have no playlists. Click on the create new playlist button to create a new one.: Nemáte žiadne playlisty. Kliknutím na tlačidlo playlistu vytvoríte nový.\n  Empty Search Message: V tomto playliste nie sú žiadne videá zodpovedajúce vášmu vyhľadávaniu\n  Add to Playlist: Pridať do playlistu\n  Move Video Down: Posunúť video nadol\n  Copy Playlist: Kopírovať playlist\n  Search bar placeholder: Vyhľadať playlisty\n  Create New Playlist: Vytvoriť nový playlist\n  This playlist currently has no videos.: Tento playlist momentálne nemá žiadne videá.\n  Add to Favorites: Pridať do playlistu {playlistName}\n  Remove from Favorites: Odstrániť z playlistu {playlistName}\n  Playlist Name: Názov playlistu\n  Cancel: Zrušiť\n  Playlist Description: Popis playlistu\n  Playlists with Matching Videos: Playlisty so zodpovedajúcimi videami\n  Remove from Playlist: Odstrániť z playlistu\n  Save Changes: Uložiť zmeny\n  Edit Playlist Info: Upraviť informácie o playliste\n  Remove Watched Videos: Odstrániť pozerané videá\n  Remove Duplicate Videos: Odstrániť duplicitné videá\n  Move Video Up: Posunúť video nahor\n  SinglePlaylistView:\n    Toast:\n      This playlist does not exist: Tento playlist neexistuje\n      Video has been removed: Video bolo odstránené\n      There was a problem with removing this video: Došlo k problému pri odstránení tohto videa\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Niektoré videá v playliste nie sú ešte načítané. Ak chcete predsa len skopírovať, kliknite sem.\n      \"{videoCount} video(s) have been removed\": '1 video bolo odstránené | Počet odstránených videí: {videoCount}'\n      Playlist {playlistName} has been deleted.: Playlist {playlistName} bol vymazaný.\n      There were no videos to remove.: Neboli žiadne videá na odstránenie.\n      Playlist has been updated.: Playlist bol aktualizovaný.\n      This playlist is protected and cannot be removed.: Tento playlist je chránený a nemôže byť odstránený.\n      This video cannot be moved up.: Toto video nemôže byť posunuté nahor.\n      This video cannot be moved down.: Toto video nemôže byť posunuté nadol.\n      This playlist has a video with a duration error: Tento playlist obsahuje aspoň jedno video, ktoré nemá trvanie, bude zoradený akoby jeho trvanie bolo nula.\n      There was an issue with updating this playlist.: Došlo k problému pri aktualizácii tohto playlistu.\n      Video has been removed. Click here to undo.: Video bolo odstránené. Kliknite sem pre vrátenie späť.\n      Playlist name cannot be empty. Please input a name.: Názov playlistu nemôže byť prázdny. Prosím zadajte názov.\n      This playlist is already being used for quick bookmark.: Tento playlist sa už používa pre rýchle záložky.\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Tento playlist sa teraz používa pre rýchle záložky namiesto {oldPlaylistName}. Kliknite sem pre vrátenie späť\n      This playlist is now used for quick bookmark: Tento playlist sa teraz používa pre rýchle záložky\n      Reverted to use {oldPlaylistName} for quick bookmark: Vrátené na použitie {oldPlaylistName} pre rýchle záložky\n    Search for Videos: Vyhľadať videá\n  Sort By:\n    NameAscending: A-Z\n    LatestCreatedFirst: Dátum vytvorenia (najnovšie)\n    LatestUpdatedFirst: Dátum aktualizácie (najnovšie)\n    NameDescending: Z-A\n    EarliestCreatedFirst: Dátum vytvorenia (najstaršie)\n    LatestPlayedFirst: Dátum prehrávania (najnovšie)\n    EarliestPlayedFirst: Dátum prehrávania (najstaršie)\n    EarliestUpdatedFirst: Dátum aktualizácie (najstaršie)\n  Are you sure you want to delete this playlist? This cannot be undone: Naozaj chcete vymazať tento playlist? Toto sa nedá vrátiť späť.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Naozaj chcete z tohto playlistu odstrániť 1 duplicitné video? Toto sa nedá vrátiť späť. | Naozaj chcete z tohto playlistu odstrániť duplicitné videá v počte {playlistItemCount}? Toto sa nedá vrátiť späť.\n  Export Playlist: Exportovať tento playlist\n  The playlist has been successfully exported: Playlist bol úspešne exportovaný\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Naozaj chcete z tohto playlistu odstrániť 1 pozerané video? Toto sa nedá vrátiť späť. | Naozaj chcete z tohto playlistu odstrániť pozerané videá v počte {playlistItemCount}? Toto sa nedá vrátiť späť.\n  Delete Playlist: Vymazať playlist\n  AddVideoPrompt:\n    Allow Adding Duplicate Video(s): Povoliť pridávanie duplicitnych videí\n    N playlists selected: 'Vybrané: {playlistCount}'\n    Search in Playlists: Vyhľadať v playlistoch\n    Added {count} Times: Už pridané | Pridané {count} krát\n    Select a playlist to add your N videos to: Vyberte playlist pre pridanie vášho videa | Vyberte playlist pre pridanie vašich {videoCount} videí\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": 'Počet už pridaných videí: {videoCount}/{totalVideoCount}'\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"Video(á) pridané do 1 playlistu | Video(á) pridané do {playlistCount} playlistov\"\n      You haven't selected any playlist yet.: Ešte ste nevybrali žiadny playlist.\n    Save: Uložiť\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": 'Budú pridané videá: {videoCount}/{totalVideoCount}'\n  Quick Bookmark Enabled: Rýchle záložky zapnuté\n  Enable Quick Bookmark With This Playlist: Zapnúť rýchle záložky v tomto playliste\n  TotalTimePlaylist: 'Celkový čas: {duration}'\n  Cannot delete the quick bookmark target playlist.: Nie je možné vymazať cieľový playlist rýchlych záložiek.\n  CreatePlaylistPrompt:\n    Create: Vytvoriť\n    Toast:\n      There was an issue with creating the playlist.: Došlo k problému pri vytváraní playlistu.\n      There is already a playlist with this name. Please pick a different name.: Playlist s týmto názvom už existuje. Vyberte iný názov.\n      Playlist {playlistName} has been successfully created.: Playlist {playlistName} bol úspešne vytvorený.\n    New Playlist Name: Názov nového playlistu\n  Export list of URLs: Exportovať zoznam adries URL\nHistory:\n  # On History Page\n  History: 'História'\n  Watch History: 'História pozerania'\n  Your history list is currently empty.: 'Váš zoznam histórie je momentálne prázdny.'\n  Search bar placeholder: Vyhľadať v histórii\n  Case Sensitive Search: Vyhľadávanie s rozlišovaním veľkých a malých písmen\n  Empty Search Message: V histórii nie sú žiadne videá zodpovedajúce vášmu vyhľadávaniu\n  DateOldestHistory: Dátum pozerania (najstaršie)\n  DateNewestHistory: Dátum pozerania (najnovšie)\nSettings:\n  # On Settings Page\n  Settings: 'Nastavenia'\n  General Settings:\n    General Settings: 'Všeobecné'\n    Fallback to Non-Preferred Backend on Failure: 'Pri chybe prepnúť na alternatívny backend'\n    Enable Search Suggestions: 'Zapnúť návrhy vyhľadávania'\n    Default Landing Page: 'Predvolená vstupná stránka'\n    Locale Preference: 'Nastaviť jazyk'\n    Preferred API Backend:\n      Preferred API Backend: 'Preferované API Backend'\n      Local API: 'Lokálne API'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Typ zobrazenia videa'\n      Grid: 'Mriežka'\n      List: 'Zoznam'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Preferencia náhľadu'\n      Default: 'Predvolene'\n      Beginning: 'Začiatok'\n      Middle: 'Stred'\n      End: 'Koniec'\n      Hidden: Skryté\n      Blur: Rozmazané\n    Region for Trending: 'Región pre trendy'\n        #! List countries\n    Check for Latest Blog Posts: Kontrolovať najnovšie príspevky na blogu\n    Check for Updates: Kontrolovať aktualizácie\n    View all Invidious instance information: Zobraziť všetky informácie o inštancii Invidious\n    System Default: Podľa systému\n    Set Current Instance as Default: Nastaviť aktuálnu inštanciu ako predvolenú\n    External Link Handling:\n      External Link Handling: Spracovanie externých odkazov\n      No Action: Žiadna akcia\n      Ask Before Opening Link: Spýtať sa pred otvorením odkazu\n      Open Link: Otvoriť odkaz\n    The currently set default instance is {instance}: Aktuálne nastavená predvolená inštancia je {instance}\n    No default instance has been set: Nebola nastavená žiadna predvolená inštancia\n    Current instance will be randomized on startup: Aktuálna inštancia bude pri spustení náhodná\n    Clear Default Instance: Vyčistiť predvolenú inštanciu\n    Current Invidious Instance: Aktuálna inštancia Invidious\n    Auto Load Next Page:\n      Tooltip: Automaticky načíta ďalšie stránky a komentáre.\n      Label: Automaticky načítať ďalšiu stránku\n    Open Deep Links In New Window: Otvoriť adresy URL odoslané do FreeTube v novom okne\n    Minimize to system tray: Minimalizovať do systémovej lišty\n  Theme Settings:\n    Theme Settings: 'Téma'\n    Match Top Bar with Main Color: 'Prispôsobiť hornú lištu hlavnej farbe'\n    Base Theme:\n      Base Theme: 'Základnâ téma'\n      Black: 'Čierna'\n      Dark: 'Tmavá'\n      Light: 'Svetlá'\n      Dracula: 'Dracula'\n      Nordic: Nordic\n      Gruvbox Dark: Gruvbox tmavá\n      Gruvbox Light: Gruvbox svetlá\n      System Default: Systémovo predvolená\n      Everforest Light Hard: Everforest svetlá drsná\n      Solarized Light: Solarized svetlá\n      Catppuccin Mocha: Catpuccino Mocha\n      Everforest Dark Low: Everforest tmavá jemná\n      Everforest Light Medium: Everforest svetlá stredná\n      Everforest Light Low: Everforest svetlá jemná\n      Pastel Pink: Pastelovo ružová\n      Everforest Dark Hard: Everforest tmavá drsná\n      Catppuccin Frappe: Catppuccin Frappe\n      Hot Pink: Horúca ružová\n      Solarized Dark: Solarized tmavá\n      Everforest Dark Medium: Everforest tmavá stredná\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Hlavná farba témy'\n      Red: 'Červená'\n      Pink: 'Ružová'\n      Purple: 'Fialová'\n      Deep Purple: 'Tmavofialová'\n      Indigo: 'Indigová'\n      Blue: 'Modrá'\n      Light Blue: 'Svetlomodrá'\n      Cyan: 'Azúrová'\n      Teal: 'Modrozelená'\n      Green: 'Zelená'\n      Light Green: 'Svetlozelená'\n      Lime: 'Limetková'\n      Yellow: 'Žltá'\n      Amber: 'Jantárová'\n      Orange: 'Oranžová'\n      Deep Orange: 'Tmavooranžová'\n      Dracula Cyan: 'Dracula azúrová'\n      Dracula Green: 'Dracula zelená'\n      Dracula Orange: 'Dracula oranžová'\n      Dracula Pink: 'Dracula ružová'\n      Dracula Purple: 'Dracula fialová'\n      Dracula Red: 'Dracula červená'\n      Dracula Yellow: 'Dracula žltá'\n      Catppuccin Frappe Rosewater: Catppuccin Frappe ružová voda\n      Catppuccin Frappe Flamingo: Catppuccin Frappe plameniakovoružová\n      Catppuccin Frappe Pink: Catppuccin Frappe ružová\n      Catppuccin Frappe Mauve: Catppuccin Frappe lilavá\n      Catppuccin Frappe Red: Catppuccin Frappe červená\n      Catppuccin Frappe Maroon: Catppuccin Frappe gaštanovohnedá\n      Catppuccin Frappe Peach: Catppuccin Frappe broskyňová\n      Catppuccin Frappe Yellow: Catppuccin Frappe žltá\n      Catppuccin Frappe Green: Catppuccin Frappe zelená\n      Catppuccin Frappe Teal: Catppuccin Frappe modrozelená\n      Catppuccin Frappe Sky: Catppuccin Frappe nebeská modrá\n      Catppuccin Frappe Sapphire: Catppuccin Frappe zafírová\n      Catppuccin Frappe Blue: Catppuccin Frappe modrá\n      Catppuccin Frappe Lavender: Catppuccin Frappe levanduľová\n      Catppuccin Latte Mauve: Catppuccin Latte lilavá\n      Catppuccin Latte Red: Catppuccin Latte červená\n      Catppuccin Mocha Rosewater: Catppuccin Mocha ružová voda\n      Catppuccin Mocha Flamingo: Catppuccin Mocha plameniakovoružová\n      Catppuccin Mocha Pink: Catppuccin Mocha ružová\n      Catppuccin Mocha Mauve: Catppuccin Mocha lilavá\n      Catppuccin Mocha Red: Catppuccin Mocha červená\n      Catppuccin Mocha Maroon: Catppuccin Mocha gaštanovohnedá\n      Catppuccin Mocha Peach: Catppuccin Mocha broskyňová\n      Catppuccin Mocha Yellow: Catppuccin Mocha žltá\n      Catppuccin Mocha Green: Catppuccin Mocha zelená\n      Catppuccin Mocha Teal: Catppuccin Mocha modrozelená\n      Catppuccin Mocha Sky: Catppuccin Mocha nebeská modrá\n      Catppuccin Mocha Sapphire: Catppuccin Mocha zafírová\n      Catppuccin Mocha Blue: Catppuccin Mocha modrá\n      Catppuccin Mocha Lavender: Catppuccin Mocha levanduľová\n      Gruvbox Dark Green: Gruvbox tmavozelená\n      Gruvbox Dark Yellow: Gruvbox tmavožltá\n      Gruvbox Dark Blue: Gruvbox tmavomodrá\n      Gruvbox Dark Purple: Gruvbox tmavofialová\n      Gruvbox Dark Aqua: Gruvbox tmavá akvamarínová\n      Gruvbox Dark Orange: Gruvbox tmavooranžová\n      Gruvbox Light Red: Gruvbox svetločervená\n      Gruvbox Light Blue: Gruvbox svetlomodrá\n      Gruvbox Light Purple: Gruvbox svetlofialová\n      Gruvbox Light Orange: Gruvbox svetlooranžová\n      Solarized Yellow: Solarized žltá\n      Solarized Orange: Solarized oranžová\n      Solarized Red: Solarized červená\n      Solarized Magenta: Solarized purpurová\n      Solarized Violet: Solarized fialková\n      Solarized Blue: Solarized modrá\n      Solarized Cyan: Solarized azúrová\n      Solarized Green: Solarized zelená\n      Everforest Dark Red: Everforest tmavočervená\n      Everforest Dark Orange: Everforest tmavooranžová\n      Everforest Dark Yellow: Everforest tmavožltá\n      Everforest Dark Green: Everforest tmavozelená\n      Everforest Dark Aqua: Everforest tmavá akvamarínová\n      Everforest Dark Blue: Everforest tmavomodrá\n      Everforest Dark Purple: Everforest tmavofialová\n      Everforest Light Red: Everforest svetločervená\n      Everforest Light Orange: Everforest svetlooranžová\n      Everforest Light Yellow: Everforest svetložltá\n      Everforest Light Green: Everforest svetlozelená\n      Everforest Light Aqua: Everforest svetlá akvamarínová\n      Everforest Light Blue: Everforest svetlomodrá\n      Everforest Light Purple: Everforest svetlofialová\n    Secondary Color Theme: 'Sekundárna farba témy'\n        #* Main Color Theme\n    UI Scale: Veľkosť UI\n    Disable Smooth Scrolling: Vypnúť plynulé posúvanie\n    Expand Side Bar by Default: Predvolene rozbaliť bočnú lištu\n    Hide Side Bar Labels: Skryť označenia bočnej lišty\n    Hide FreeTube Header Logo: Skryť logo hlavičky FreeTube\n  Player Settings:\n    Player Settings: 'Prehrávač'\n    Play Next Video: 'Automaticky prehrávať odporúčané videá'\n    Turn on Subtitles by Default: 'Zapnúť titulky predvolene'\n    Autoplay Videos: 'Spustiť videá automaticky'\n    Proxy Videos Through Invidious: 'Proxy videá cez Invidious'\n    Autoplay Playlists: 'Automaticky prehrávať videá v playliste'\n    Enable Theatre Mode by Default: 'Predvolene zapínať Kino mód'\n    Default Volume: 'Predvolená hlasitosť'\n    Default Playback Rate: 'Predvolená rýchlosť prehrávania'\n    Default Video Format:\n      Default Video Format: 'Predvolený formát videa'\n      Dash Formats: 'Formáty DASH'\n      Legacy Formats: 'Staré formáty'\n      Audio Formats: 'Zvukové formáty'\n    Default Quality:\n      Default Quality: 'Predvolená kvalita'\n      Auto: 'Automaticky'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Časovač odpočítavania automatického prehrávania\n    Scroll Playback Rate Over Video Player: Meniť rýchlosť prehrávania posúvaním cez prehrávač videa\n    Fast-Forward / Rewind Interval: Interval rýchleho posunu dopredu / dozadu\n    Display Play Button In Video Player: Zobraziť tlačidlo prehrávania v prehrávači videa\n    Scroll Volume Over Video Player: Meniť hlasitosť posúvaním cez prehrávač videa\n    Screenshot:\n      Error:\n        Empty File Name: Prázdny názov súboru\n        Forbidden Characters: Zakázané znaky\n      File Name Tooltip: Môžete používať nasledujúce premenné. %Y Rok 4 číslice. %M Mesiac 2 číslice. %D Deň 2 číslice. %H Hodina 2 číslice. %N Minúta 2 číslice. %S Sekunda 2 číslice. %T Milisekunda 3 číslice. %s Sekunda videa. %t Milisekunda videa 3 číslice. %i ID videa.\n      File Name Label: Vzor názvu súboru\n      Folder Button: Vybrať priečinok\n      Folder Label: Priečinok snímky obrazovky\n      Ask Path: Spýtať sa na priečinok uloženia\n      Quality Label: Kvalita snímky obrazovky\n      Format Label: Formát snímky obrazovky\n      Enable: Povoliť snímku obrazovky\n    Video Playback Rate Interval: Interval rýchlosti prehrávania videa\n    Max Video Playback Rate: Maximálna rýchlosť prehrávania videa\n    Autoplay Interruption Timer: Časovač prerušenia automatického prehrávania\n    Enter Fullscreen on Display Rotate: Prejsť do režimu celej obrazovky pri otočení displeja\n    Skip by Scrolling Over Video Player: Preskočiť posúvaním cez prehrávač videa\n    Default Viewing Mode:\n      External Player: Externý prehrávač ({externalPlayerName})\n      Picture in Picture: Obraz v obraze\n      Full Screen: Celá obrazovka\n      Default Viewing Mode: Predvolený režim zobrazenia\n      Theater: Kino\n  Subscription Settings:\n    Subscription Settings: 'Odber'\n    Fetch Feeds from RSS: Načítať kanály z RSS\n\n    Confirm Before Unsubscribing: Potvrdiť pred odhlásením\n    To: Do\n    'Limit the number of videos displayed for each channel': Obmedziť počet zobrazovaných videí pre každý kanál\n    Fetch Automatically: Automaticky načítať kanál\n  Data Settings:\n    How do I import my subscriptions?: Ako môžem importovať svoje odbery?\n    Unknown data key: Neznámy dátový kľúč\n    Unable to write file: Súbor sa nepodarilo zapísať\n    Unable to read file: Súbor sa nepodarilo prečítať\n    All watched history has been successfully exported: Celá história pozerania bola úspešne exportovaná\n    All watched history has been successfully imported: Celá história pozerania bola úspešne importovaná\n    History object has insufficient data, skipping item: Predmet histórie má nedostatočné údaje, preskakovanie položky\n    Subscriptions have been successfully exported: Odbery boli úspešne exportované\n    Invalid history file: Chybný súbor histórie\n    Invalid subscriptions file: Chybný súbor odberov\n    All subscriptions have been successfully imported: Všetky odbery boli úspešne importované\n    All subscriptions and profiles have been successfully imported: Všetky odbery a profily boli úspešne importované\n    Profile object has insufficient data, skipping item: Predmet profilu má nedostatočné údaje, preskakovanie položky\n    Export History: Exportovať históriu\n    Import History: Importovať históriu\n    Export NewPipe: Exportovať dáta vo formáte NewPipe\n    Export YouTube: Exportovať dáta vo formáte Youtube\n    Export FreeTube: Exportovať dáta vo formáte FreeTube\n    Export Subscriptions: Exportovať odbery\n    Import Subscriptions: Importovať odbery\n    Select Export Type: Vybrať typ exportu\n    Data Settings: Dáta\n    Manage Subscriptions: Spravovať odbery\n    Search history file: Súbor histórie vyhľadávania\n    Search history: História vyhľadávania\n    Import search history: Importovať históriu vyhľadávania\n    Export search history: Exportovať históriu vyhľadávania\n    All search history has been successfully imported: Celá história vyhľadávania bola úspešne importovaná\n    All search history has been successfully exported: Celá história vyhľadávania bola úspešne exportovaná\n    All playlists has been successfully exported: Všetky playlisty boli úspešne exportované\n    All playlists has been successfully imported: Všetky playlisty boli úspešne importované\n    Playlist insufficient data: Nedostatočné údaje pre playlist \"{playlist}\", preskakovanie položky\n    Export Playlists: Exportovať playlisty\n    Import Playlists: Importovať playlisty\n    Playlist File: Súbor playlistov\n    History File: Súbor histórie\n    Subscription File: Súbor odberov\n  Distraction Free Settings:\n    Hide Live Chat: Skryť živý chat\n    Hide Popular Videos: Skryť populárne videá\n    Hide Trending Videos: Skryť trendujúce videá\n    Hide Recommended Videos: Skryť odporúčané videá\n    Hide Comment Likes: Skryť hodnotenie komentárov\n    Hide Channel Subscribers: Skryť počet odberateľov\n    Hide Video Likes And Dislikes: Skryť hodnotenie videa\n    Hide Video Views: Skryť počet zobrazení\n    Distraction Free Settings: Bez rušenia\n    Hide Active Subscriptions: Skryť aktívne odbery\n    Hide Playlists: Skryť playlisty\n    Hide Videos on Watch: 'Skryť videá pri pozeraní'\n    Show Added Items: Zobraziť pridané položky\n    Hide Subscriptions Posts: Skryť príspevky odberov\n    Hide Subscriptions Live: Skryť živé prenosy odberov\n    Hide Subscriptions Shorts: Skryť krátke videá odberov\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Slovo, časť slova alebo fráza\n    Hide Videos, Playlists and Channels Containing Text: Skryť videá, playlisty a kanály obsahujúce text\n    Hide Channel Courses: Skryť kartu kanálov \"Kurzy\"\n    Hide Channel Releases: Skryť kartu kanálov \"Vydania\"\n    Hide Channel Podcasts: Skryť kartu kanálov \"Podcasty\"\n    Hide Channel Shorts: Skryť kartu kanálov \"Krátke\"\n    Hide Channel Home: Skryť kartu kanálov \"Domov\"\n    Hide Channel Posts: Skryť kartu kanálov \"Príspevky\"\n    Hide Channel Playlists: Skryť kartu kanálov \"Playlisty\"\n    Hide Featured Channels: Skryť odporúčané kanály\n    Hide Channels Already Exists: ID kanála už existuje\n    Hide Subscriptions Videos: Skryť videá odberov\n    Hide Channels API Error: Chyba pri načítaní používateľa so zadaným ID. Skontrolujte, či je ID správny.\n    Hide Channels Invalid: Zadaný ID kanála bol neplatný\n    Hide Channels Placeholder: ID kanála\n    Hide Channels Disabled Message: Niektoré kanály boli blokované pomocou ID a neboli spracované. Funkcia je blokovaná počas aktualizácie týchto ID\n    Hide Channels: Skryť videá z kanálov\n    Hide Chapters: Skryť kapitoly\n    Hide Sharing Actions: Skryť akcie zdieľania\n    Hide Upcoming Premieres: Skryť nadchádzajúce premiéry\n    Hide Live Streams: Skryť živé prenosy\n    Display Titles Without Excessive Capitalisation: Zobraziť nadpisy bez nadmerne veľkého písma a interpunkcie\n    Hide Profile Pictures in Comments: Skryť profilové obrázky v komentároch\n    Hide Comments: Skryť komentáre\n    Hide Video Description: Skryť popis videa\n    Sections:\n      General: Všeobecné\n      Watch Page: Stránka pozerania\n      Channel Page: Stránka kanála\n      Subscriptions Page: Stránka odberov\n      Side Bar: Bočná lišta\n  Privacy Settings:\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Naozaj chcete odstrániť všetky odbery a profily? Toto sa nedá vrátiť späť.\n    Remove All Subscriptions / Profiles: Odstrániť všetky odbery / profily\n    Remove Watch History: Odstrániť históriu pozerania\n    Are you sure you want to clear out your search cache?: Ste si istý, že chcete vymazať vyrovnávaciu pamäť vyhľadávania?\n    Clear Search Cache: Zmazať vyrovnávaciu pamäť vyhľadávania\n    Save Watched Progress: Uložiť postup pozerania\n    Remember History: Pamätať si históriu pozerania\n    Privacy Settings: Súkromie\n    Watch history has been cleared: História pozerania bola vyčistená\n    Are you sure you want to remove your entire watch history?: Naozaj chcete odstrániť celú históriu pozerania?\n    Search cache has been cleared: Vyrovnávacia pamäť vyhľadávania bola vymazaná\n    Remember Search History: Pamätať si históriu vyhľadávania\n    Clear Search History and Cache: Vyčistiť históriu vyhľadávania a medzipamäť\n    Are you sure you want to clear out your search history and cache?: Naozaj chcete vyčistiť históriu vyhľadávania a medzipamäť?\n    Search history and cache have been cleared: História vyhľadávania a medzipamäť boli vyčistené\n    Save Watched Videos With Last Viewed Playlist: Ukladať pozerané videá do naposledy zobrazeného playlistu\n    Remove All Playlists: Odstrániť všetky playlisty\n    All playlists have been removed: Všetky playlisty boli odstránené\n    Are you sure you want to remove all your playlists?: Naozaj chcete odstrániť všetky vaše playlisty?\n    Watched Progress Saving Mode:\n      Tooltip: Automaticky = Ukladá pri každom opustení stránky s videom, keď sa video skončí a pri chybe (napr. obmedzená rýchlosť a vypršanie platnosti relácie pozerania). Poloautomaticky = Podobne ako Automaticky okrem opustenia stránky s videom, pričom postup pozerania je možné uložiť manuálne pomocou tlačidla Uložiť postup pozerania, umiestnené pod prehrávačom videa.\n      Modes:\n        Never: Nikdy\n        Semi-auto: Poloautomaticky\n        Auto: Automaticky\n  The app needs to restart for changes to take effect. Restart and apply change?: Aplikácia sa musí reštartovať, aby sa zmeny prejavili. Reštartovať a aplikovať zmeny?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Chyba pri získavaní informácií o sieti. Je váš server proxy správne nakonfigurovaný?\n    City: Mesto\n    Region: Región\n    Country: Krajina\n    Ip: IP adresa\n    Your Info: Vaše údaje\n    Test Proxy: Testovať proxy\n    Clicking on Test Proxy will send a request to: Kliknutím na \"Testovať proxy\" sa odošle žiadosť na\n    Proxy Port Number: Číslo portu proxy servera\n    Proxy Host: Adresa proxy\n    Proxy Protocol: Protokol proxy\n    Enable Tor / Proxy: Povoliť Tor / server Proxy\n    Proxy Settings: Proxy\n    Proxy Password: Heslo proxy\n    Proxy Username: Používateľský názov proxy\n    Proxy Warning: FreeTube nemá vstavaný proxy server, ale môže sa pripojiť k externému proxy serveru, napríklad k serveru bežiacemu na vašom počítači, ako je Tor, alebo k externému proxy serveru, ako je SOCKS5 proxy server poskytovaný niektorými VPN. Ak je táto funkcia povolená, uistite sa, že je váš proxy server/Tor správne nakonfigurovaný, inak FreeTube nebude môcť načítať žiadne údaje.\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Upozorniť, keď bude segment sponzora preskočený\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API SponsorBlock (predvolená adresa je https://sponsor.ajay.app)\n    Enable SponsorBlock: Zapnúť SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Category Color: Farba kategórie\n    Skip Options:\n      Do Nothing: Nerobiť nič\n      Prompt To Skip: Spýtať sa na preskočenie\n      Show In Seek Bar: Zobraziť vo vyhľadávacej lište\n      Auto Skip: Automaticky preskočiť\n      Skip Option: Možnosť preskočenia\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL API generátora náhľadov DeArrow (predvolená adresa je https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Použiť DeArrow pre náhľady\n    UseDeArrowTitles: Použiť titulky videa DeArrow\n  External Player Settings:\n    Custom External Player Arguments: Vlastné argumenty externého prehrávača\n    External Player: Externý prehrávač\n    External Player Settings: Externý prehrávač\n    Ignore Unsupported Action Warnings: Ignorovať upozornenia na nepodporované akcie\n    Custom External Player Executable: Vlastný spustiteľný externý prehrávač\n    Players:\n      None:\n        Name: Žiadny\n    Ignore Default Arguments: Ignorovať predvolené argumenty\n  Sort Settings Sections (A-Z): Zoradiť sekcie nastavení (A-Z)\n  Return to Settings Menu: Vrátiť sa do menu nastavení\n  Parental Control Settings:\n    Hide Search Bar: Skryť lištu vyhľadávania\n    Show Family Friendly Only: Zobraziť len obsah vhodný pre rodinu\n    Hide Uploader on Watch page: Skryť nahrávača na stránke pozerania\n    Hide Unsubscribe Button: Skryť tlačidlo odhlásenia\n    Parental Control Settings: Rodičovská kontrola\n  Password Settings:\n    Remove Password: Odstrániť heslo\n    Set Password: Nastaviť heslo\n    Set Password To Prevent Access: Nastavte heslo na zabránenie prístupu k nastaveniam\n    Password Settings: Heslo\n  Password Dialog:\n    Enter Password To Unlock: Zadajte heslo pre odomknutie nastavení\n    Password: Heslo\n  Experimental Settings:\n    Replace HTTP Cache: Nahradiť medzipamäť HTTP\n    Warning: Tieto nastavenia sú experimentálne a môžu spôsobiť zlyhanie systému, ak sú aktivované. Dôrazne odporúčame vytvárať zálohy. Používate na vlastné riziko!\n    Experimental Settings: Experimentálne\n\nAbout:\n  #On About page\n  About: 'O FreeTube'\n  #& About\n#On Channel Page\n  FreeTube Wiki: Wiki FreeTube\n  Help: Pomoc\n  GitHub releases: Vydania na GitHube\n  Downloads / Changelog: Súbory na stiahnutie / Zoznam zmien\n  Beta: Testovacia verzia\n  Source code: Zdrojový kód\n  GitHub issues: Problémy z GitHubu\n  Report a problem: Nahlásiť problém\n  FAQ: Otázky a odpovede\n  Donate: Darujte\n  these people and projects: týmto ľuďom a projektom\n  Credits: Zásluhy\n  Translate: Preložiť\n  room rules: pravidlá miestností\n  Chat on Matrix: Napíšte nám na Matrix-e\n  Mastodon: Komunikačná platforma Mastodon\n  Email: Elektronická pošta\n  Blog: Blog\n  Website: Webstránka\n  Please check for duplicates before posting: Pred odoslaním prosím skontrolujte duplicitné otázky\n  Discussions: Diskusie\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licencované pod {licenseLink}\n  Please read the {roomRulesLink}: Prečítajte si prosím {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube existuje vďaka {creditsPageLink}\nChannel:\n  Subscribe: 'Odoberať'\n  Unsubscribe: 'Odhlásiť odber'\n  Search Channel: 'Vyhľadať v kanáli'\n  Your search results have returned 0 results: 'Vaše vyhľadávanie vrátilo 0 výsledkov'\n  Videos:\n    Videos: 'Videá'\n    This channel does not currently have any videos: 'Tento kanál momentálne nemá žiadne videá'\n    Sort Types:\n      Newest: 'Najnovšie'\n      Oldest: 'Najstaršie'\n      Most Popular: 'Najpopulárnejšie'\n  Playlists:\n    Playlists: 'Playlisty'\n    This channel does not currently have any playlists: 'Tento kanál momentálne nemá žiadne playlisty'\n    Sort Types:\n      Last Video Added: 'Posledné pridané video'\n      Newest: 'Najnovšie'\n      Oldest: 'Najstaršie'\n  About:\n    About: 'O kanáli'\n    Channel Description: 'Popis kanála'\n    Featured Channels: 'Odporúčané kanály'\n    Tags:\n      Search for: Vyhľadať \"{tag}\"\n      Tags: Označenia\n    Location: Lokácia\n    Joined: Pripojený\n    Details: Podrobnosti\n  Added channel to your subscriptions: Kanál bol pridaný k vašim odberom\n  Channel has been removed from your subscriptions: Kanál bol odstránený z vašich odberov\n  Removed subscription from {count} other channel(s): Odstránený odber z {count} iných kanálov\n  This channel does not allow searching: Tento kanál neumožňuje vyhľadávanie\n  Posts:\n    Video hidden by FreeTube: Video skryté FreeTube\n    Hide Answers: Skryť odpovede\n    Reveal Answers: Ukázať odpovede\n    View Full Post: Zobraziť celý príspevok\n    votes: 'Počet hlasov: {votes}'\n    This channel currently does not have any posts: Tento kanál momentálne nemá žiadne príspevky\n  Courses:\n    This channel does not currently have any courses: Tento kanál momentálne nemá žiadne kurzy\n    Courses: Kurzy\n  Releases:\n    This channel does not currently have any releases: Tento kanál momentálne nemá žiadne vydania\n    Releases: Vydania\n  Podcasts:\n    This channel does not currently have any podcasts: Tento kanál momentálne nemá žiadne podcasty\n    Podcasts: Podcasty\n  Home:\n    View Playlist: Pozrieť playlist\n    Home: Domov\n  Live:\n    This channel does not currently have any live streams: Tento kanál momentálne nemá žiadne živé prenosy\n    Live: Naživo\n  Shorts:\n    This channel does not currently have any shorts: Tento kanál momentálne nemá žiadne krátke videá\n  Channel Tabs: Karty kanálov\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Tento kanál je obmedzený vekom a momentálne nemôže byť pozeraný vo FreeTube.\n  This channel does not exist: Tento kanál neexistuje\nVideo:\n  Mark As Watched: 'Označiť ako pozerané'\n  Remove From History: 'Odstrániť z histórie'\n  Video has been marked as watched: 'Video bolo označené ako pozerané'\n  Video has been removed from your history: 'Video bolo odstránené z vašej histórie'\n  Open in YouTube: 'Otvoriť na Youtube'\n  Copy YouTube Link: 'Kopírovať odkaz YouTube'\n  Open YouTube Embedded Player: 'Otvoriť vstavaný prehrávač YouTube'\n  Copy YouTube Embedded Player Link: 'Kopírovať odkaz vstavaného prehrávača YouTube'\n  Open in Invidious: 'Otvoriť v Invidious'\n  Copy Invidious Link: 'Kopírovať odkaz Invidious'\n  Views: 'Zobrazenia'\n  Watched: 'Pozerané'\n  # As in a Live Video\n  Live: 'Naživo'\n  Live Now: 'Teraz naživo'\n  Live Chat: 'Živý chat'\n  Enable Live Chat: 'Povoliť živý chat'\n  Live Chat is currently not supported in this build.: 'Live chat nie je v tejto verzií momentálne podporovaný.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Live chat je povolený.   Po odoslaní sa tu zobrazia četové správy.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Živý chat momentálne nie je podporovaný s API Invidious. Vyžaduje sa priame spojenie s YouTube.'\n  Published on: 'Publikované dňa'\n#& Videos\n  Autoplay: Automatické prehrávanie\n  Starting soon, please refresh the page to check again: Čoskoro začína, obnovte stránku a znova skontrolujte\n  Started streaming on: Začiatok vysielania o\n  Streamed on: Odvysielané dňa\n  Previous: Predchádzajúce\n  Next: Ďalšie\n  Reverse Playlist: Obrátiť playlist\n  Shuffle Playlist: Zamiešať playlist\n  Loop Playlist: Opakovať playlist\n  Copy Invidious Channel Link: Kopírovať odkaz kanála Invidious\n  Open Channel in Invidious: Otvoriť kanál v Invidious\n  Copy YouTube Channel Link: Kopírovať odkaz kanála YouTube\n  Open Channel in YouTube: Otvoriť kanál v YouTube\n  Video has been removed from your saved list: Video bolo odstránené z vášho zoznamu uložených\n  Video has been saved: Video bolo uložené\n  Save Video: Uložiť video\n  Sponsor Block category:\n    music offtopic: Hudba offtopic\n    interaction: Interakcia\n    self-promotion: Sebapropagácia\n    outro: Záver\n    intro: Úvod\n    sponsor: Sponzor\n    filler: Výplň\n    recap: Zhrnutie\n  External Player:\n    OpenInTemplate: Otvoriť v {externalPlayer}\n    Unsupported Actions:\n      setting a playback rate: nastavenie rýchlosti prehrávania\n      reversing playlists: obrátenie playlistov\n      looping playlists: opakovanie playlistov\n      starting video at offset: spustenie videa od určitého miesta\n      opening playlists: otváranie playlistov\n      opening specific video in a playlist (falling back to opening the video): otvorenie konkrétneho videa v playliste (vrátenie sa k otvoreniu videa)\n      shuffling playlists: premiešavanie playlistov\n    playlist: playlist\n    UnsupportedActionTemplate: '{externalPlayer} nepodporuje: {action}'\n    video: video\n    OpeningTemplate: Otvára sa {videoOrPlaylist} v {externalPlayer}...\n#& Playlists\n  Player:\n    Skipped segment: Preskočený segment {segmentCategory}\n    Playback will resume automatically when your connection comes back: Prehrávanie bude automaticky pokračovať, keď sa obnoví pripojenie.\n    You appear to be offline: Zdá sa, že ste offline.\n    Stats:\n      CodecsVideoAudioNoItags: 'Kodeky: {videoCodec} / {audioCodec}'\n      CodecsVideoAudio: 'Kodeky: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Vynechané snímky: {droppedFrames} / Celkom snímok: {totalFrames}'\n      Buffered: 'Načítané: {bufferedPercentage}%'\n      Bandwidth: 'Šírka pásma: {bandwidth} kb/s'\n      Volume: 'Hlasitosť: {volumePercentage}%'\n      Bitrate: 'Dátový tok: {bitrate} kb/s'\n      Player Dimensions: 'Rozmery prehrávača: {width}x{height}'\n      Resolution: \"Rozlíšenie: {width}x{height}{'@'}{frameRate}\"\n      Media Formats: 'Formáty médií: {formats}'\n      Video ID: 'ID videa: {videoId}'\n      Stats: Štatistika\n    Hide Stats: Skryť štatistiku\n    Show Stats: Zobraziť štatistiku\n    Take Screenshot: Urobiť snímku obrazovky\n    Exit Full Window: Opustiť celé okno\n    Full Window: Celé okno\n    Exit Theatre Mode: Opustiť režim kina\n    Theatre Mode: Režim kina\n    Autoplay is on: Automatické prehrávanie je zapnuté\n    Autoplay is off: Automatické prehrávanie je vypnuté\n    Audio Tracks: Zvukové stopy\n    TranslatedCaptionTemplate: '{language} (preložené z \"{originalLanguage}\")'\n  DeArrow:\n    Show Modified Details: Zobraziť upravené detaily\n    Show Original Details: Zobraziť pôvodné detaily\n  Published:\n    In less than a minute: Za menej ako minútu\n  Show Super Chat Comment: Zobraziť komentár super chatu\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Živý chat nie je dostupný pre tento stream. Mohol byť zakázaný nahrávačom.\n  Unlisted: Neuvedené\n  Upcoming: Nadchádzajúce\n  Premieres: Premiéry\n  Unhide Channel: Zobraziť kanál\n  Hide Channel: Skryť kanál\n  Watched Progress Saved: Postup pozerania uložený\n  Save Watched Progress: Uložiť postup pozerania\n  More Options: Viac možností\n  DRMProtected: Videá chránené DRM nemôžu byť prehrávané vo FreeTube, pretože vyžadujú proprietárne, uzavreté zdrojové komponenty. Ak chcete pozerať toto video, prosím pozrite si ho na oficiálnej stránke YouTube vo webovom prehliadači s povoleným DRM.\n  AgeRestricted: Videá obmedzené vekom nemôžu byť pozerané vo FreeTube, pretože vyžadujú prihlásenie Google a použitie vekovo overeného účtu YouTube.\n  MembersOnly: Videá len pre členov nemôžu byť pozerané vo FreeTube, pretože vyžadujú prihlásenie Google a platené členstvo v kanáli nahrávača.\n  IP block: YouTube zablokoval pozeranie videa z vašej IP adresy. Prosím skúste prepnúť na inú VPN alebo proxy.\n  Scroll to Bottom: Posunúť na koniec\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Zostávajúci čas prvotnej reklamy: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Zostávajúci čas pauzy SABR: {remindingTimeSeconds} s'\n  Popout Live Chat: Popout Chat\nPlaylist:\n  #& About\n  View Full Playlist: 'Zobraziť celý playlist'\n  Last Updated On: 'Naposledy aktualizované dňa'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Playlist\n  Sort By:\n    Custom: Vlastné\n    VideoDurationDescending: Trvanie (najdlhšie)\n    VideoDurationAscending: Trvanie (najkratšie)\n    VideoTitleDescending: Názov (Z-A)\n    VideoTitleAscending: Názov (A-Z)\n    AuthorDescending: Autor (Z-A)\n    AuthorAscending: Autor (A-Z)\n    PublishedOldest: Dátum publikovania (najstaršie)\n    PublishedNewest: Dátum publikovania (najnovšie)\n    DateAddedOldest: Dátum pridania (najstaršie)\n    DateAddedNewest: Dátum pridania (najnovšie)\nChange Format:\n  Change Media Formats: 'Zmena formátov videa'\n  Use Dash Formats: 'Použiť formáty DASH'\n  Use Legacy Formats: 'Použiť staré formáty'\n  Use Audio Formats: 'Použiť zvukové formáty'\n  Dash formats are not available for this video: Formáty DASH nie sú dostupné pre toto video\n  Audio formats are not available for this video: Pre toto video nie sú dostupné zvukové formáty\n  Legacy formats are not available for this video: Staré formáty nie sú dostupné pre toto video\nShare:\n  Share Video: 'Zdieľať video'\n  Share Playlist: 'Zdieľať playlist'\n  Copy Link: 'Skopírovať odkaz'\n  Open Link: 'Otvoriť odkaz'\n  Copy Embed: 'Kopírovať vložené'\n  Open Embed: 'Otvoriť vložené'\n  # On Click\n  Invidious URL copied to clipboard: 'URL Invidious bola skopírovaná do schránky'\n  Invidious Embed URL copied to clipboard: 'Vložená URL Invidious bola skopírovaná do schránky'\n  YouTube URL copied to clipboard: 'URL adresa YouTube bola skopírovaná do schránky'\n  YouTube Embed URL copied to clipboard: 'Vložená URL adresa YouTube skopírovaná do schránky'\n  Include Timestamp: Zahrnúť časovú pečiatku\n  YouTube Channel URL copied to clipboard: URL kanála YouTube bola skopírovaná do schránky\n  Invidious Channel URL copied to clipboard: URL kanála Invidious skopírovaná do schránky\n  Share Channel: Zdieľať kanál\n  Share Post: Zdieľať príspevok\nMini Player: 'Mini prehrávač'\nComments:\n  Comments: 'Komentáre'\n  Click to View Comments: 'Kliknutím zobrazíte komentáre'\n  Getting comment replies, please wait: 'Získavanie odpovedí na komentáre, čakajte prosím'\n  Hide Comments: 'Skryť komentáre'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Pre toto video nie sú dostupné žiadne komentáre'\n  Load More Comments: 'Načítať viac komentárov'\n  There are no more comments for this video: Pre toto video nie sú žiadne ďalšie komentáre\n  Newest first: Najnovšie prvé\n  Top comments: Najlepšie komentáre\n  Pinned by: Pripnuté od\n  Show More Replies: Zobraziť viac odpovedí\n  Hearted: Obľúbené\n  Subscribed: Odoberané\n  Member: Člen\n  There are no comments available for this post: Pre tento príspevok nie sú dostupné žiadne komentáre\n  View {replyCount} replies from {channelName} and others: Zobraziť {replyCount} odpovedí od {channelName} a ostatných\n  View 1 reply from {channelName}: Zobraziť 1 odpoveď od {channelName}\n  Hide {replyCount} replies: Skryť 1 odpoveď | Skryť odpovede v počte {replyCount}\n  View {replyCount} replies: Zobraziť 1 odpoveď | Zobraziť {replyCount} odpovedí\nUp Next: 'Ďalšie'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Chyba lokálneho API (kliknite pre kopírovanie)'\nInvidious API Error (Click to copy): 'Chyba Invidious API (kliknite pre kopírovanie)'\nFalling back to Invidious API: 'Návrat k Invidious API'\nFalling back to Local API: 'Návrat k lokálnemu API'\nLoop is now disabled: 'Slučka je teraz vypnutá'\nLoop is now enabled: 'Slučka je teraz zapnutá'\nShuffle is now disabled: 'Zamiešanie je teraz vypnuté'\nShuffle is now enabled: 'Zamiešanie je teraz zapnuté'\nPlaying Next Video: 'Prehrávanie nasledujúceho videa'\nPlaying Previous Video: 'Prehrávanie predchádzajúceho videa'\nCanceled next video autoplay: 'Zrušené automatické prehrávanie ďalšieho videa'\n'The playlist has ended. Enable loop to continue playing': 'Playlist skončil.   Povolte slučku pre pokračovanie prehrávania'\n\nYes: 'Áno'\nNo: 'Nie'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Toto video nie je dostupné kvôli chýbajúcim formátom. Toto sa môže stať kvôli nedostupnosti krajiny.\nThe playlist has been reversed: Playlist bol obrátený\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Keď je zapnuté, FreeTube použije RSS namiesto predvolenej metódy na získanie vášho odoberaného kanála. RSS je rýchlejší a zabraňuje blokovaniu IP, ale neposkytuje určité informácie ako trvanie videa, stav naživo alebo príspevky\n    Fetch Automatically: Keď je zapnuté, FreeTube automaticky načíta váš odoberaný kanál pri spustení a keď je otvorené nové okno.\n  Player Settings:\n    Default Video Format: Nastavte formáty používané pri prehrávaní videa. Formáty DASH umožňujú prehrávanie vo vyššej kvalite. Staršie formáty sú obmedzené na maximálne rozlíšenie 360p, ale využívajú menšiu šírku pásma. Formáty zvuku sú iba audio streamy.\n    Proxy Videos Through Invidious: Pripojí sa k Invidious na poskytovanie videí namiesto priameho pripojenia k YouTube.\n    Scroll Playback Rate Over Video Player: Keď je kurzor nad videom, stlačte a podržte kláves Control (kláves Command na Macu) a posúvaním kolieska myši dopredu alebo dozadu ovládajte rýchlosť prehrávania. Stlačte a podržte kláves Control (kláves Command na Macu) a kliknite ľavým tlačidlom myši pre rýchly návrat k predvolenej rýchlosti prehrávania (1x, ak nebola zmenená v nastaveniach).\n    Skip by Scrolling Over Video Player: Použite koliesko myši na preskakovanie cez video v štýle MPV.\n  General Settings:\n    Region for Trending: Región trendov vám umožňuje zvoliť si krajinu pre trendové videá, ktoré chcete zobraziť.\n    Invidious Instance: Inštancia Invidious, ku ktorej sa FreeTube pripojí pre volania API.\n    Thumbnail Preference: Všetky náhľady vo FreeTube budú nahradené snímkou z videa, ktorá bude rozmazaná alebo skrytá namiesto východzieho náhľadu.\n    Fallback to Non-Preferred Backend on Failure: Keď má vaše preferované API problém, FreeTube sa automaticky pokúsi použiť vaše nepreferované API ako náhradnú metódu, ak je táto funkcia zapnutá.\n    Preferred API Backend: Vyberte backend, ktorý FreeTube používa na získavanie údajov. Lokálne API je vstavaný extraktor. API Invidious vyžaduje pripojenie k serveru Invidious.\n    External Link Handling: \"Vyberte predvolené správanie pri kliknutí na odkaz, ktorý nemožno otvoriť vo FreeTube.\\nV predvolenom nastavení FreeTube otvorí odkaz, na ktorý ste klikli, vo vašom predvolenom prehliadači.\\n\"\n    Open Deep Links In New Window: URL adresy odovzdané do FreeTube, napríklad presmerovaním rozšírení prehliadača alebo cez argumenty príkazového riadku, sa otvoria v novom okne.\n  External Player Settings:\n    DefaultCustomArgumentsTemplate: \"(Predvolené: '{defaultCustomArguments}')\"\n    External Player: Pri výbere externého prehrávača sa na náhľade zobrazí ikona na otvorenie videa (playlistu, ak je podporovaný) v externom prehrávači. Pozor, nastavenia Invidious nemajú vplyv na externé prehrávače.\n    Custom External Player Executable: Predvolene FreeTube predpokladá, že zvolený externý prehrávač je možné nájsť prostredníctvom premennej prostredia PATH. V prípade potreby je možné tu nastaviť vlastnú cestu.\n    Ignore Warnings: Zakážte upozornenia, keď aktuálny externý prehrávač nepodporuje aktuálnu akciu (napr. obrátenie playlistov atď.).\n    Custom External Player Arguments: Akékoľvek vlastné argumenty príkazového riadka, ktoré chcete odovzdať externému prehrávaču.\n    Ignore Default Arguments: Okrem URL videa neposielajte externému prehrávaču žiadne predvolené argumenty (napr. rýchlosť prehrávania, URL playlistu atď.). Vlastné argumenty budú naďalej odovzdávané.\n  Distraction Free Settings:\n    Hide Channels: Zadajte ID kanála, aby sa všetky videá, playlisty a samotný kanál nezobrazovali vo vyhľadávaní, trendoch, najobľúbenejších a odporúčaných položkách. Zadaný ID kanála musí byť úplne zhodný a rozlišujú sa veľké a malé písmená.\n    Hide Videos on Watch: Skryje pozerané videá z kariet Videá, Krátke a Naživo na stránkach Odber a Kanál. Toto neovplyvní kartu Domov na stránkach Kanál\n    Hide Videos, Playlists and Channels Containing Text: Zadajte slovo, fragment slova alebo frázu (necitlivé na veľkosť písmen) na skrytie všetkých videí, playlistov a kanálov, ktorých originálne názvy ho obsahujú v celom FreeTube, okrem kariet História, Vaše playlisty a videí vnútri playlistov.\n    Hide Subscriptions Live: Toto nastavenie je prepísané nastavením celej aplikácie \"{appWideSetting}\", v časti \"{subsection}\" sekcie \"{settingsSection}\"\n  SponsorBlock Settings:\n    UseDeArrowThumbnails: Nahradí náhľady videí náhľadmi z DeArrow.\n    UseDeArrowTitles: Nahradí názvy videí názvami z DeArrow, ktoré zadali jeho používatelia.\n  Experimental Settings:\n    Replace HTTP Cache: Zakáže diskovú cache HTTP Electron a povolí vlastnú cache obrázkov v pamäti. Vedie k zvýšenému použitiu RAM.\nProfile:\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Naozaj chcete odstrániť vybrané kanály?  Týmto sa kanál neodstráni z žiadneho iného profilu.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Toto je váš hlavný profil. Naozaj chcete vymazať vybrané kanály? Tie isté kanály budú vymazané v akomkoľvek profile, kde sa nachádzajú.\n  No channel(s) have been selected: Neboli vybrané žiadne kanály\n  Add Selected To Profile: Pridať vybrané do profilu\n  Delete Selected: Vymazať vybrané\n  Select None: Nevybrať nič\n  Select All: Vybrať všetko\n  '{number} selected': 'Vybrané: {number}'\n  Other Channels: Iné kanály\n  Subscription List: Zoznam odberov\n  '{profile} is now the active profile': '{profile} je teraz aktívny profil'\n  Your default profile has been changed to your primary profile: Váš predvolený profil bol zmenený na váš hlavný profil\n  Removed {profile} from your profiles: '{profile} odstránený z vašich profilov'\n  Your default profile has been set to {profile}: Váš predvolený profil bol nastavený na {profile}\n  Profile has been updated: Profil bol aktualizovaný\n  Profile has been created: Profil bol vytvorený\n  Your profile name cannot be empty: Názov vášho profilu nemôže byť prázdny\n  All subscriptions will also be deleted.: Budú tiež vymazané všetky odbery.\n  Are you sure you want to delete this profile?: Naozaj chcete vymazať tento profil?\n  Delete Profile: Vymazať profil\n  Make Default Profile: Nastaviť ako predvolený profil\n  Update Profile: Aktualizovať profil\n  Create Profile: Vytvoriť profil\n  Profile Preview: Náhľad profilu\n  Custom Color: Vlastná farba\n  Color Picker: Výber farby\n  Edit Profile: Upraviť profil\n  Create New Profile: Vytvoriť nový profil\n  Profile Manager: Správca profilov\n  All Channels: Všetky kanály\n  Profile Select: Výber profilu\n  Profile Filter: Filter profilov\n  Profile Settings: Profil\n  Open Profile Dropdown: Otvoriť rozbaľovacie menu profilu\n  Close Profile Dropdown: Zatvoriť rozbaľovacie menu profilu\n  Profile Name: Názov profilu\n  Create Profile Name: Vytvoriť názov profilu\n  Edit Profile Name: Upraviť názov profilu\n  Toggle Profile List: Prepnúť zoznam profilov\nA new blog is now available, {blogTitle}. Click to view more: 'Dostupný nový článok na blogu: {blogTitle}. Kliknite pre viac info'\nDownload From Site: Stiahnuť z webu\nVersion {versionNumber} is now available!  Click for more details: Verzia {versionNumber} je k dispozícii! Kliknite pre viac podrobností\nLocale Name: Slovenčina\nPlaying Next Video Interval: Prehrávanie ďalšieho videa okamžite. Kliknite pre zrušenie. | Prehrávanie ďalšieho videa o {nextVideoInterval} sekundu. Kliknite pre zrušenie. | Prehrávanie ďalšieho videa o {nextVideoInterval} sekúnd. Kliknite pre zrušenie.\nMore: Viac\nUnknown YouTube url type, cannot be opened in app: Neznámy typ adresy URL YouTube, nemôže byť otvorený v aplikácii\nOpen New Window: Otvoriť nové okno\nDefault Invidious instance has been set to {instance}: Predvolená inštancia Invidious bola nastavená na {instance}\nSearch Bar:\n  Clear Input: Vyčistiť zadané údaje\n  Remove: Odstrániť\nDefault Invidious instance has been cleared: Predvolená inštancia Invidious bola vymazaná\nExternal link opening has been disabled in the general settings: Otváranie externých odkazov bolo zakázané vo všeobecných nastaveniach\nAre you sure you want to open this link?: Naozaj chcete otvoriť tento odkaz?\nNew Window: Nové okno\nChannels:\n  Channels: Kanály\n  Title: Zoznam kanálov\n  Count: 'Nájdené kanály: {number}.'\n  Search bar placeholder: Vyhľadať kanály\n  Empty: Váš zoznam kanálov je momentálne prázdny.\n  Unsubscribe Prompt: Určite sa chcete odhlásiť z odberu \"{channelName}\"?\nPreferences: Predvoľby\nClose Banner: Zatvoriť banner\nSearch character limit: Hľadaný výraz presahuje povolený limit {searchCharacterLimit} znakov\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Titulky\n    Closed Captions: Skryté titulky\n    8K: 8K\n    360 Video: 360°\n    3D: 3D\n    VR180: VR180\n    New: Nové\nFeed:\n  Feed Last Updated: 'Kanál {feedName} naposledy aktualizovaný: {date}'\n  Refresh Feed: Obnoviť {subscriptionName}\nGo to page: Prejsť na {page}\nRight-click or hold to see history: Podržte alebo kliknite pravým tlačidlom pre zobrazenie histórie\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Prepnúť nástroje pre vývojárov\n  Zoom In: Priblížiť\n  Zoom Out: Oddialiť\n  Fullscreen: Prepnúť celú obrazovku\n  Focus Secondary Search: Zamerať na sekundárnu lištu vyhľadávania (ak je prítomná)\n  Focus Search: Zamerať na lištu vyhľadávania\n  Search in New Window: Vyhľadávať v novom okne\n  Skip to Previous Video: Preskočiť na predchádzajúce video v playliste\n  Volume Up: Zvýšiť hlasitosť\n  Decrease Video Speed: Znížiť rýchlosť videa na základe intervalu rýchlosti prehrávania videa\n  Increase Video Speed: Zvýšiť rýchlosť videa na základe intervalu rýchlosti prehrávania videa\n  New Window: Vytvoriť nové okno\n  Navigate to Settings: Prejsť na stránku Nastavenia\n  Navigate to History: Prejsť na stránku História\n  Refresh: Obnoviť zdroj s najnovším obsahom\n  Keyboard Shortcuts: Klávesové skratky\n  Sections:\n    Video:\n      Playback: 'Video: Prehrávanie'\n      General: Video: Všeobecné\n    App:\n      Situational: 'Aplikácia: Situačné'\n      General: 'Aplikácia: Všeobecné'\n  Show Keyboard Shortcuts: Zobraziť klávesové skratky\n  History Backward: Ísť späť o jednu stránku\n  History Forward: Ísť dopredu o jednu stránku\n  Skip to Next Video: Preskočiť na ďalšie video v playliste alebo ďalšie odporúčané video\n  End: Posunúť na koniec videa\n  Home: Posunúť na začiatok videa\n  Skip by Tenths: Preskočiť cez video percentom (3 preskočenia na 30% trvania)\n  Next Chapter: Ďalšia kapitola\n  Last Chapter: Posledná kapitola\n  Small Fast Forward: Rýchlo posunúť X sekúnd na základe intervalu rýchleho posunu a aktuálnej rýchlosti prehrávania videa\n  Small Rewind: Posunúť dozadu X sekúnd na základe intervalu posunu dozadu a aktuálnej rýchlosti prehrávania videa\n  Volume Down: Znížiť hlasitosť\n  Next Frame: Ďalšia snímka (pri pauze)\n  Last Frame: Predchádzajúca snímka (pri pauze)\n  Reset Zoom: Resetovať úroveň priblíženia / rozpätia používateľského rozhrania\n  Close Window: Zatvoriť okno\n  Minimize Window: Minimalizovať okno\n  Take Screenshot: Urobiť snímku obrazovky\n  Theatre Mode: Prepnúť režim kina\n  Full Window: Prepnúť celé okno\n  Mute: Prepnúť stlmenie\n  Large Fast Forward: Posunúť dopredu 10 sekúnd / Rýchlo posunúť video dopredu na základe aktuálnej rýchlosti prehrávania videa\n  Play: Prepnúť prehrávanie/pauzu\n  Large Rewind: Posunúť dozadu 10 sekúnd / Posunúť video dozadu na základe aktuálnej rýchlosti prehrávania videa\n  Picture in Picture: Prepnúť režim obraz v obraze\n  Stats: Zobraziť štatistiku videa\n  Captions: Prepnúť titulky ZAP/VYP\nKeys:\n  arrowdown: Šípka nadol\n  arrowleft: Šípka doľava\n  arrowright: Šípka doprava\n  arrowup: Šípka nahor\n  shift: Shift\n  enter: Enter\n  plus: Plus\n  ctrl: Ctrl\n  alt: Alt\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nAge Restricted:\n  This video is age restricted: Toto video je vekovo obmedzené\n  This channel is age restricted: Tento kanál je vekovo obmedzený\nshortcutLabelSeparator: ｜\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nCancel: Zrušiť\nYes, Open Link: Áno, otvoriť odkaz\nYes, Restart: Áno, reštartovať\nYes, Delete: Áno, vymazať\nOk: OK\nMoments Ago: pred chvíľou\nHashtag:\n  This hashtag does not currently have any videos: Tento hashtag momentálne nemá žiadne videá\n  Hashtag: Hashtag\nTrimmed input must be at least N characters long: Orezaný vstup musí byť aspoň 1 znak dlhý | Orezaný vstup musí byť aspoň {length} znakov dlhý\nChannel Unhidden: '{channel} odstránený z filtra kanálov'\nChannel Hidden: '{channel} pridaný do filtra kanálov'\nScreenshot Error: Snímka obrazovky sa nepodarila. {error}\nScreenshot Success: Snímka obrazovky uložená\nAutoplay Interruption Timer: Automatické prehrávanie zrušené kvôli {autoplayInterruptionIntervalHours} hodinám nečinnosti\nDescription:\n  Collapse Description: Zobraziť menej\n  Expand Description: '...viac'\nChapters:\n  Key Moments: Kľúčové momenty\n  Chapters: Kapitoly\nClipboard:\n  Cannot access clipboard without a secure connection: Prístup k schránke nie je možný bez zabezpečeného pripojenia\n  Copy failed: Kopírovanie do schránky zlyhalo\nTag already exists: Označenie \"{tagName}\" už existuje\nCompact side navigation: Kompaktná bočná navigácia\nExpand side navigation: Rozbaliť bočnú navigáciu\n"
  },
  {
    "path": "static/locales/sl.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'slovenščina'\n\n# Webkit Menu Bar\nFile: 'Datoteka'\nQuit: 'Zapri'\nEdit: 'Uredi'\nUndo: 'Razveljavi'\nRedo: 'Uveljavi'\nCut: 'Izreži'\nCopy: 'Kopiraj'\nPaste: 'Prilepi'\nDelete: 'Izbriši'\nSelect all: 'Označi vse'\nToggle Developer Tools: 'Preklopi razvijalska orodja'\nActual size: 'Dejanska velikost'\nZoom in: 'Povečaj'\nZoom out: 'Zmanjšaj'\nToggle fullscreen: 'Preklopi celoten zaslon'\nWindow: 'Okno'\nMinimize: 'Minimiraj'\nClose: 'Zapri'\nBack: 'Nazaj'\nForward: 'Naprej'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videoposnetki'\n  Sort By: 'Razvrstitev'\n\n  Live: V živo\nVersion {versionNumber} is now available!  Click for more details: 'Na voljo je različica {versionNumber}!·  Za več podrobnosti kliknite tukaj'\nDownload From Site: 'Prenesi iz spletne strani'\nA new blog is now available, {blogTitle}. Click to view more: 'Na voljo je nov članek, {blogTitle}. Kliknite tukaj, če ga želite prebrati'\n\n# Search Bar\nSearch / Go to URL: 'Išči/pojdi na URL naslov'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Iskalni filtri'\n  Sort By:\n    Most Relevant: 'Ustreznost'\n    Rating: 'Ocena'\n    Upload Date: 'Datum nastanka'\n    View Count: 'Število ogledov'\n  Time:\n    Time: 'Čas'\n    Any Time: 'Vsak čas'\n    Last Hour: 'Zadnja ura'\n    Today: 'Danes'\n    This Week: 'Ta teden'\n    This Month: 'Ta mesec'\n    This Year: 'To leto'\n  Type:\n    Type: 'Vrsta'\n    All Types: 'Vse vrste'\n    Videos: 'Videoposnetki'\n    Channels: 'Kanali'\n    #& Playlists\n    Movies: Filmi\n  Duration:\n    Duration: 'Trajanje'\n    All Durations: 'Vsa trajanja'\n    Short (< 4 minutes): 'Kratko (<4 minute)'\n    Long (> 20 minutes): 'Dolgo (>20 minut)'\n  # On Search Page\n    Medium (4 - 20 minutes): Srednje (4–20 minut)\n  Search Results: 'Rezultati'\n  Fetching results. Please wait: 'Pridobivamo rezultate. Prosimo, počakajte'\n  Fetch more results: 'Pridobi več rezultatov'\n# Sidebar\n  There are no more results for this search: Nič več rezultatov\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Naročnine'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Vaš seznam naročnin je trenutno prazen. Začnite dodajati naročnine, da jih boste videli tukaj.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Ta profil ima veliko količino naročnin.· Da bi se izognili omejitvi hitrosti, bo uporabljen RSS\n  Load More Videos: Naloži več videoposnetkov\n  Error Channels: Kanali z napakami\n  Disabled Automatic Fetching: Onemogočili ste samodejno pridobivanje seznama naročnin. Osvežite seznam naročnin, da jih vidite tukaj.\n  Empty Channels: Vaši naročeni kanali trenutno nimajo nobenega novega videoposnetka.\nTrending:\n  Trending: 'Priljubljeno'\n  Gaming: Igričarstvo\n  Sports: Šport\nMost Popular: 'Najbolj popularno'\nPlaylists: 'Seznami predvajanja'\nUser Playlists:\n  Your Playlists: 'Vaši seznami predvajanja'\n  Search bar placeholder: Iskanje v seznamu predvajanja\n  Empty Search Message: Na tem seznamu predvajanja ni videoposnetkov, ki bi ustrezali vašemu iskanju\nHistory:\n  # On History Page\n  History: 'Zgodovina'\n  Watch History: 'Zgodovina predvajanj'\n  Your history list is currently empty.: 'Seznam vaše zgodovine je trenutno prazen.'\n  Search bar placeholder: Išči v zgodovini\n  Empty Search Message: V vaši zgodovini ni videoposnetkov, ki bi ustrezali vašemu iskanju\nSettings:\n  # On Settings Page\n  Settings: 'Nastavitve'\n  General Settings:\n    General Settings: 'Splošne nastavitve'\n    Check for Updates: 'Preveri posodobitve'\n    Check for Latest Blog Posts: 'Preveri najnovejše članke na blogu'\n    Fallback to Non-Preferred Backend on Failure: 'Ob napaki začasno uporabi sekundarni zaledni sistem'\n    Enable Search Suggestions: 'Vklopi iskalne predloge'\n    Default Landing Page: 'Prevzeta vstopna stran'\n    Locale Preference: 'Izbira lokacije'\n    Preferred API Backend:\n      Preferred API Backend: 'Primarni zaledni sistem aplikacijskega programskega vmesnika (APV)'\n      Local API: 'Lokalni APV'\n      Invidious API: 'Invidious APV'\n    Video View Type:\n      Video View Type: 'Tip razvrščanja videoposnetkov'\n      Grid: 'Mreža'\n      List: 'Seznam'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Izbira sličic'\n      Default: 'Prevzeto'\n      Beginning: 'Začetek'\n      Middle: 'Sredina'\n      End: 'Konec'\n    Region for Trending: 'Regija za priljubljene videoposnetke'\n        #! List countries\n    View all Invidious instance information: Prikaži vse podatke o Invidious domeni\n    System Default: Sistemsko privzeto\n    External Link Handling:\n      External Link Handling: Ravnanje z zunanjimi povezavami\n      Open Link: Odpri povezavo\n      Ask Before Opening Link: Vprašaj pred odpiranjem povezave\n      No Action: Brez dejanja\n    Current Invidious Instance: Trenutna Invidious instanca\n    No default instance has been set: Nastavljena ni nobena privzeta instanca\n    Clear Default Instance: Izbriši privzeto instanco\n    Current instance will be randomized on startup: Trenutna instanca bo ob zagonu naključno izbrana\n    Set Current Instance as Default: Nastavi trenutno instanco kot privzeto\n    The currently set default instance is {instance}: Trenutno nastavljena privzeta instanca je {instance}\n  Theme Settings:\n    Theme Settings: 'Nastavitve tem'\n    Match Top Bar with Main Color: 'Uskladi zgornji trak z glavno barvo'\n    Base Theme:\n      Base Theme: 'Glavna tema'\n      Black: 'Črna'\n      Dark: 'Temna'\n      Light: 'Svetla'\n      Dracula: 'Drakula'\n      Catppuccin Mocha: Catppuccin Mocha\n      System Default: Sistemsko privzeto\n    Main Color Theme:\n      Main Color Theme: 'Glavna barvna tema'\n      Red: 'Rdeča'\n      Pink: 'Roza'\n      Purple: 'Vijolična'\n      Deep Purple: 'Škrlatna'\n      Indigo: 'Indigo'\n      Blue: 'Modra'\n      Light Blue: 'Svetlo modra'\n      Cyan: 'Zelenomodra'\n      Teal: 'Modrozelena'\n      Green: 'Zelena'\n      Light Green: 'Svetlo zelena'\n      Lime: 'Limeta'\n      Yellow: 'Rumena'\n      Amber: 'Jantarna'\n      Orange: 'Oranžna'\n      Deep Orange: 'Temno oranžna'\n      Dracula Cyan: 'Drakula Zelenomodra'\n      Dracula Green: 'Drakula Green'\n      Dracula Orange: 'Drakula Oranžna'\n      Dracula Pink: 'Drakula Roza'\n      Dracula Purple: 'Drakula Vijolična'\n      Dracula Red: 'Drakula Rdeča'\n      Dracula Yellow: 'Drakula Rumena'\n      Catppuccin Mocha Red: Catppuccin Mocha rdeča\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Maroon: Catppuccin Mocha kostanjeva\n      Catppuccin Mocha Pink: Catppuccin Mocha roza\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Yellow: Catppuccin Mocha rumena\n      Catppuccin Mocha Green: Catppuccin Mocha zelena\n      Catppuccin Mocha Teal: Catppuccin Mocha zelenomodra\n      Catppuccin Mocha Blue: Catppuccin Mocha modra\n      Catppuccin Mocha Sky: Catppuccin Mocha nebo\n      Catppuccin Mocha Peach: Catppuccin Mocha breskev\n      Catppuccin Mocha Lavender: Catppuccin Mocha sivka\n      Catppuccin Mocha Sapphire: Catppuccin Mocha safir\n    Secondary Color Theme: 'Sekundarna barvna tema'\n        #* Main Color Theme\n    UI Scale: Merilo uporabniškega vmesnika\n    Disable Smooth Scrolling: Izklopi gladko drsenje\n    Expand Side Bar by Default: Prevzeto razširi stransko vrstico\n    Hide FreeTube Header Logo: Skrij logotip v glavi FreeTube\n    Hide Side Bar Labels: Skrij oznake na stranski vrstici\n  Player Settings:\n    Player Settings: 'Nastavitve predvajalnika'\n    Play Next Video: 'Predvajaj naslednji videoposnetek'\n    Turn on Subtitles by Default: 'Samodejno vklopi podnapise'\n    Autoplay Videos: 'Samodejno predvajaj naslednji videoposnetek'\n    Proxy Videos Through Invidious: 'Uporabi Invidious kot namestnik'\n    Autoplay Playlists: 'Samodejno predvajaj sezname predvajanja'\n    Enable Theatre Mode by Default: 'Samodejno vklopi gledališki način'\n    Default Volume: 'Prevzeta glasnost'\n    Default Playback Rate: 'Prevzeta hitrost predvajanja'\n    Default Video Format:\n      Default Video Format: 'Prevzeta oblika videoposnetka'\n      Dash Formats: 'DASH oblike'\n      Legacy Formats: 'Zapuščinske oblike'\n      Audio Formats: 'Audio oblike'\n    Default Quality:\n      Default Quality: 'Prevzeta kvaliteta'\n      Auto: 'Samodejno'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      File Name Tooltip: Spodaj lahko uporabite spremenljivke. %Y leto 4 števke. %M mesec 2 števki. %D dan 2 števki. %H ura 2 števki. %N minuta 2 števki. %S sekunda 2 števki. %T milisekunda 3 števke. %s video sekunda. %t Video milisekunda 3 števke. %i ID videa.\n      Enable: Omogoči posnetek zaslona\n      Format Label: Format posnetka zaslona\n      Error:\n        Empty File Name: Prazno ime datoteke\n        Forbidden Characters: Prepovedani znaki\n      Quality Label: Kakovost posnetka zaslona\n      Folder Label: Mapa posnetkov zaslona\n      Folder Button: Izberi mapo\n      File Name Label: Vzorec imena datoteke\n    Enter Fullscreen on Display Rotate: Pri vrtenju zaslona vstopite v celozaslonski način\n    Next Video Interval: Interval do naslednjega videa\n    Display Play Button In Video Player: Prikaz gumba za predvajanje v video predvajalniku\n    Fast-Forward / Rewind Interval: Interval za hitro previjanje naprej/nazaj\n    Video Playback Rate Interval: Interval hitrosti predvajanja videa\n  Privacy Settings:\n    Privacy Settings: 'Nastavitve zasebnosti'\n    Remember History: 'Zapomni si zgodovino'\n    Save Watched Progress: 'Zapomni si napredek gledanja'\n    Clear Search Cache: 'Izbriši iskalni predpomnilnik'\n    Are you sure you want to clear out your search cache?: 'Ste prepričani, da želite izbrisati vaš iskalni predpomnilnik?'\n    Search cache has been cleared: 'Iskalni predpomnilnik je bil izbrisan'\n    Remove Watch History: 'Izbriši zgodovino gledanj'\n    Are you sure you want to remove your entire watch history?: 'Ste prepričani, da želite izbrisati vašo celotno zgodovino gledanj?'\n    Watch history has been cleared: 'Zgodovina gledanj je bila izbrisana'\n    Remove All Subscriptions / Profiles: 'Izbriši vse naročnine/profile'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Ste prepričani, da želite izbrisati vse naročnine in profile?·  Te odločitve ni mogoče razveljaviti.'\n    Save Watched Videos With Last Viewed Playlist: Shrani gledane videoposnetke z nazadnje ogledanim seznamom predvajanja\n  Subscription Settings:\n    Subscription Settings: 'Nastavitve naročnin'\n    Fetch Feeds from RSS: 'Pridobi vire iz RSS'\n  Data Settings:\n    Data Settings: 'Podatkovne nastavitve'\n    Select Export Type: 'Izberi izvozno obliko'\n    Import Subscriptions: 'Uvozi naročnine'\n    Export Subscriptions: 'Izvozi naročnine'\n    Export FreeTube: 'Izvozi za FreeTube'\n    Export YouTube: 'Izvozi za YouTube'\n    Export NewPipe: 'Izvozi za NewPipe'\n    Import History: 'Uvozi zgodovino'\n    Export History: 'Izvozi zgodovino'\n    Profile object has insufficient data, skipping item: 'Profilni predmet ima pomankljive podatke in je bil preskočen'\n    All subscriptions and profiles have been successfully imported: 'Vse naročnine in profili so bili uspešno uvoženi'\n    All subscriptions have been successfully imported: 'Vse naročnine so bile uspešno uvožene'\n    Invalid subscriptions file: 'Neveljavna datoteka z naročninami'\n    Invalid history file: 'Neveljavna datoteka z zgodovino'\n    Subscriptions have been successfully exported: 'Naročnine so bile uspešno izvožene'\n    History object has insufficient data, skipping item: 'Zgodovinski objekt ima pomankljive podatke in je bil preskočen'\n    All watched history has been successfully imported: 'Vsa zgodovina gledanj je bila uspešno uvožena'\n    All watched history has been successfully exported: 'Vsa zgodovina gledanj je bila uspešno izvožena'\n    Unable to read file: 'Datoteke ni možno prebrati'\n    Unable to write file: 'Datoteke ni možno prebrati'\n    Unknown data key: 'Neznan podatkovni ključ'\n    How do I import my subscriptions?: 'Kako lahko uvozim moje naročnine?'\n    Manage Subscriptions: Upravljaj z naročninami\n\n  Distraction Free Settings:\n    Hide Live Chat: Skrij klepet v živo\n    Hide Popular Videos: Skrij popularne videoposnetke\n    Hide Trending Videos: Skrij trendne videoposnetke\n    Hide Recommended Videos: Skrij priporočene videoposnetke\n    Hide Comment Likes: Skrij všečke komentarjev\n    Hide Video Likes And Dislikes: Skrij všečke in nevšečke videoposnetkov\n    Hide Channel Subscribers: Skrij število naročnikov\n    Hide Video Views: Skrij število ogledov\n    Distraction Free Settings: Brezmotenjske nastavitve\n    Hide Active Subscriptions: Skrij aktivne naročnine\n    Hide Playlists: Skrij sezname predvajanja\n    Hide Comments: Skrij komentarje\n    Hide Chapters: Skrij poglavja\n    Hide Channels Placeholder: Ime ali ID kanala\n    Hide Live Streams: Skrij prenose v živo\n    Hide Channels: Skrij videoposnetke iz kanalov\n    Hide Video Description: Skrij opis videoposnetka\n    Hide Upcoming Premieres: Skrij prihajajoče premiere\n    Hide Videos on Watch: 'Skrij gledane videoposnetke'\n  The app needs to restart for changes to take effect. Restart and apply change?: Program se mora ponovno zagnati, preden bodo spremembe uveljavljene. Ga želite ponovno zagnati zdaj?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Prišlo je do napake pri pridobivanju informacij o omrežju. Ali je vaš namestnik pravilno nastavljen?\n    City: Mesto\n    Region: Regija\n    Country: Država\n    Ip: IP naslov\n    Your Info: Vaši podatki\n    Test Proxy: Preizkusi namestnik\n    Clicking on Test Proxy will send a request to: Ko kliknete na Preizkusi namestnik, bo poizvedba poslana na\n    Proxy Port Number: Številka vrat namestnika\n    Proxy Settings: Nastavitve namestnika\n    Proxy Host: Gostitelj namestnika\n    Proxy Protocol: Protokol namestnika\n    Enable Tor / Proxy: Vklopi Tor/namestnik\n  External Player Settings:\n    External Player: Zunanji predvajalnik\n    External Player Settings: Nastavitve zunanjega predvajalnika\n    Players:\n      None:\n        Name: nobenega\n    Ignore Unsupported Action Warnings: Prezri opozorila o nepodprtih dejanjih\nAbout:\n  #On About page\n  About: 'O programu'\n  #& About\n  Donate: Doniraj\n  these people and projects: teh ljudi in projektov\n  Credits: Zahvale\n  Translate: Prevedi\n  room rules: sobna pravila\n  Chat on Matrix: Klepetajte na Matrixu\n  Mastodon: Mastodon\n  Email: E-pošta\n  Blog: Blog\n  Website: Spletna stran\n  Please check for duplicates before posting: Prosimo, da pred pošiljanjem preverite, da ni dvojnikov\n  GitHub issues: GitHub težave\n  Report a problem: Prijavi napako\n  FAQ: Pogosto zastavljena vprašanja\n  FreeTube Wiki: FreeTube wiki\n  Help: Pomoč\n  GitHub releases: Github izdaje\n  Downloads / Changelog: Prenosi in dnevnik sprememb\n  Source code: Izvirna koda\n  Beta: Beta\nProfile:\n  Profile Select: 'Izberi profil'\n  All Channels: 'Vsi kanali'\n  Profile Manager: 'Upravitelj profilov'\n  Create New Profile: 'Ustvari nov profil'\n  Edit Profile: 'Uredi profil'\n  Color Picker: 'Izbiralnik barv'\n  Custom Color: 'Barva po meri'\n  Profile Preview: 'Predogled profila'\n  Create Profile: 'Ustvari profil'\n  Update Profile: 'Posodobi profil'\n  Make Default Profile: 'Nastavi kot prevzeti profil'\n  Delete Profile: 'Izbriši profil'\n  Are you sure you want to delete this profile?: 'Ste prepričani, da želite izbrisati ta profil?'\n  All subscriptions will also be deleted.: 'Izbrisane bodo tudi vse naročnine.'\n  Your profile name cannot be empty: 'Ime profila ne sme biti prazno'\n  Profile has been created: 'Profil je bil ustvarjen'\n  Profile has been updated: 'Profil je bil posodobljen'\n  Your default profile has been set to {profile}: 'Vaš prevzeti profil je bil nastavljen na {profile}'\n  Removed {profile} from your profiles: 'Profil {profile} je bil izbrisan'\n  Your default profile has been changed to your primary profile: 'Vaš prevzeti profil je bil nastavljen na vaš primarni profil'\n  '{profile} is now the active profile': 'Aktivni profil je zdaj {profile}'\n  Subscription List: 'Seznam naročnin'\n  Other Channels: 'Drugi kanali'\n  '{number} selected': '{number} je označen'\n  Select All: 'Označi vse'\n  Select None: 'Ne označi ničesar'\n  Delete Selected: 'Izbriši označeno'\n  Add Selected To Profile: 'Dodaj označeno v profil'\n  No channel(s) have been selected: 'Označili niste nobenih kanalov'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'To je vaš primarni profil.·  Ste prepričani, da želite izbrisati označene kanale?·  Kanali bodo izbrisani v vseh profilih, kjer se nahajajo.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Ali ste prepričani, da želite izbrisati označene kanale?  Kanali ne bodo izbrisani iz drugih profilov.'\n#On Channel Page\n  Profile Filter: Filter profilov\n  Profile Settings: Nastavitve profila\nChannel:\n  Subscribe: 'Naroči se'\n  Unsubscribe: 'Prekini naročnino'\n  Channel has been removed from your subscriptions: 'Kanal je bil odstranjen iz vaših naročnin'\n  Removed subscription from {count} other channel(s): 'Naročnina je bila prekinjena v {count} kanalih'\n  Added channel to your subscriptions: 'Kanal je bil dodan v vaše naročnine'\n  Search Channel: 'Preišči kanal'\n  Your search results have returned 0 results: 'Najdenih ni bilo nobenih rezultatov'\n  Videos:\n    Videos: 'Videoposnetki'\n    This channel does not currently have any videos: 'Ta kanal trenutno nima nobenih videoposnetkov'\n    Sort Types:\n      Newest: 'Najnovejši'\n      Oldest: 'Najstarejši'\n      Most Popular: 'Najbolj popularni'\n  Playlists:\n    Playlists: 'Seznami predvajanja'\n    This channel does not currently have any playlists: 'Ta kanal trenutno nima nobenih seznamov predvajanja'\n    Sort Types:\n      Last Video Added: 'Zadnji videoposnetek dodan'\n      Newest: 'Najnovejši'\n      Oldest: 'Najstarejši'\n  About:\n    About: 'O kanalu'\n    Channel Description: 'Opis kanala'\n    Featured Channels: 'Izpostavljeni kanali'\nVideo:\n  Mark As Watched: 'Označi kot ogledano'\n  Remove From History: 'Izbriši iz zgodovine'\n  Video has been marked as watched: 'Videoposnetek je bil označen kot ogledan'\n  Video has been removed from your history: 'Videoposnetek je bil izbrisan iz zgodovine'\n  Open in YouTube: 'Odpri v YouTube'\n  Copy YouTube Link: 'Kopiraj YouTube povezavo'\n  Open YouTube Embedded Player: 'Odpri vgrajeni YouTube predvajalnik'\n  Copy YouTube Embedded Player Link: 'Kopiraj povezavo vgrajenega YouTube predvajalnika'\n  Open in Invidious: 'Odpri v Invidious'\n  Copy Invidious Link: 'Kopiraj Invidious povezavo'\n  Views: 'Ogledi'\n  Loop Playlist: 'Ponovno predvajaj seznam predvajanja'\n  Shuffle Playlist: 'Mešaj seznam predvajanja'\n  Reverse Playlist: 'Obrni seznam predvajanja'\n  Previous: 'Nazaj'\n  Next: 'Naprej'\n  Watched: 'Ogledano'\n  Autoplay: 'Samodejno predvajanje'\n  Starting soon, please refresh the page to check again: 'Predvajanje se začenja. Prosimo, osvežite stran, če želite poskusiti znova'\n  # As in a Live Video\n  Live: 'V živo'\n  Live Now: 'Trenutno v živo'\n  Live Chat: 'Klepet v živo'\n  Enable Live Chat: 'Vklopi klepet v živo'\n  Live Chat is currently not supported in this build.: 'Klepet v živo v tej različici trenutno ni podprt.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Pogovor v živo je vklopljen.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Klepet v živo trenutno ni podprt v Invidious APV.  Potrebna je neposredna povezava z YouTubom.'\n  Published:\n    In less than a minute: Manj kot minuti\n  Published on: 'Objavljeno dne'\n#& Videos\n  Started streaming on: Pretok začet dne\n  Streamed on: Pretočeno dne\n  Copy Invidious Channel Link: Kopiraj povezavo Invidious kanala\n  Open Channel in Invidious: Odpri ta kanal v Invidiousu\n  Copy YouTube Channel Link: Kopiraj povezavo YouTube kanala\n  Open Channel in YouTube: Odpri ta kanal v YouTubu\n  Video has been removed from your saved list: Videoposnetek je bil odstranjen iz seznama\n  Video has been saved: Videoposnetek je bil shranjen\n  Save Video: Shrani videoposnetek\n#& Playlists\nPlaylist:\n  #& About\n  View Full Playlist: 'Pokaži celoten seznam predvajanja'\n  Last Updated On: 'Nazadnje posodobljeno dne'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Seznam predvajanja\nChange Format:\n  Change Media Formats: 'Spremeni vrsto videoposnetka'\n  Use Dash Formats: 'Uporabi DASH oblike'\n  Use Legacy Formats: 'Uporabi zapuščinske oblike'\n  Use Audio Formats: 'Uporabi avdio oblike'\n  Dash formats are not available for this video: 'DASH oblike za ta videoposnetek niso na voljo'\n  Audio formats are not available for this video: 'Avdio oblike za ta videoposnetek niso na voljo'\nShare:\n  Share Video: 'Deli videoposnetek'\n  Share Playlist: 'Deli seznam predvajanja'\n  Include Timestamp: 'Vključi časovno oznako'\n  Copy Link: 'Kopiraj povezavo'\n  Open Link: 'Odpri povezavo'\n  Copy Embed: 'Kopiraj vložek'\n  Open Embed: 'Odpri vložek'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL kopiran'\n  Invidious Embed URL copied to clipboard: 'Invidious vložek URL kopiran'\n  YouTube URL copied to clipboard: 'YouTube URL kopiran'\n  YouTube Embed URL copied to clipboard: 'YouTube vložek URL kopiran'\n  YouTube Channel URL copied to clipboard: URL YouTube kanala je bil kopiran\n  Invidious Channel URL copied to clipboard: URL Invidious kanala je bil kopiran\n  Share Channel: Deli kanal\nMini Player: 'Mini predvajalnik'\nComments:\n  Comments: 'Komentarji'\n  Click to View Comments: 'Kliknite za prikaz komentarjev'\n  Getting comment replies, please wait: 'Pridobivanje odgovorov na komentar. Prosimo, počakajte'\n  There are no more comments for this video: 'Za ta posnetek ni več komentarjev'\n  Hide Comments: 'Skrij komentarje'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Ta videoposnetek nima nobenih komentarjev'\n  Load More Comments: 'Naloži več komentarjev'\n  Newest first: Najnovejši komentarji\n  Top comments: Najbolje ocenjeni komentarji\n  Show More Replies: Pokaži več odgovorov\n  Member: Član\nUp Next: 'Naslednje na sporedu'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Napaka lokalnega APV (kliknite za kopiranje)'\nInvidious API Error (Click to copy): 'Napaka Invidious APV (kliknite za kopiranje)'\nFalling back to Invidious API: 'Začasno bo uporabljen Invidious APV'\nFalling back to Local API: 'Začasno bo uporabljen lokalni APV'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Videoposnetek zaradi mankajočih oblik ni dostopen. To se lahko zgodi, ko v vaši državi ni na razpolago.'\nLoop is now disabled: 'Ponovno predvajanje je izklopljeno'\nLoop is now enabled: 'Ponovno predvajanje je vklopljeno'\nShuffle is now disabled: 'Mešanje je izklopljeno'\nShuffle is now enabled: 'Mešanje je vklopljeno'\nThe playlist has been reversed: 'Sezam predvajanja je bil obrnjen'\nPlaying Next Video: 'Predvaja se naslednji videoposnetek'\nPlaying Previous Video: 'Predvaja se prejšnji videoposnetek'\nCanceled next video autoplay: 'Samodejno predvajanje preklicano'\n'The playlist has ended. Enable loop to continue playing': \"Seznama predvajanja je konec.  Vklopite ponovno predvajanje, če želite nadaljevati\"\n\nYes: 'Da'\nNo: 'Ne'\nMore: Več\nTooltips:\n  General Settings:\n    Preferred API Backend: Izberite zaledje, ki ga FreeTube uporablja za pridobivanje podatkov. Lokalni APV je vgrajeni . Invidious APV za delovanje potrebuje Invidious strežnik.\n  Subscription Settings:\n    Fetch Feeds from RSS: Ko je omogočeno, bo FreeTube namesto privzete metode uporabljal RSS za pridobivanje vašega vira naročnin. RSS je hitrejši in preprečuje blokiranje IP-ja, vendar ne zagotavlja določenih informacij, kot je trajanje videa ali status stanja v živo\n  Player Settings:\n    Skip by Scrolling Over Video Player: Uporabite kolesce za pomikanje po videoposnetku v slogu MPV.\nNew Window: Novo okno\nChannels:\n  Channels: Kanali\n  Title: Seznam kanalov\n  Search bar placeholder: Išči kanale\n  Empty: Vaš seznam kanalov je trenutno prazen.\n  Count: Najdenih {number} kanalov.\n  Unsubscribe Prompt: Ali ste prepričani, da želite prekiniti naročnino od \"{channelName}\"?\nAre you sure you want to open this link?: Ali ste prepričani, da želite odpreti to povezavo?\nPreferences: Nastavitve\nSearch Bar:\n  Clear Input: Počisti vnos\nOpen New Window: Odpri novo okno\nChapters:\n  Chapters: Poglavja\nSearch Listing:\n  Label:\n    8K: 8K\n    4K: 4K\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Preklopi razvijalska orodja\n  Zoom In: Povečaj\n  Zoom Out: Zmanjšaj\n  Fullscreen: Preklopi celoten zaslon\n"
  },
  {
    "path": "static/locales/sm.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Gagana Samoa'\n\n# Webkit Menu Bar\nFile: 'Faila'\nNew Window: 'Fa''amalama fou'\nPreferences: 'Faaitalia'\nQuit: 'Ulufafo'\nEdit: 'Sui'\nUndo: ''\nRedo: ''\nCut: ''\nCopy: ''\nPaste: ''\nDelete: ''\nSelect all: ''\nToggle Developer Tools: ''\nActual size: ''\nZoom in: ''\nZoom out: ''\nToggle fullscreen: ''\nWindow: ''\nMinimize: ''\nClose: ''\nBack: ''\nForward: ''\nOpen New Window: ''\n\nVersion {versionNumber} is now available!  Click for more details: ''\nDownload From Site: ''\nA new blog is now available, {blogTitle}. Click to view more: ''\nAre you sure you want to open this link?: ''\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: ''\n  Shorts: ''\n  Live: ''\n  Posts: ''\n  Counts:\n    Video Count: ''\n    Channel Count: ''\n    Subscriber Count: ''\n    View Count: ''\n    Watching Count: ''\n\n# Search Bar\nSearch / Go to URL: ''\nSearch Bar:\n  Clear Input: ''\n  # In Filter Button\nSearch Filters:\n  Search Filters: ''\n  Sort By:\n    Most Relevant: ''\n    Rating: ''\n    Upload Date: ''\n    View Count: ''\n  Time:\n    Time: ''\n    Any Time: ''\n    Last Hour: ''\n    Today: ''\n    This Week: ''\n    This Month: ''\n    This Year: ''\n  Type:\n    Type: ''\n    All Types: ''\n    Videos: ''\n    Channels: ''\n    Movies: ''\n    #& Playlists\n  Duration:\n    Duration: ''\n    All Durations: ''\n    Short (< 4 minutes): ''\n    Medium (4 - 20 minutes): ''\n    Long (> 20 minutes): ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Trending Tabs: ''\nMost Popular: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\nSettings:\n  # On Settings Page\n  Settings: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Turn on Subtitles by Default: ''\n    Autoplay Videos: ''\n    Proxy Videos Through Invidious: ''\n    Autoplay Playlists: ''\n    Enable Theatre Mode by Default: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n    Ignore Default Arguments: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Save Watched Progress: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search Cache: ''\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Placeholder: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: ''\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    Reveal Answers: ''\n    Hide Answers: ''\nVideo:\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\nUp Next: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nYes: ''\nNo: ''\nOk: ''\n"
  },
  {
    "path": "static/locales/sq.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Shqip'\n\n# Webkit Menu Bar\nFile: 'File'\nNew Window: 'Dritare e re'\nPreferences: 'Preferencat'\nQuit: 'Dil'\nEdit: 'Modifiko'\nUndo: 'Ribë'\nRedo: 'Përsërit'\nCut: 'Prit'\nCopy: 'Kopjo'\nPaste: 'Ngjit'\nDelete: 'Fshi'\nSelect all: 'Zgjidh gjithçka'\nToggle Developer Tools: 'Aktivo/çaktivizo veglat për zhvilluesit'\nActual size: 'Madhësi reale'\nZoom in: 'Zmadho'\nZoom out: 'Zvogëlo'\nToggle fullscreen: 'Aktivo/çaktivizo ekranin e plotë'\nWindow: 'Dritare'\nMinimize: 'Minimizo'\nClose: 'Mbyll'\nBack: 'Mbrapa'\nForward: 'Përpara'\nRight-click or hold to see history: 'Kliko me butonin e djathtë ose mbaj shtypur për të parë historinë'\nOpen New Window: 'Hap dritare të re'\nGo to page: 'Shko tek {page}'\nClose Banner: 'Mbyll bannerin'\n\nVersion {versionNumber} is now available!  Click for more details: 'Versioni {versionNumber} është i disponueshëm! Kliko për më shumë detaje'\nDownload From Site: 'Shkarko nga faqja'\nA new blog is now available, {blogTitle}. Click to view more: 'Një blog i ri është i disponueshëm, {blogTitle}. Kliko për të shikuar më shumë'\nAre you sure you want to open this link?: 'A je i sigurt që dëshiron ta hapësh këtë link?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video'\n  Shorts: 'Video të shkurtra'\n  Live: 'Në kohë reale'\n  Posts: 'Postimet'\n  Sort By: 'Rendit sipas'\n  Counts:\n    Video Count: '1 video | {count} video'\n    Channel Count: '1 kanal | {count} kanale'\n    Subscriber Count: '1 abonent | {count} abonentë'\n    View Count: '1 shikim | {count} shikime'\n    Like Count: '1 pëlqim | {count} pëlqime'\n    Comment Count: '1 koment | {count} komente'\n    Watching Count: '1 spektator | {count} spektatorë'\n\n# Search Bar\nSearch / Go to URL: 'Kërko ose hap URL YouTube'\nSearch Bar:\n  Clear Input: 'Fshi kërkimin'\n  Remove: 'Hiq'\nSearch character limit: 'Kërkimi është mbi limitin prej {searchCharacterLimit} karakteresh'\nSearch Listing:\n  Label:\n    4K: '4K'\n    8K: '8K'\n    VR180: 'VR180'\n    360 Video: '360°'\n    Subtitles: 'Titrat'\n    New: 'E re'\n    3D: '3D'\n    # Aria labels\n    Closed Captions: 'Titra për personat me probleme dëgjimi'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Filtra të kërkimit'\n  Sort By:\n    Most Relevant: 'Më të përshtatshmet'\n    Rating: 'Vlerësimi'\n    Upload Date: 'Data e ngarkimit'\n    View Count: 'Shikimet'\n  Time:\n    Time: 'Koha'\n    Any Time: 'Përherë'\n    Last Hour: 'Ora e fundit'\n    Today: 'Sot'\n    This Week: 'Këtë javë'\n    This Month: 'Këtë muaj'\n    This Year: 'Këtë vit'\n  Type:\n    Type: 'Tipi'\n    All Types: 'Çdo tip'\n    Videos: 'Video'\n    Channels: 'Kanale'\n    Movies: 'Filma'\n    #& Playlists\n  Duration:\n    Duration: 'Gjatësia'\n    All Durations: 'Të gjitha gjatësitë'\n    Short (< 4 minutes): 'E shkurtër (< 4 minuta)'\n    Medium (4 - 20 minutes): 'E mesme (4 - 20 minuta)'\n    Long (> 20 minutes): 'E gjatë (> 20 minuta)'\n  Features:\n    Features: 'Karakteristikat'\n    HD: 'HD'\n    Subtitles: 'Titrat'\n    Creative Commons: 'Creative Commons'\n    3D: '3D'\n    Live: 'Në kohë reale'\n    4K: '4K'\n    360 Video: 'Video 360'\n    Location: 'Vendndodhja'\n    HDR: 'HDR'\n    VR180: 'VR180'\n  # On Search Page\n  Search Results: 'Rezultatet e kërkimit'\n  Fetching results. Please wait: 'Duke gjetur rezultatet. Ju lutemi të prisni'\n  Fetch more results: 'Shfaq më shumë rezultate'\n  There are no more results for this search: 'Nuk ka rezultate të tjera për këtë kërkim'\n  Clear Filters: 'Fshi filtrat'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonimet'\n  # channels that were likely deleted\n  Error Channels: 'Kanale me probleme'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Ky profil ka një numër të madh abonimesh. Do të përdoret RSS për të shmangur limitimet'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Lista e abonimeve është bosh. Nëse dëshiron të importosh abonimet e tua mund të shkosh tek Opsionet e të dhënave dhe të zgjedhësh të importosh abonimet ose mund të kërkosh për një kanal dhe të abonohesh.'\n  Disabled Automatic Fetching: 'Ke çaktivizuar rekuperimin automatik të abonimeve. Rifresko abonimet që ti shohësh këtu.'\n  Empty Channels: 'Kanalet me të cilët je abonuar nuk kanë ndonjë video.'\n  Empty Posts: 'Kanalet me të cilët je abonuar nuk kanë ndonjë postim.'\n  Load More Videos: 'Kariko më shumë video'\n  Load More Posts: 'Kariko më shumë postime'\n  Subscriptions Tabs: 'Skedat e abonimeve'\n  All Subscription Tabs Hidden: 'Të gjitha skedat e abonimeve janë fshehur. Për të parë të dhëna këtu, shfaq disa skeda në sektorin \"{subsection}\" në \"{settingsSection}\".'\nMore: 'Më shumë'\nChannels:\n  Channels: 'Kanale'\n  Title: 'Lista e kanaleve'\n  Search bar placeholder: 'Kërko kanale'\n  Count: '{number} kanal(e) u gjet(ën).'\n  Empty: 'Lista e kanaleve të tua është boshe.'\n  Unsubscribe Prompt: 'A je i sigurt se do të heqësh abonimin nga \"{channelName}\"?'\nTrending:\n  Trending: 'Në trend'\n  Gaming: 'Lojëra'\n  Trending Tabs: 'Skeda në trend'\nMost Popular: 'Më populloret'\nFeed:\n  Feed Last Updated: 'Feed-i {feedName} u rifreskua për here të fundit në: {date}'\n  Refresh Feed: 'Rifresko {subscriptionName}'\nPlaylists: 'Playlist'\nUser Playlists:\n  Your Playlists: 'Playlistat e tu'\n  You have no playlists. Click on the create new playlist button to create a new one.: 'Nuk ke asnjë playlist. Kiliko butonin e krijimit të playlistit të ri për të krijuar një të re.'\n  Empty Search Message: 'Nuk ka video në këtë playlist që i përputhen kërkimit tënd'\n  Search bar placeholder: 'Kërko për playlist'\n  Playlists with Matching Videos: 'Playlist me video të njëjta'\n\n  This playlist currently has no videos.: 'Ky playlist nuk ka video.'\n\n  Create New Playlist: 'Krijo playlist të ri'\n\n  Add to Playlist: 'Shto në playlist'\n  Add to Favorites: 'Shto në {playlistName}'\n  Remove from Favorites: 'Hiq nga {playlistName}'\n\n  Move Video Up: 'Lëviz videon më lart'\n  Move Video Down: 'Lëviz videon më poshtë'\n  Remove from Playlist: 'Hiq nga playlist'\n\n  Playlist Name: 'Emri i playlistit'\n  Playlist Description: 'Përshkrimi i playlistit'\n\n  Save Changes: 'Ruaj ndryshimet'\n  Cancel: 'Anullo'\n  Edit Playlist Info: 'Ndrysho të dhënat e playlistit'\n  Copy Playlist: 'Kopjo playlistin'\n  Remove Duplicate Videos: 'Hiq videot e dyfishta'\n  Remove Watched Videos: 'Hiq videot e shikuara'\n  Enable Quick Bookmark With This Playlist: 'Aktivizo shënimin e shpejtë me këtë playlist'\n  Quick Bookmark Enabled: 'Shënimi i shpejtë u aktivizua'\n  Export Playlist: 'Eksporto këtë playlist'\n  The playlist has been successfully exported: 'Playlisti u eksportua me sukses'\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: 'A je i sigurtë që do të heqësh 1 video të dyfishtë nga ky playlist? Ky veprim nuk mund të kthehet pas. | A je i sigurtë që do të heqësh {playlistItemCount} video të dyfishta nga ky playlist? Ky veprim nuk mund të kthehet pas.'\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 'A je i sigurtë që do të heqësh 1 video të shikuar nga ky playlist? Ky veprim nuk mund të kthehet pas. | A je i sigurtë që do të heqësh {playlistItemCount} video të shikuara nga ky playlist? Ky veprim nuk mund të kthehet pas.'\n  Delete Playlist: 'Fshi playlistin'\n  Cannot delete the quick bookmark target playlist.: 'Nuk mund të fshihet playlisti me destinacion tek shënimet e shpejta.'\n  Are you sure you want to delete this playlist? This cannot be undone: 'A je i sigurtë se do të fshish këtë playlist? Ky veprim nuk mund të kthehet pas.'\n\n  TotalTimePlaylist: \"Koha totale: {duration}\"\n\n  Sort By:\n    NameAscending: 'A-Z'\n    NameDescending: 'Z-A'\n\n    LatestCreatedFirst: 'Krijuar më së shpejti'\n    EarliestCreatedFirst: 'Krijuar më vonë'\n\n    LatestUpdatedFirst: 'Ndryshuar më së shpejti'\n    EarliestUpdatedFirst: 'Ndryshuar më vonë'\n\n    LatestPlayedFirst: 'Luajtur më së shpejti'\n    EarliestPlayedFirst: 'Luajtur më vonë'\n  SinglePlaylistView:\n    Search for Videos: 'Kërko për video'\n\n    Toast:\n      This video cannot be moved up.: 'Kjo video nuk mund te lëvizet më lart.'\n      This video cannot be moved down.: 'Kjo video nuk mund të lëvizet më poshtë.'\n      Video has been removed: 'Video është hequr'\n      Video has been removed. Click here to undo.: 'Video është hequr. Kliko këtu për ta rikthyer.'\n      There was a problem with removing this video: 'Kishte një problem me heqjen e kësaj video'\n\n      This playlist is already being used for quick bookmark.: 'Ky playlist është duke u perdorur tashmë si një shenjë e shpejtë.'\n      This playlist is now used for quick bookmark: 'Ky playlist po përdoret tani si shenjë e shpejtë'\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: 'Ky playlist po përdoret tani si shenjë e shpejte në vend të {oldPlaylistName}. Kliko këtu për të anulluar këtë veprim'\n      Reverted to use {oldPlaylistName} for quick bookmark: 'Shenja e shpejtë u rikthye tek {oldPlaylistName}'\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 'Disa video në playlist nuk janë karikuar akoma. Kliko këtu për të kopjuar gjithsesi.'\n      Playlist name cannot be empty. Please input a name.: 'Emri i playlistit nuk mund të jetë bosh. Të lutem shto një emër.'\n      Playlist has been updated.: 'Playlisti u ndryshua.'\n      There was an issue with updating this playlist.: 'Kishte probleme me ndryshimin e këtij playlisti.'\n      \"{videoCount} video(s) have been removed\": \"1 video u hoq | {videoCount} video u hoqën\"\n      There were no videos to remove.: 'Nuk ka video për të hequr.'\n      This playlist is protected and cannot be removed.: 'Ky playlist është i ruajtur dhe nuk mund të hiqet.'\n      Playlist {playlistName} has been deleted.: 'Playlisti {playlistName} u hoq.'\n\n      This playlist does not exist: 'Ky playlist nuk ekziston'\n\n      This playlist has a video with a duration error: 'Ky playlist përmban të paktën një video që nuk ka një kohëzgjatje, do të renditet sikur kohëzgjatja ështe zero.'\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: 'Zgjidh një playlist ku të shtosh videon tënde | Zgjidh një playlist ku të shtosh {videoCount} videot e tua'\n    N playlists selected: '{playlistCount} zgjedhur'\n    Search in Playlists: 'Kërko në playlist'\n    Allow Adding Duplicate Video(s): 'Lejo shtimin e videove të dyfishta'\n    Save: 'Ruaj'\n\n    Added {count} Times: 'Tashmë shtuar | Shtuar {count} here'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} video do të shtohen'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": 'Tashmë janë shtuar {videoCount}/{totalVideoCount} video'\n\n    Toast:\n      You haven't selected any playlist yet.: 'Nuk ke zgjedhur akoma asnjë playlist.'\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: 'Emri i playlist'\n    Create: 'Krijo'\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: 'Tashmë ekziston një playlist me atë emer. Zgjidh një emër tjeter.'\n      Playlist {playlistName} has been successfully created.: 'Playlisti {playlistName} u krijua me sukses.'\n      There was an issue with creating the playlist.: 'Kishte një problem me krijimin e playlistit.'\nHistory:\n  # On History Page\n  History: 'Historia'\n  Watch History: 'Historia e shikimit'\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n      Everforest Dark Hard: ''\n      Everforest Dark Medium: ''\n      Everforest Dark Low: ''\n      Everforest Light Hard: ''\n      Everforest Light Medium: ''\n      Everforest Light Low: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n      Everforest Dark Red: ''\n      Everforest Dark Orange: ''\n      Everforest Dark Yellow: ''\n      Everforest Dark Green: ''\n      Everforest Dark Aqua: ''\n      Everforest Dark Blue: ''\n      Everforest Dark Purple: ''\n      Everforest Light Red: ''\n      Everforest Light Orange: ''\n      Everforest Light Yellow: ''\n      Everforest Light Green: ''\n      Everforest Light Aqua: ''\n      Everforest Light Blue: ''\n      Everforest Light Purple: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Autoplay Playlists: ''\n    Autoplay Videos: ''\n    Turn on Subtitles by Default: ''\n    Proxy Videos Through Invidious: ''\n    Default Viewing Mode:\n      Theater: ''\n      Default Viewing Mode: ''\n      Full Screen: ''\n      Picture in Picture: ''\n      External Player: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Remember Search History: ''\n    Save Watched Progress: ''\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: ''\n        Semi-auto: ''\n        Never: ''\n      Tooltip: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search History and Cache: ''\n    Are you sure you want to clear out your search history and cache?: ''\n    Search history and cache have been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Hide Videos on Watch: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Posts: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Channel Courses: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Hide Subscriptions Posts: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Export Playlists For Older FreeTube Versions:\n      Label: ''\n      # |- = Keep newlines, No newline at end\n      Tooltip: |\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: ''\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  Courses:\n    Courses: ''\n    This channel does not currently have any courses: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\n    Viewing Posts Only Supported By Invidious: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Watched Progress: ''\n  Watched Progress Saved: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: 'Prapa'\n  Next: 'Tjetër'\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Autoplay is off: ''\n    Autoplay is on: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nshortcutLabelSeparator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: ''\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: ''\n  Reset Zoom: ''\n  Zoom In: ''\n  Zoom Out: ''\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n  Home: ''\n  End: ''\n"
  },
  {
    "path": "static/locales/sr.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Српски'\n\n# Webkit Menu Bar\nFile: 'Фајл'\nQuit: 'Напусти'\nEdit: 'Измени'\nUndo: 'Поништи'\nRedo: 'Обнови'\nCut: 'Исеци'\nCopy: 'Копирај'\nPaste: 'Налепи'\nDelete: 'Избриши'\nSelect all: 'Изабери све'\nToggle Developer Tools: 'Укључи алатке за програмере'\nActual size: 'Стварна величина'\nZoom in: 'Увећај'\nZoom out: 'Умањи'\nToggle fullscreen: 'Укључи цео екран'\nWindow: 'Прозор'\nMinimize: 'Минимизирај'\nClose: 'Затвори'\nBack: 'Назад'\nForward: 'Напред'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Видео снимци'\n\n  Counts:\n    Video Count: 1 видео снимак | {count} видео снимака\n    Subscriber Count: 1 пратилац | {count} пратилаца\n    View Count: 1 преглед | {count} прегледа\n    Watching Count: 1 гледање | {count} гледања\n    Channel Count: 1 канал | {count} канала\n    Comment Count: 1 коментар | {count} коментара\n    Like Count: 1 свиђање | {count} свиђања\n  Live: Уживо\n  Posts: Постови\n  Shorts: Кратки\n  Sort By: Сортирање по\nVersion {versionNumber} is now available!  Click for more details: 'Верзија {versionNumber} је сада достуна!  Кликните за више детаља'\nDownload From Site: 'Преузми са сајта'\nA new blog is now available, {blogTitle}. Click to view more: 'Нови блог је сада доступан, {blogTitle}. Кликните да бисте видели више'\n\n# Search Bar\nSearch / Go to URL: 'Претрага / Иди на URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Филтери претраге'\n  Sort By:\n    Most Relevant: 'Најрелевантније'\n    Rating: 'Оцена'\n    Upload Date: 'Датум отпремања'\n    View Count: 'Број прегледа'\n  Time:\n    Time: 'Време'\n    Any Time: 'Било које време'\n    Last Hour: 'Последњи сат'\n    Today: 'Данас'\n    This Week: 'Ове недеље'\n    This Month: 'Овог месеца'\n    This Year: 'Ове године'\n  Type:\n    Type: 'Врста'\n    All Types: 'Све врсте'\n    Videos: 'Видео снимци'\n    Channels: 'Канали'\n    #& Playlists\n    Movies: Филмови\n  Duration:\n    Duration: 'Трајање'\n    All Durations: 'Сва трајања'\n    Short (< 4 minutes): 'Кратко (< 4 минута)'\n    Long (> 20 minutes): 'Дуго (> 20 минута)'\n  # On Search Page\n    Medium (4 - 20 minutes): Средње (4 - 20 минута)\n  Search Results: 'Резултати претраге'\n  Fetching results. Please wait: 'Прикупљање резултата. Сачекајте'\n  Fetch more results: 'Прикупити више резултата'\n  There are no more results for this search: 'Нема више резултата за ову претрагу'\n# Sidebar\n  Features:\n    Creative Commons: Creative Commons\n    3D: 3D\n    HDR: HDR\n    VR180: VR180\n    Features: Функције\n    HD: HD\n    Subtitles: Титлови\n    Location: Локација\n    Live: Уживо\n    4K: 4K\n    360 Video: 360 видео\n  Clear Filters: Очисти филтере\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Праћења'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Овај профил има велики број праћења.  Присиљавање RSS-а да се избегне ограничавање брзине'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Ваша листа праћења је тренутно празна. Ако желите да увезете своја праћења, можете отићи у Подешавања података и изабрати Увоз праћења или можете претражити канал и запратити га.'\n  Load More Videos: 'Учитај више видео снимака'\n  Load More Posts: Учитај више објава\n  Empty Channels: Канали које пратите тренутно немају ниједан видео снимак.\n  Subscriptions Tabs: Картице праћења\n  Empty Posts: Канали које пратите тренутно немају ниједну објаву.\n  All Subscription Tabs Hidden: Све картице праћења су скривене. Да бисте видели садржај овде, откријте неке картице у одељку „{subsection}“ у „{settingsSection}“.\n  Disabled Automatic Fetching: Онемогућили сте аутоматско прикупљање праћења. Освежите праћења да бисте их видели овде.\n  Error Channels: Канали са грешкама\nMore: 'Више'\nTrending:\n  Trending: 'У тренду'\n  Gaming: Видео игре\n  Trending Tabs: Картице у тренду\nMost Popular: 'Најпопуларније'\nPlaylists: 'Плејлисте'\nUser Playlists:\n  Your Playlists: 'Ваше плејлисте'\n  Empty Search Message: На овој плејлисти нема видео снимака који одговарају вашој претрази\n  Search bar placeholder: Претрага плејлиста\n  AddVideoPrompt:\n    Search in Playlists: Претрага у плејлистама\n    Save: Сачувај\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: Још увек нисте изабрали ниједну плејлисту.\n    Select a playlist to add your N videos to: Изаберите плејлисту на коју желите да додате видео снимак | Изаберите плејлисту на коју желите да додате {videoCount} видео снимака\n    N playlists selected: 'Изабрано: {playlistCount}'\n    Added {count} Times: Већ додато | Додато {count} пута\n    Allow Adding Duplicate Video(s): Дозволи додавање дупликата видео снимака\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} видео снимака ће бити додато'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} видео снимака је већ додато'\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: Није било видео снимака за уклањање.\n      Video has been removed: Видео снимак је уклоњен\n      Playlist has been updated.: Плејлиста је ажурирана.\n      There was an issue with updating this playlist.: Дошло је до грешке при ажурирању ове плејлисте.\n      This video cannot be moved up.: Овај видео снимак се не може померити нагоре.\n      This playlist is protected and cannot be removed.: Ова плејлиста је заштићена и не може се уклонити.\n      Playlist {playlistName} has been deleted.: Плејлиста „{playlistName}“ је избрисана.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Неки видео снимци на плејлисти још увек нису учитани. Кликните овде да бисте ипак копирали.\n      This playlist does not exist: Ова плејлиста не постоји\n      Playlist name cannot be empty. Please input a name.: Назив плејлисте не може бити празан. Унесите назив.\n      There was a problem with removing this video: Дошло је до грешке при уклањању овог видео снимка\n      \"{videoCount} video(s) have been removed\": 1 видео снимак је уклоњен | {videoCount} видео снимака је уклоњено\n      This video cannot be moved down.: Овај видео снимак се не може померити надоле.\n      This playlist is now used for quick bookmark: Ова плејлиста се сада користи за брзо обележавање\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Ова плејлиста се сада користи за брзо обележавање, уместо „{oldPlaylistName}“. Кликните овде да поништите\n      Reverted to use {oldPlaylistName} for quick bookmark: Враћено на коришћење „{oldPlaylistName}“ за брзо обележавање\n      This playlist is already being used for quick bookmark.: Ова плејлиста се већ користи за брзо обележавање.\n      This playlist has a video with a duration error: Ова плејлиста садржи најмање један видео снимак који нема трајање, биће сортиран као да је његово трајање нула.\n      Video has been removed. Click here to undo.: Видео снимак је уклоњен. Додирните овде да поништите.\n    Search for Videos: Претрага видео снимака\n  Are you sure you want to delete this playlist? This cannot be undone: Желите ли заиста да избришете ову плејлисту? Ово се не може поништити.\n  Sort By:\n    LatestPlayedFirst: Недавно пуштано\n    EarliestCreatedFirst: Најраније направљено\n    LatestCreatedFirst: Недавно направљено\n    EarliestUpdatedFirst: Најраније ажурирано\n    NameDescending: Z-A\n    EarliestPlayedFirst: Најраније пуштано\n    LatestUpdatedFirst: Недавно ажурирано\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: Немате плејлисте. Кликните на дугме „Направи нову плејлисту“ да бисте направили нову.\n  Remove from Playlist: Уклони са плејлисте\n  Save Changes: Сачувај измене\n  CreatePlaylistPrompt:\n    Create: Направи\n    Toast:\n      There was an issue with creating the playlist.: Дошло је до грешке при прављењу плејлисте.\n      Playlist {playlistName} has been successfully created.: Плејлиста „{playlistName}“ је успешно направљена.\n      There is already a playlist with this name. Please pick a different name.: Већ постоји плејлиста с овим називом. Молимо, изаберите други назив.\n    New Playlist Name: Нови назив плејлисте\n  This playlist currently has no videos.: Ова плејлиста тренутно нема ниједан видео снимак.\n  Add to Playlist: Додај на плејлисту\n  Move Video Down: Помери видео снимак надоле\n  Playlist Name: Назив плејлисте\n  Remove Watched Videos: Уклони одгледане видео снимке\n  Move Video Up: Помери видео снимак нагоре\n  Cancel: Откажи\n  Delete Playlist: Избриши плејлисту\n  Create New Playlist: Направи нову плејлисту\n  Edit Playlist Info: Измени информације о плејлисти\n  Copy Playlist: Копирај плејлисту\n  Playlist Description: Опис плејлисте\n  Enable Quick Bookmark With This Playlist: Омогући брзо обележавање помоћу ове плејлисте\n  Add to Favorites: Додај на плејлисту „{playlistName}“\n  Remove from Favorites: Уклони са плејлисте „{playlistName}“\n  Playlists with Matching Videos: Плејлисте с подударајућим видео снимцима\n  Cannot delete the quick bookmark target playlist.: Није могуће избрисати циљну плејлисту за брзо обележавање.\n  Quick Bookmark Enabled: Брзо обележавање омогућено\n  Remove Duplicate Videos: Уклони дуплиране видео снимке\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Желите ли заиста да уклоните 1 дуплирани видео снимак с ове плејлисте? Ово не може бити опозвано. | Желите ли заиста да уклоните {playlistItemCount} дуплираних видео снимака с ове плејлисте? Ово не може бити опозвано.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Желите ли заиста да уклоните 1 одгледани видео с ове плејлисте? Ово не може бити опозвано. | Желите ли заиста да уклоните {playlistItemCount} одледаних видео снимака с ове плејлисте? Ово не може бити опозвано.\n  Export Playlist: Извези ову плејлисту\n  The playlist has been successfully exported: Плејлиста је успешно извезена\n  TotalTimePlaylist: 'Укупно време: {duration}'\nHistory:\n  # On History Page\n  History: 'Историја'\n  Watch History: 'Историја гледања'\n  Your history list is currently empty.: 'Ваша историја је тренутно празна.'\n  Search bar placeholder: Претрага у историји\n  Empty Search Message: У вашој историји нема видео снимака који одговарају вашој претрази\n  Case Sensitive Search: Претрага осетљива на велика и мала слова\n  DateOldestHistory: Најраније гледано прво\n  DateNewestHistory: Најкасније гледано прво\nSettings:\n  # On Settings Page\n  Settings: 'Подешавања'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Апликација се мора рестартовати да би се примениле промене. Рестартовати и применити промене?'\n  General Settings:\n    General Settings: 'Опште'\n    Check for Updates: 'Провера ажурирања'\n    Check for Latest Blog Posts: 'Провера најновијих објава на блогу'\n    Fallback to Non-Preferred Backend on Failure: 'Повратак на непреферирани бек-енд у случају неуспеха'\n    Enable Search Suggestions: 'Омогући предлоге за претрагу'\n    Default Landing Page: 'Подразумевана почетна страница'\n    Locale Preference: 'Локална преференција'\n    Preferred API Backend:\n      Preferred API Backend: 'Преферирани API бек-енд'\n      Local API: 'Локални API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Врста приказа видео снимка'\n      Grid: 'Мрежа'\n      List: 'Листа'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Преференција сличице'\n      Default: 'Подразумевано'\n      Beginning: 'Почетак'\n      Middle: 'Средина'\n      End: 'Крај'\n      Hidden: Скривено\n      Blur: Замагљено\n    View all Invidious instance information: 'Погледај све информације о Invidious инстанци'\n    Region for Trending: 'Регион за „У тренду“'\n        #! List countries\n    External Link Handling:\n      Open Link: Отвори линк\n      External Link Handling: Руковање спољним линковима\n      No Action: Нема радње\n      Ask Before Opening Link: Питај пре отварања линка\n    No default instance has been set: Није подешена ниједна подразумевана инстанца\n    System Default: Системски подразумевано\n    Set Current Instance as Default: Подеси тренутну инстанцу као подразумевану\n    Current instance will be randomized on startup: Тренутна инстанца ће бити насумично изабрана при покретању\n    Clear Default Instance: Очисти подразумеване инстанце\n    The currently set default instance is {instance}: Тренутно подешена подразумевана инстанца је {instance}\n    Current Invidious Instance: Тренутна Invidious инстанца\n    Auto Load Next Page:\n      Label: Аутоматски учитај следећу страницу\n      Tooltip: Аутоматско учитавање додатних страница и коментара.\n    Open Deep Links In New Window: Отворите URL адресе прослеђене FreeTube-у у новом прозору\n    Minimize to system tray: Минимизирај у системску траку\n  Theme Settings:\n    Theme Settings: 'Тема'\n    Match Top Bar with Main Color: 'Усклади горњу траку са главном бојом'\n    Expand Side Bar by Default: 'Подразумевано прошири бочну траку'\n    Disable Smooth Scrolling: 'Онемогући глатко прелажење'\n    UI Scale: 'Скала корисничког интерфејса'\n    Base Theme:\n      Base Theme: 'Основна тема'\n      Black: 'Црна'\n      Dark: 'Тамна'\n      Light: 'Светла'\n      Dracula: 'Дракула'\n      Pastel Pink: Пастелно розе\n      Hot Pink: Врућа розе\n      Catppuccin Mocha: Catppuccin Mocha\n      System Default: Системски подразумевана\n      Nordic: Нордичка\n      Solarized Dark: Соларизована тамна\n      Solarized Light: Соларизована светла\n      Gruvbox Dark: Gruvbox тамна\n      Gruvbox Light: Gruvbox светла\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: Everforest тврдо-тамна\n      Everforest Light Hard: Everforest тврдо-светла\n      Everforest Light Low: Everforest ниско-светла\n      Everforest Dark Low: Everforest ниско-тамна\n      Everforest Light Medium: Everforest средње-светла\n      Everforest Dark Medium: Everforest средње-тамна\n    Main Color Theme:\n      Main Color Theme: 'Главна тема боја'\n      Red: 'Црвена'\n      Pink: 'Розе'\n      Purple: 'Љубичаста'\n      Deep Purple: 'Тамнољубичаста'\n      Indigo: 'Индиго'\n      Blue: 'Плава'\n      Light Blue: 'Светлоплава'\n      Cyan: 'Цијан'\n      Teal: 'Тиркизна'\n      Green: 'Зелена'\n      Light Green: 'Светлозелена'\n      Lime: 'Лимета'\n      Yellow: 'Жута'\n      Amber: 'Амбер'\n      Orange: 'Наранџаста'\n      Deep Orange: 'Тамнонаранџаста'\n      Dracula Cyan: 'Дракула цијан'\n      Dracula Green: 'Дракула зелена'\n      Dracula Orange: 'Дракула наранџаста'\n      Dracula Pink: 'Дракула розе'\n      Dracula Purple: 'Дракула љубичаста'\n      Dracula Red: 'Дракула црвена'\n      Dracula Yellow: 'Дракула жута'\n      Catppuccin Mocha Red: Catppuccin Mocha црвена\n      Catppuccin Mocha Maroon: Catppuccin Mocha тамноцрвена\n      Catppuccin Mocha Sky: Catppuccin Mocha небеска\n      Catppuccin Mocha Sapphire: Catppuccin Mocha сафирна\n      Catppuccin Mocha Teal: Catppuccin Mocha тиркизна\n      Catppuccin Mocha Yellow: Catppuccin Mocha жута\n      Catppuccin Mocha Rosewater: Catppuccin Mocha ружина водица\n      Catppuccin Mocha Peach: Catppuccin Mocha бресква\n      Catppuccin Mocha Flamingo: Catppuccin Mocha фламингос\n      Catppuccin Mocha Mauve: Catppuccin Mocha бледољубичаста\n      Catppuccin Mocha Pink: Catppuccin Mocha розе\n      Catppuccin Mocha Lavender: Catppuccin Mocha лаванда\n      Catppuccin Mocha Blue: Catppuccin Mocha плава\n      Catppuccin Mocha Green: Catppuccin Mocha зелена\n      Solarized Yellow: Соларизована жута\n      Solarized Orange: Соларизована наранџаста\n      Solarized Red: Соларизована црвена\n      Solarized Cyan: Соларизована цијан\n      Solarized Green: Соларизована зелена\n      Solarized Magenta: Соларизована магента\n      Solarized Blue: Соларизована плава\n      Solarized Violet: Соларизована љубичаста\n      Gruvbox Dark Green: Gruvbox тамнозелена\n      Gruvbox Dark Purple: Gruvbox тамнољубичаста\n      Gruvbox Dark Yellow: Gruvbox тамножута\n      Gruvbox Dark Blue: Gruvbox тамноплава\n      Gruvbox Dark Aqua: Gruvbox тамноаква\n      Gruvbox Dark Orange: Gruvbox тамнонаранџаста\n      Gruvbox Light Red: Gruvbox светлоцрвена\n      Gruvbox Light Blue: Gruvbox светлоплава\n      Gruvbox Light Purple: Gruvbox светлољубичаста\n      Gruvbox Light Orange: Gruvbox светлонаранџаста\n      Catppuccin Frappe Rosewater: Catppuccin Frappe ружина водица\n      Catppuccin Frappe Flamingo: Catppuccin Frappe фламингос\n      Catppuccin Frappe Mauve: Catppuccin Frappe бледољубичаста\n      Catppuccin Frappe Red: Catppuccin Frappe црвена\n      Catppuccin Frappe Maroon: Catppuccin Frappe тамноцрвена\n      Catppuccin Frappe Yellow: Catppuccin Frappe жута\n      Catppuccin Frappe Green: Catppuccin Frappe зелена\n      Catppuccin Frappe Sky: Catppuccin Frappe небеска\n      Catppuccin Frappe Sapphire: Catppuccin Frappe сафирна\n      Catppuccin Frappe Blue: Catppuccin Frappe плава\n      Catppuccin Frappe Peach: Catppuccin Frappe бресква\n      Catppuccin Frappe Lavender: Catppuccin Frappe лаванда\n      Catppuccin Frappe Pink: Catppuccin Frappe розе\n      Catppuccin Frappe Teal: Catppuccin Frappe тиркизна\n      Everforest Dark Orange: Everforest тамнонаранџаста\n      Everforest Dark Red: Everforest тамноцрвена\n      Everforest Dark Yellow: Everforest тамножута\n      Everforest Dark Green: Everforest тамнозелена\n      Everforest Dark Blue: Everforest тамноплава\n      Everforest Dark Aqua: Everforest тамноаква\n      Everforest Dark Purple: Everforest тамнољубичаста\n      Everforest Light Orange: Everforest светлонаранџаста\n      Everforest Light Yellow: Everforest светложута\n      Everforest Light Green: Everforest светлозелена\n      Everforest Light Red: Everforest светлоцрвена\n      Everforest Light Aqua: Everforest светлоаква\n      Everforest Light Blue: Everforest светлоплава\n      Everforest Light Purple: Everforest светлољубичаста\n    Secondary Color Theme: 'Секундарна тема боје'\n        #* Main Color Theme\n    Hide FreeTube Header Logo: Сакриј FreeTube логотип у заглављу\n    Hide Side Bar Labels: Сакриј ознаке бочне траке\n  Player Settings:\n    Player Settings: 'Плејер'\n    Play Next Video: 'Аутоматски пусти препоручене видео снимке'\n    Turn on Subtitles by Default: 'Подразумевано омогући титлове'\n    Autoplay Videos: 'Аутоматски пусти видео снимке'\n    Proxy Videos Through Invidious: 'Прокси видео снимци преко Invidious-а'\n    Autoplay Playlists: 'Аутоматски пусти видео снимке с плејлисте'\n    Enable Theatre Mode by Default: 'Подразумевано омогући биоскопски режим'\n    Default Volume: 'Подразумевана јачина звука'\n    Default Playback Rate: 'Подразумевана брзина репродукције'\n    Default Video Format:\n      Default Video Format: 'Подразумевани формат видео снимка'\n      Dash Formats: 'DASH формати'\n      Legacy Formats: 'Застарели формати'\n      Audio Formats: 'Аудио формати'\n    Default Quality:\n      Default Quality: 'Подразумевани квалитет'\n      Auto: 'Аутоматски'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Screenshot:\n      Folder Label: Фолдер за снимке екрана\n      Error:\n        Empty File Name: Празан назив фајла\n        Forbidden Characters: Забрањени знакови\n      Folder Button: Избор фолдера\n      Format Label: Формат снимка екрана\n      Enable: Омогући снимак екрана\n      Ask Path: Питај за фолдер за чување\n      Quality Label: Квалитет снимка екрана\n      File Name Tooltip: Можете да користите променљиве испод. %Y Година 4 цифре. %M Месец 2 цифре. %D Дан 2 цифре. %H Сат 2 цифре. %N Минут 2 цифре. %S Секунда 2 цифре. %T Милисекунда 3 цифре. %s Секунда видео снимка. %t Милисекунда видео снимка 3 цифре. %i ID видео снимка.\n      File Name Label: Образац назива фајла\n    Scroll Volume Over Video Player: Превуци за јачину звука преко плејера видео снимка\n    Skip by Scrolling Over Video Player: Прескочи превлачењем преко плејера видео снимка\n    Scroll Playback Rate Over Video Player: Превуци за брзину репродукције преко плејера видео снимка\n    Fast-Forward / Rewind Interval: Интервал брзог премотавања унапред/уназад\n    Video Playback Rate Interval: Интервал брзине репродукције видео снимка\n    Max Video Playback Rate: Максимална брзина репродукције видео снимка\n    Enter Fullscreen on Display Rotate: Уђи у цео екран при окретању екрана\n    Next Video Interval: Тајмер за одбројавање аутоплеја\n    Display Play Button In Video Player: Прикажи дугме за пуштање у плејеру видео снимка\n    Autoplay Interruption Timer: Тајмер за прекид аутоплеја\n    Default Viewing Mode:\n      Theater: Биоскоп\n      Default Viewing Mode: Подразумевани режим гледања\n      Full Screen: Цео екран\n      External Player: Спољни плејер ({externalPlayerName})\n      Picture in Picture: Слика у слици\n  Privacy Settings:\n    Privacy Settings: 'Приватност'\n    Remember History: 'Запамти историју гледања'\n    Save Watched Progress: 'Сачувај напредак одгледаног'\n    Clear Search Cache: 'Очисти кеш претраге'\n    Are you sure you want to clear out your search cache?: 'Желите ли заиста да очистите кеш претраге?'\n    Search cache has been cleared: 'Кеш претраге је очишћен'\n    Remove Watch History: 'Очисти историју гледања'\n    Are you sure you want to remove your entire watch history?: 'Желите ли заиста да очистите целу историју гледања?'\n    Watch history has been cleared: 'Историја гледања је очишћена'\n    Remove All Subscriptions / Profiles: 'Уклони сва праћења/профиле'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Желите ли заиста да уклоните сва праћења и профиле?   Ово се не може поништити.'\n    Save Watched Videos With Last Viewed Playlist: Сачувај одгледане видео снимке са последње гледане плејлисте\n    All playlists have been removed: Све плејлисте су уклоњене\n    Remove All Playlists: Уклони све плејлисте\n    Are you sure you want to remove all your playlists?: Желите ли заиста да уклоните све своје плејлисте?\n    Remember Search History: Запамти историју претраге\n    Search history and cache have been cleared: Историја претраге и кеш меморија су обрисани\n    Clear Search History and Cache: Очисти историју претраге и кеш меморију\n    Are you sure you want to clear out your search history and cache?: Желите ли заиста да очистите историју претраге и кеш меморију?\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Аутоматски\n        Semi-auto: Полуаутоматски\n        Never: Никада\n      Tooltip: Аутоматски = Чување при сваком излазу са странице видео снимка, када се видео снимак заврши и дође до грешке (нпр. ограничење брзине и истекла сесија гледања). Полуаутоматски = Попут „Аутоматски“ осим на излазу са странице видео снимка и може ручно сачувати путем дугмета под називом „Сачувај напредак одгледаног“, које се налази испод видео плејера.\n  Subscription Settings:\n    Subscription Settings: 'Праћење'\n    Fetch Feeds from RSS: 'Прикупи фидове из RSS-а'\n    Fetch Automatically: Аутоматски прикупи фид\n    Confirm Before Unsubscribing: Избегни случајно отпраћивање\n    To: На\n    'Limit the number of videos displayed for each channel': Ограничи број приказаних видео снимака за сваки канал\n  Distraction Free Settings:\n    Distraction Free Settings: 'Без ометања'\n    Hide Video Views: 'Сакриј прегледе видео снимка'\n    Hide Video Likes And Dislikes: 'Сакриј свиђања и несвиђања видео снимка'\n    Hide Channel Subscribers: 'Сакриј праћења канала'\n    Hide Comment Likes: 'Сакриј свиђања коментара'\n    Hide Recommended Videos: 'Сакриј препоручене видео снимке'\n    Hide Trending Videos: 'Сакриј видео снимке у тренду'\n    Hide Popular Videos: 'Сакриј популарне видео снимке'\n    Hide Playlists: 'Сакриј плејлисте'\n    Hide Live Chat: 'Сакриј ћаскање уживо'\n    Hide Active Subscriptions: 'Сакриј активна праћења'\n    Hide Channels Placeholder: ID канала\n    Hide Video Description: Сакриј опис видео снимка\n    Hide Chapters: Сакриј поглавља\n    Sections:\n      Watch Page: Страница гледања\n      Side Bar: Бочна трака\n      Channel Page: Страница канала\n      Subscriptions Page: Страница праћења\n      General: Опште\n    Hide Subscriptions Videos: Сакриј видео снимке канала које пратите\n    Hide Comments: Сакриј коментаре\n    Hide Channel Shorts: Сакриј картицу „Shorts“ канала\n    Hide Sharing Actions: Сакриј радње дељења\n    Hide Videos on Watch: 'Сакриј видео снимке на гледању'\n    Hide Channel Podcasts: Сакриј картицу „Подкасти“ канала\n    Hide Live Streams: Сакриј стримове уживо\n    Hide Channel Playlists: Сакриј картицу „Плејлисте“ канала\n    Hide Channels: Сакриј видео снимке са канала\n    Hide Subscriptions Live: Сакриј стримове уживо канала које пратите\n    Hide Subscriptions Shorts: Сакриј Shorts снимке канала које пратите\n    Display Titles Without Excessive Capitalisation: Прикажи наслове без претераног писања великих слова и интерпункције\n    Hide Featured Channels: Сакриј истакнуте канале\n    Hide Profile Pictures in Comments: Сакриј слике профила у коментарима\n    Hide Upcoming Premieres: Сакриј предстојеће премијере\n    Hide Channel Releases: Сакриј картицу „Издања“ канала\n    Hide Channels Invalid: Наведени ID канала је неважећи\n    Hide Channels Disabled Message: Неки канали су блокирани помоћу ID-а и нису обрађени. Функција је блокирана док се ти ID-ови ажурирају\n    Hide Channels Already Exists: ID канала већ постоји\n    Hide Channels API Error: Грешка при преузимању корисника са наведеним ID-ом. Проверите поново да ли је ID тачан.\n    Hide Videos, Playlists and Channels Containing Text: Сакриј видео снимке и плејлисте које садрже текст\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Реч, део речи или фраза\n    Hide Channel Home: Сакриј картицу „Почетна“ канала\n    Show Added Items: Прикажи додате предмете\n    Hide Channel Courses: Сакриј картицу „Курсеви“ на каналу\n    Hide Channel Posts: Сакриј картицу „Објаве“ канала\n    Hide Subscriptions Posts: Сакриј објаве о претплатама\n  Data Settings:\n    Data Settings: 'Подаци'\n    Select Export Type: 'Избор врсте извоза'\n    Import Subscriptions: 'Увоз праћења'\n    Export Subscriptions: 'Извоз праћења'\n    Export FreeTube: 'Извоз FreeTube-а'\n    Export YouTube: 'Извоз YouTube-а'\n    Export NewPipe: 'Извоз NewPipe-а'\n    Import History: 'Увоз историје'\n    Export History: 'Извоз историје'\n    Profile object has insufficient data, skipping item: 'Објекат профила нема довољно података, прескакање предмета'\n    All subscriptions and profiles have been successfully imported: 'Сва праћења и профили су успешно увезени'\n    All subscriptions have been successfully imported: 'Сва праћења су успешно увезена'\n    Invalid subscriptions file: 'Неважећи фајл праћења'\n    Invalid history file: 'Неважећи фајл историје'\n    Subscriptions have been successfully exported: 'Праћења су успешно извезена'\n    History object has insufficient data, skipping item: 'Објекат историје нема довољно података, прескакање предмета'\n    All watched history has been successfully imported: 'Цела историја гледања је успешно увезена'\n    All watched history has been successfully exported: 'Цела историја гледања је успешно извезена'\n    Unable to read file: 'Није могуће прочитати фајл'\n    Unable to write file: 'Није могуће написати фајл'\n    Unknown data key: 'Непознати кључ података'\n    How do I import my subscriptions?: 'Како да увезем своја праћења?'\n    Manage Subscriptions: 'Управљање праћењима'\n    All playlists has been successfully exported: Све плејлисте су успешно извезене\n    Playlist File: Фајл плејлисте\n    Subscription File: Фајл праћења\n    History File: Фајл историје\n    Export Playlists: Извор плејлиста\n    Import Playlists: Увоз плејлиста\n    All playlists has been successfully imported: Све плејлисте су успешно увезене\n    Playlist insufficient data: Нема довољно података за плејлисту „{playlist}“, прескакање предмета\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"Ова опција извози видео снимке са свих плејлиста у једну плејлисту под називом „Омиљено“.\\nКако да извезете и увезете видео снимке у плејлисте за старију верзију FreeTube-а:\\n1. Извезите своје плејлисте са омогућеном овом опцијом.\\n2. Избришите све своје постојеће плејлисте користећи опцију „Уклони све плејлисте“ у оквиру подешавања приватности.\\n3. Покрените старију верзију FreeTube-а и увезите извезене плејлисте.\"\n      Label: Извоз плејлиста за старије верзије FreeTube-а\n  Proxy Settings:\n    Proxy Settings: 'Прокси'\n    Enable Tor / Proxy: 'Омогући Tor / Прокси'\n    Proxy Protocol: 'Протокол проксија'\n    Proxy Host: 'Хост проксија'\n    Proxy Port Number: 'Број порта проксија'\n    Clicking on Test Proxy will send a request to: 'Клик на „Тестирај прокси“ послаће захтев на'\n    Test Proxy: 'Тестирај прокси'\n    Your Info: 'Ваше информације'\n    Ip: 'IP'\n    Country: 'Држава'\n    Region: 'Регион'\n    City: 'Град'\n    Error getting network information. Is your proxy configured properly?: 'Грешка при набављању информација о мрежи. Да ли је ваш прокси исправно конфигурисан?'\n    Proxy Warning: FreeTube нема уграђени прокси, али може да се повеже са спољним проксијем, као што је онај који ради на вашој машини као што је Tor или спољни прокси као што је SOCKS5 прокси који пружају неки VPN-ови. Ако је омогућено, уверите се да је ваш прокси/Tor исправно конфигурисан или FreeTube неће моћи да прикупи никакве податке.\n  Experimental Settings:\n    Replace HTTP Cache: Замени HTTP кеш\n    Experimental Settings: Експериментално\n    Warning: Ова подешавања су експериментална, могу да доведу до отказивања док су омогућена. Прављење резервних копија је веома препоручљиво. Користите на властиту одговорност!\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Обавештење када се спонзор сегмент прескочи\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API-ја SponsorBlock-а (Подразумевано је https://sponsor.ajay.app)\n    Skip Options:\n      Skip Option: Опција прескакања\n      Do Nothing: Не ради ништа\n      Prompt To Skip: Упит за прескакање\n      Auto Skip: Аутоматско прескакање\n      Show In Seek Bar: Приказ у траци за прескакање\n    UseDeArrowTitles: Користи DeArrow наслове видео снимака\n    Enable SponsorBlock: Омогући SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Category Color: Боја категорије\n    UseDeArrowThumbnails: Користи DeArrow за сличице\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL API-ја DeArrow генератора сличица (Подразумевано је https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    External Player: Спољни плејер\n    External Player Settings: Спољни плејер\n    Custom External Player Executable: Прилагођени извршни спољни плејер\n    Ignore Unsupported Action Warnings: Занемари упозорења о неподржаним радњама\n    Custom External Player Arguments: Прилагођени аргументи спољног плејера\n    Players:\n      None:\n        Name: Ниједно\n    Ignore Default Arguments: Занемари подразумеване аргументе\n  Password Settings:\n    Remove Password: Уклони лозинку\n    Set Password To Prevent Access: Подеси лозинку да спречиш приступ подешавањима\n    Password Settings: Лозинка\n    Set Password: Подеси лозинку\n  Parental Control Settings:\n    Show Family Friendly Only: Прикажи само погодно за породицу\n    Hide Unsubscribe Button: Сакриј дугме „Прекини праћење“\n    Hide Search Bar: Сакриј траку за претрагу\n    Parental Control Settings: Родитељска контрола\n    Hide Uploader on Watch page: Сакриј отпремаоца на страници за гледање\n  Password Dialog:\n    Password: Лозинка\n    Enter Password To Unlock: Унесите лозинку да бисте откључали подешавања\n  Sort Settings Sections (A-Z): Сортирање одељка подешавања (A-Z)\n  Return to Settings Menu: Врати се у мени подешавања\nAbout:\n  #On About page\n  About: 'О апликацији'\n  Beta: 'Бета'\n  Source code: 'Изворни кôд'\n  Downloads / Changelog: 'Преузимања / Евиденција промена'\n  GitHub releases: 'GitHub издања'\n  Help: 'Помоћ'\n  FreeTube Wiki: 'FreeTube Wiki'\n  FAQ: 'ЧПП'\n  Report a problem: 'Пријава проблема'\n  GitHub issues: 'Пријава проблема на GitHub-у'\n  Please check for duplicates before posting: 'Проверите да ли има дупликата пре објављивања'\n  Website: 'Веб-сајт'\n  Blog: 'Блог'\n  Email: 'Имејл'\n  Mastodon: 'Mastodon'\n  Chat on Matrix: 'Ћаскање на Matrix-у'\n  room rules: 'правила собе'\n  Translate: 'Преведи'\n  Credits: 'Заслуге'\n  these people and projects: 'ови људи и пројекти'\n  Donate: 'Донација'\n\n  Discussions: Дискусије\n  AGPLv3: AGPLv3\nProfile:\n  Profile Select: 'Избор профила'\n  Profile Filter: 'Филтер профила'\n  All Channels: 'Сви канали'\n  Profile Manager: 'Управљање профилом'\n  Create New Profile: 'Направи нови профил'\n  Edit Profile: 'Измени профил'\n  Color Picker: 'Бирач боје'\n  Custom Color: 'Прилагођена боја'\n  Profile Preview: 'Преглед профила'\n  Create Profile: 'Направи профил'\n  Update Profile: 'Ажурирај профил'\n  Make Default Profile: 'Направи подразумевани профил'\n  Delete Profile: 'Избриши профил'\n  Are you sure you want to delete this profile?: 'Желите ли заиста да избришете овај профил?'\n  All subscriptions will also be deleted.: 'Сва праћења ће такође бити избрисана.'\n  Your profile name cannot be empty: 'Име профила не може бити празно'\n  Profile has been created: 'Профил је направљен'\n  Profile has been updated: 'Профил је ажуриран'\n  Your default profile has been set to {profile}: 'Ваш подразумевани профил је постављен на {profile}'\n  Removed {profile} from your profiles: 'Уклоњен {profile} из ваших профила'\n  Your default profile has been changed to your primary profile: 'Ваш подразумевани профил је промењен на ваш примарни профил'\n  '{profile} is now the active profile': '{profile} је сада активан профил'\n  Subscription List: 'Листа праћења'\n  Other Channels: 'Остали канали'\n  '{number} selected': 'Изабрано: {number}'\n  Select All: 'Изабери све'\n  Select None: 'Ниједан'\n  Delete Selected: 'Избриши изабрано'\n  Add Selected To Profile: 'Додај изабрано на профил'\n  No channel(s) have been selected: 'Није изабран ниједан канал'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Ово је ваш примарни профил.  Желите ли заиста да избришете изабране канале?  Исти канали ће бити избрисани у било ком профилу на којем се налазе.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Желите ли заиста да избришете изабране канале?  Ово неће избрисати канал из било ког другог профила.'\n#On Channel Page\n  Profile Settings: Профил\n  Toggle Profile List: Укључи листу профила\n  Open Profile Dropdown: Отвори падајући мени профила\n  Close Profile Dropdown: Затвори падајући мени профила\n  Profile Name: Име профила\n  Edit Profile Name: Измени име профила\n  Create Profile Name: Направи име профила\nChannel:\n  Subscribe: 'Запрати'\n  Unsubscribe: 'Прекини праћење'\n  Channel has been removed from your subscriptions: 'Канал је уклоњен из ваших праћења'\n  Removed subscription from {count} other channel(s): 'Уклоњено праћење са {count} других канала'\n  Added channel to your subscriptions: 'Канал је додат у ваша праћења'\n  Search Channel: 'Претражи канал'\n  Your search results have returned 0 results: 'Резултати претраге су дали 0 резултата'\n  Videos:\n    Videos: 'Видео снимци'\n    This channel does not currently have any videos: 'Овај канал тренутно нема ниједан видео снимак'\n    Sort Types:\n      Newest: 'Најновије'\n      Oldest: 'Најстарије'\n      Most Popular: 'Најпопуларније'\n  Playlists:\n    Playlists: 'Плејлисте'\n    This channel does not currently have any playlists: 'Овај канал тренутно нема ниједну плејлисту'\n    Sort Types:\n      Last Video Added: 'Последњи додат видео снимак'\n      Newest: 'Најновије'\n      Oldest: 'Најстарије'\n  About:\n    About: 'О каналу'\n    Channel Description: 'Опис канала'\n    Featured Channels: 'Истакнути канали'\n    Joined: Придружено\n    Tags:\n      Search for: Претрага „{tag}“\n      Tags: Ознаке\n    Details: Детаљи\n    Location: Локација\n  Posts:\n    This channel currently does not have any posts: Овај канал тренутно нема ниједну објаву\n    Reveal Answers: Откриј одговоре\n    Hide Answers: Сакриј одговоре\n    votes: 'Гласова: {votes}'\n    Video hidden by FreeTube: Видео снимак сакрио је FreeTube\n    View Full Post: Погледај целу објаву\n    Viewing Posts Only Supported By Invidious: Гледање објава подржава само Invidious. Идите на картицу заједнице канала да видите садржај тамо без Invidious-a.\n  Live:\n    Live: Уживо\n    This channel does not currently have any live streams: Овај канал тренутно нема ниједан стрим уживо\n  Releases:\n    Releases: Издања\n    This channel does not currently have any releases: Овај канал тренутно нема ниједно издање\n  This channel does not allow searching: Овај канал не дозвољава претрагу\n  Shorts:\n    This channel does not currently have any shorts: Овај канал тренутно нема Shorts снимке\n  Podcasts:\n    This channel does not currently have any podcasts: Овај канал тренутно нема ниједан подкаст\n    Podcasts: Подкасти\n  Channel Tabs: Картице канала\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Овај канал је старосно ограничен и тренутно се не може гледати на FreeTube-у.\n  This channel does not exist: Овај канал не постоји\n  Home:\n    Home: Почетна\n    View Playlist: Погледај плејлисту\n  Courses:\n    Courses: Курсеви\n    This channel does not currently have any courses: Овај канал тренутно нема ниједан курс\nVideo:\n  Mark As Watched: 'Означи као одгледано'\n  Remove From History: 'Уклони из историје'\n  Video has been marked as watched: 'Видео снимак је означен као одгледан'\n  Video has been removed from your history: 'Видео снимак је уклоњен из ваше историје'\n  Save Video: 'Сачувај видео снимак'\n  Video has been saved: 'Видео снимак је сачуван'\n  Video has been removed from your saved list: 'Видео снимак је уклоњен из ваше листе сачуваног'\n  Open in YouTube: 'Отвори у YouTube-у'\n  Copy YouTube Link: 'Копирај YouTube линк'\n  Open YouTube Embedded Player: 'Отвори YouTube уграђени плејер'\n  Copy YouTube Embedded Player Link: 'Копирај линк YouTube уграђеног плејера'\n  Open in Invidious: 'Отвори у Invidious-у'\n  Copy Invidious Link: 'Копирај Invidious линк'\n  Open Channel in YouTube: 'Отвори канал у YouTube-у'\n  Copy YouTube Channel Link: 'Копирај линк YouTube канала'\n  Open Channel in Invidious: 'Отвори канал у Invidious-у'\n  Copy Invidious Channel Link: 'Копирај линк Invidious канала'\n  Views: 'Прегледа'\n  Loop Playlist: 'Понављај плејлисту'\n  Shuffle Playlist: 'Мешање плејлисте'\n  Reverse Playlist: 'Обрнута плејлиста'\n  Previous: 'Претходно'\n  Next: 'Следеће'\n  Watched: 'Одгледано'\n  Autoplay: 'Аутоматско пуштање'\n  Starting soon, please refresh the page to check again: 'Почиње ускоро, освежите страницу да бисте поново проверили'\n  # As in a Live Video\n  Live: 'Уживо'\n  Live Now: 'Уживо сада'\n  Live Chat: 'Ћаскање уживо'\n  Enable Live Chat: 'Омогући ћаскање уживо'\n  Live Chat is currently not supported in this build.: 'Ћаскање уживо тренутно није подржано у овом издању.'\n  Published:\n    In less than a minute: За мање од једног минута\n  Upcoming: Предстојеће\n  Sponsor Block category:\n    interaction: Интеракција\n    filler: Попуњавање\n    music offtopic: Сегмент без музике\n    outro: Завршна анимација\n    self-promotion: Самопромоција\n    sponsor: Спонзор\n    recap: Рекапитулација\n    intro: Уводна анимација\n  External Player:\n    Unsupported Actions:\n      opening playlists: отварање плејлиста\n      shuffling playlists: мешање плејлиста\n      setting a playback rate: подешавање брзине репродукције\n      looping playlists: понављање плејлиста\n      reversing playlists: обртање плејлиста\n      opening specific video in a playlist (falling back to opening the video): отварање одређеног видео снимка на плејлисти (повратак на отварање видео снимка)\n      starting video at offset: почињање видео снимка у офсету\n    OpeningTemplate: Отварање {videoOrPlaylist} у {externalPlayer}...\n    OpenInTemplate: Отвори у {externalPlayer}\n    video: видео снимак\n    UnsupportedActionTemplate: '{externalPlayer} не подржава: {action}'\n    playlist: плејлиста\n  Live chat is enabled. Chat messages will appear here once sent.: Ћаскање уживо је омогућено.  Поруке ћаскања ће се појавити овде када буду послате.\n  Streamed on: Стримовано\n  Show Super Chat Comment: Прикажи Super Chat коментар\n  Scroll to Bottom: Превуци до дна\n  Started streaming on: Започето стримовање\n  Premieres: Премијера\n  Published on: Објављено\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': Ћаскање уживо тренутно није подржано са Invidious API-јем. Потребна је директна веза са YouTube-ом.\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Ћаскање уживо није доступно за овај стрим. Можда га је онемогућио аутор.\n  Unhide Channel: Прикажи канал\n  Hide Channel: Сакриј канал\n  More Options: Више опција\n  Player:\n    TranslatedCaptionTemplate: '{language} (преведено са „{originalLanguage}“)'\n    Theatre Mode: Режим биоскопа\n    Exit Theatre Mode: Изађи из режима биоскопа\n    Exit Full Window: Изађи из целог прозора\n    Take Screenshot: Направи снимак екрана\n    Show Stats: Прикажи статистику\n    Hide Stats: Сакриј статистику\n    Stats:\n      Video ID: 'ID видеа: {videoId}'\n      Media Formats: 'Формат медија: {formats}'\n      Resolution: 'Резолуција: {width}x{height}{''@''}{frameRate}'\n      Volume: 'Волумен: {volumePercentage}%'\n      Stats: Статистика\n      Dropped Frames / Total Frames: 'Испуштени кадрови: {droppedFrames} / Укупан број кадрова: {totalFrames}'\n      CodecAudio: 'Кодек: {audioCodec} ({audioItag})'\n      Player Dimensions: 'Димензије плејера: {width}x{height}'\n      Bitrate: 'Брзина преноса: {bitrate} kbps'\n      Bandwidth: 'Пропусни опсег: {bandwidth} kbps'\n      Buffered: 'Баферовано: {bufferedPercentage}%'\n      CodecsVideoAudio: 'Кодеци: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Кодеци: {videoCodec} / {audioCodec}'\n    Audio Tracks: Аудио нумере\n    Full Window: Цео прозор\n    You appear to be offline: Изгледа да сте офлајн.\n    Playback will resume automatically when your connection comes back: Репродукција ће се аутоматски наставити када се ваша интернет веза врати.\n    Skipped segment: Прескочен сегмент „{segmentCategory}“\n    Autoplay is off: Аутоматско пуштање је искључено\n    Autoplay is on: Аутоматско пуштање је укључено\n  IP block: YouTube је блокирао вашу IP адресу за гледање видео снимака. Покушајте прећи на други VPN или прокси.\n  Unlisted: По позиву\n  MembersOnly: Видео снимци само за чланове не могу да се гледају на FreeTube-у јер захтевају пријављивање на Google налог и плаћено чланство на каналу.\n  AgeRestricted: Видео снимци са старосним ограничењемне могу се гледати на FreeTube-у јер захтевају пријаву на Google налог и коришћење YouTube налога који је старосно верификован.\n  DeArrow:\n    Show Modified Details: Прикажи измењене детаље\n    Show Original Details: Прикажи оригиналне детаље\n  DRMProtected: Видео снимци заштићени DRM не могу се репродуковати у FreeTube-у, јер захтевају власничке компоненте затвореног кода. Ако желите да гледате овај видео снимак, погледајте га на званичном сајту YouTube-а у веб-прегледачу с омогућеним DRM.\n  Save Watched Progress: Сачувај напредак гледања\n  Watched Progress Saved: Напредак гледања је сачуван\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: 'Када је омогућено, FreeTube ће користити RSS уместо свог подразумеваног метода за прикупљање вашег фида праћења. RSS је бржи и спречава блокирање IP адресе, али не пружа одређене информације као што су трајање видео снимка, статус уживо или објаве'\n\n# Toast Messages\n    Fetch Automatically: Када је омогућено, FreeTube ће аутоматски преузети ваш фид претплата при покретању и када се отвори нови прозор.\n  General Settings:\n    External Link Handling: \"Изаберите подразумевано понашање када се кликне на линк који се не може отворити у FreeTube-у.\\nПодразумевано, FreeTube ће отворити линк на који сте кликнули у вашем подразумеваном прегледачу.\\n\"\n    Fallback to Non-Preferred Backend on Failure: Када ваш преферирани API има проблем, FreeTube ће аутоматски покушати да користи ваш непреферирани API као резервни метод, када је омогућено.\n    Preferred API Backend: Изаберите бек-енд коју FreeTube користи за добијање података. Локални API је уграђени екстрактор. Invidious API захтева Invidious сервер за повезивање.\n    Thumbnail Preference: Све сличице на FreeTube-у биће замењене оквиром видеа, замућеним или скривеним уместо подразумеване сличице.\n    Region for Trending: Регион трендова вам омогућава да изаберете државу за видео снимке у тренду коју желите да се приказује.\n    Invidious Instance: Invidious инстанца на коју ће се FreeTube повезати за API позиве.\n    Open Deep Links In New Window: URL адресе прослеђене FreeTube-у, као што су додаци прегледача за преусмеравање или аргументи командне линије, отварају се у новом прозору.\n  External Player Settings:\n    Custom External Player Arguments: Сви прилагођени аргументи командне линије, желите да буду прослеђени спољном плејеру.\n    External Player: Избором спољног плејера ће приказати иконицу, за отварање видео снимка (плејлисте, ако је подржана) у спољном плејеру, на сличици. Упозорење, подешавања Invidious-а не утичу на спољне плејере.\n    DefaultCustomArgumentsTemplate: (Подразумевано:„{defaultCustomArguments}“)\n    Custom External Player Executable: Подразумевано, FreeTube ће претпоставити да се изабрани спољни плејер може пронаћи преко PATH променљиве окружења. Ако је потребно, овде се може подесити прилагођена путања.\n    Ignore Warnings: Поништи упозорења када тренутни спољни плејер не подржава тренутну радњу (нпр. обртање плејлиста итд.).\n    Ignore Default Arguments: Немојте слати никакве подразумеване аргументе спољном плејеру осим URL адресе видео снимка (нпр. брзина репродукције, URL адреса плејлисте итд.). Прилагођени аргументи ће и даље бити прослеђени.\n  Distraction Free Settings:\n    Hide Channels: Унесите назив канала или ID канала да бисте сакрили све видео снимке, плејлисте и сам канал, да се не појављују у претрази, у тренду, најпопуларнијима и препорученима. ID канала који сте унели мора се потпуно подударати и разликовати велика и мала слова.\n    Hide Subscriptions Live: Ово подешавање је замењено подешавањем за целу апликацију „{appWideSetting}“ у одељку „{subsection}“ у „{settingsSection}“\n    Hide Videos, Playlists and Channels Containing Text: Унесите реч, део речи или фразу (не разликује велика и мала слова) да бисте сакрили све видео снимке и плејлисте чији их оригинални наслови садрже у целом FreeTube-у, искључујући само историју, ваше плејлисте и видео снимке унутар плејлиста.\n    Hide Videos on Watch: Скрива гледане видео снимке са картица „Видео снимци“, „Shorts“ и „Уживо“ на страницама „Праћења“ и „Канал“. Ово не утиче на картицу „Почетна“ на страницама „Канал“\n  Player Settings:\n    Default Video Format: Подесите формате који се користе приликом репродукције видеа. DASH формати могу да репродукују бољи квалитет. Застарели формати су ограничени на највише 360p, али користе мањи пропусни опсег. Звучни формати су само звучни стримови.\n    Proxy Videos Through Invidious: Повезаће се сa Invidious-ом ради приказивања видео снимака уместо директног повезивања са YouTube-ом.\n    Scroll Playback Rate Over Video Player: Док је курсор изнад видео снимка, притисните и држите тастер „Control“ (тастер „Command“ на Mac-у) и померајте точкић миша унапред или уназад да бисте контролисали брзину репродукције. Притисните и држите тастер „Control“ (тастер „Command„ на Mac-у) и кликните левим тастером миша да бисте се брзо вратили на подразумевану брзину репродукције (1x, осим ако није промењено у подешавањима).\n    Skip by Scrolling Over Video Player: Користите точкић миша да бисте прескакали кроз видео снимак, MPV стил.\n  Experimental Settings:\n    Replace HTTP Cache: Онемогућава HTTP кеш заснован на Electron-овом диску и омогућава прилагођени кеш слике у меморији. То ће довести до повећане употребе RAM-а.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Замена наслова видео снимака насловима које су послали корисници DeArrow-a.\n    UseDeArrowThumbnails: Замените сличице видео снимака сличицама из DeArrow-а.\nOpen New Window: Отвори нови прозор\nShuffle is now disabled: Мешање је сада онемогућено\nNew Window: Нови прозор\nClipboard:\n  Copy failed: Копирање у привремену меморију није успело\n  Cannot access clipboard without a secure connection: Није могуће приступити привременој меморији без безбедне везе\nPlaylist:\n  View Full Playlist: Погледај целу плејлисту\n  Last Updated On: Последњи пут ажурирано\n  Playlist: Плејлиста\n  Sort By:\n    DateAddedOldest: Најраније додато прво\n    AuthorAscending: Аутор (A-Z)\n    VideoTitleAscending: Наслов (A-Z)\n    VideoTitleDescending: Наслов (Z-A)\n    Custom: Прилагођено\n    AuthorDescending: Аутор (Z-A)\n    DateAddedNewest: Најкасније додато прво\n    VideoDurationDescending: Трајање (прво најдуже)\n    VideoDurationAscending: Трајање (прво најкраће)\n    PublishedNewest: Најкасније објављено прво\n    PublishedOldest: Прво најраније објављено\nFalling back to Invidious API: Повратак на Invidious API\nChange Format:\n  Dash formats are not available for this video: DASH формати нису доступни за овај видео снимак\n  Audio formats are not available for this video: Аудио формати нису доступни за овај видео снимак\n  Use Audio Formats: Користи аудио формате\n  Change Media Formats: Промени формате медија\n  Use Dash Formats: Користи DASH формате\n  Use Legacy Formats: Користи застареле формате\n  Legacy formats are not available for this video: Застарели формати нису доступни за овај видео снимак\nComments:\n  Comments: Коментари\n  Click to View Comments: Кликни да видиш коментаре\n  Top comments: Топ коментари\n  Subscribed: Пратите\n  Getting comment replies, please wait: Набављање одговора на коментаре, сачекајте\n  Load More Comments: Учитај више коментара\n  Hide Comments: Сакриј коментаре\n  Show More Replies: Прикажи више одговора\n  Pinned by: Закачио\n  Hearted: Са срцем\n  There are no comments available for this video: Нема доступних коментара за овај видео снимак\n  View {replyCount} replies: Погледај {replyCount} одговор(а)\n  Member: Члан\n  There are no more comments for this video: Нема више коментара за овај видео снимак\n  Newest first: Најновије прво\n  There are no comments available for this post: Нема доступних коментара за ову објаву\nShare:\n  Invidious Embed URL copied to clipboard: Invidious уграђени URL је копиран у привремену меморију\n  Share Channel: Дели канал\n  Open Embed: Отвори уграђено\n  Invidious Channel URL copied to clipboard: Invidious URL канала је копиран у привремену меморију\n  YouTube URL copied to clipboard: YouTube URL је копиран у привремену меморију\n  Share Playlist: Дели плејлисту\n  Copy Embed: Копирај уграђено\n  Copy Link: Копирај линк\n  Open Link: Отвори линк\n  Share Video: Дели видео снимак\n  Include Timestamp: Укључи временску ознаку\n  Invidious URL copied to clipboard: Invidious URL је копиран у привремену меморију\n  YouTube Channel URL copied to clipboard: YouTube URL канала је копиран у привремену меморију\n  YouTube Embed URL copied to clipboard: YouTube уграђени URL је копиран у привремену меморију\nFalling back to Local API: Повратак на локални API\nUnknown YouTube url type, cannot be opened in app: Непозната врста YouTube URL адресе, не може се отворити у апликацији\nSearch Bar:\n  Clear Input: Очисти унос\n  Remove: Уклони\nUp Next: Следеће\nLoop is now disabled: Понављање је сада онемогућено\nPlaying Next Video: Пуштање следећег видео снимка\nThe playlist has been reversed: Плејлиста је обрнута\nLocal API Error (Click to copy): Грешка локалног API-ја (Кликнути за копирање)\nChannels:\n  Search bar placeholder: Претражи канале\n  Unsubscribe Prompt: Желите ли заиста да прекинете праћење „{channelName}“?\n  Channels: Канали\n  Title: Листа канала\n  Empty: Ваша листа канала је тренутно празна.\n  Count: 'Пронађено канала: {number}.'\nExternal link opening has been disabled in the general settings: Отварање спољног линка је онемогућено у општим подешавањима\nScreenshot Success: Снимак екрана је сачуван\nCanceled next video autoplay: Отказано аутоматско пуштање следећег видео снимка\nPlaying Next Video Interval: Пуштање следећег видео снимка убрзо. Кликнути за отказивање. | Пушта се следећи видео снимак за {nextVideoInterval} секунду. Кликнути за отказивање. | Пушта се следећи видео за {nextVideoInterval} секунди. Кликнути за отказивање.\nNo: Не\nYes: Да\nChapters:\n  Chapters: Поглавља\n  Key Moments: Кључни тренуци\nHashtag:\n  This hashtag does not currently have any videos: Ова хеш-ознака тренутно нема ниједан видео снимак\n  Hashtag: Хеш-ознака\nPlaying Previous Video: Пуштање претходног видео снимка\nOk: У реду\nInvidious API Error (Click to copy): Грешка Invidious API-ја (Кликнути за копирање)\nPreferences: Преференце\nDefault Invidious instance has been cleared: Подразумевана инстанца Invidious-а је избрисана\nMini Player: Мини плејер\n'The playlist has ended. Enable loop to continue playing': Плејлиста је завршена. Омогућите понављање да бисте наставили пуштање\nShuffle is now enabled: Мешање је сада омогућено\nDefault Invidious instance has been set to {instance}: Подразумевана инстанца Invidious-а је подешена на {instance}\nAre you sure you want to open this link?: Желите ли заиста да отворите овај линк?\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Овај видео снимак је недоступан, јер недостају формати. То се може догодити због недоступности државе.\nScreenshot Error: Снимак екрана није успео. {error}\nLoop is now enabled: Понављање је сада омогућено\nChannel Hidden: '{channel} је додат на филтер канала'\nGo to page: Иди на {page}\nChannel Unhidden: '{channel} је уклоњен из филтера канала'\nTrimmed input must be at least N characters long: Исечени унос мора да има најмање 1 знак | Исечени унос мора да има најмање {length} знакова\nTag already exists: Ознака „{tagName}“ већ постоји\nClose Banner: Затвори банер\nAge Restricted:\n  This channel is age restricted: Овај канал је ограничен према узрасту\n  This video is age restricted: Овај видео снимак је ограничен према узрасту\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nFeed:\n  Feed Last Updated: 'Фид {feedName} је последњи пут ажуриран: {date}'\n  Refresh Feed: Освежи {subscriptionName}\nMoments Ago: пре неколико тренутака\nCancel: Откажи\nYes, Delete: Да, избриши\nYes, Restart: Да, рестартуј\nYes, Open Link: Да, отвори линк\nSearch character limit: Упит за претрагу премашује ограничење броја знакова од {searchCharacterLimit} знакова\nSearch Listing:\n  Label:\n    Closed Captions: Скривени титлови\n    4K: 4K\n    Subtitles: Титлови\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Ново\n    3D: 3D\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nKeys:\n  alt: Alt\n  arrowdown: Стрелица доле\n  arrowleft: Стрелица лево\n  ctrl: Ctrl\n  arrowup: Стрелица горе\n  arrowright: Стрелица десно\n  shift: Shift\n  enter: Enter\n  plus: Plus\nshortcutJoinOperator: +\nRight-click or hold to see history: Кликните десним тастером миша или задржите да бисте видели историју\nAutoplay Interruption Timer: Аутоплеј је отказан због {autoplayInterruptionIntervalHours} сати неактивности\nDescription:\n  Expand Description: …више\n  Collapse Description: Прикажи мање\nKeyboardShortcutPrompt:\n  History Backward: Одлазак једну страницу уназад\n  Sections:\n    App:\n      Situational: 'Апликација: Ситуационална'\n      General: 'Апликација: Опште'\n    Video:\n      General: 'Видео снимак: Опште'\n      Playback: 'Видео снимак: Репродукција'\n  Show Keyboard Shortcuts: Прикажи тастерске пречице\n  Navigate to Settings: Одлазак на страницу „Подешавања“\n  History Forward: Одлазак једну страницу унапред\n  New Window: Прављење новог прозора\n  Large Rewind: Премотавање 10 секунди уназад / Премотавање видео снимак уназад на основу тренутне брзине репродукције видео снимка\n  Play: Пуштање/пауза\n  Zoom In: Увеличавање\n  Reset Zoom: Ресетовање нивоа увеличавања / скале корисничког интерфејса\n  Toggle Developer Tools: Укључивање програмерских опција\n  Zoom Out: Умањивање\n  Next Chapter: Следеће поглавље\n  Skip by Tenths: Прескакање кроз видео снимак по процентима (3 прескакања до 30% трајања)\n  Last Chapter: Последње поглавље\n  Keyboard Shortcuts: Тастерске пречице\n  Captions: Укључивање/искључивање титлова\n  Picture in Picture: Укључивање режима слике у слици\n  Stats: Приказ статистике видео снимка\n  Refresh: Освежавање фида најновијим садржајем\n  Navigate to History: Одлазак на страницу „Почетна“\n  Mute: Утишавање\n  Decrease Video Speed: Смањивање брзине видео снимка на основу интервала брзине репродукције видео снимка\n  Increase Video Speed: Повећавање брзине видео снимка на основу интервала брзине репродукције видео снимка\n  Theatre Mode: Укључивање режима биоскопа\n  Take Screenshot: Снимак екрана\n  Minimize Window: Минимизирање прозора\n  Close Window: Затварање прозора\n  Focus Search: Фокусирање на траку за претрагу\n  Last Frame: Претходни кадар (приликом паузе)\n  Next Frame: Следећи кадар (приликом паузе)\n  Volume Up: Појачавање јачине звука\n  Small Rewind: Премотавање X секунди уназад на основу интервала премотавања уназад и тренутне брзине репродукције видео снимка\n  Full Window: Укључивање целог прозора\n  Focus Secondary Search: Фокусирање на секундарну траку за претрагу (ако постоји)\n  Large Fast Forward: Премотавање 10 секунди унапред / Брзо премотавање видео снимка унапред на основу тренутне брзине репродукције видео снимка\n  Search in New Window: Претрага у новом прозору\n  Fullscreen: Укључивање режима целог екрана\n  Volume Down: Смањивање јачине звука\n  Small Fast Forward: Брзо премотавање унапред X секунди засновано на интервалу брзог премотавања унапред и тренутној брзини репродукције видео снимка\n  Home: Премотавање на почетак видео снимка\n  End: Премотавање на крај видео снимка\n  Skip to Next Video: Прескакање на следећи видео снимак на плејлисти или следећи препоручени видео снимак\n  Skip to Previous Video: Прескакање на претходни видео снимак на плејлисти\nshortcutLabelSeparator: ｜\n"
  },
  {
    "path": "static/locales/sv.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Svenska'\n\n# Webkit Menu Bar\nFile: 'Fil'\nQuit: 'Avsluta'\nEdit: 'Redigera'\nUndo: 'Ångra'\nRedo: 'Gör om'\nCut: 'Klipp ut'\nCopy: 'Kopiera'\nPaste: 'Klistra in'\nDelete: 'Radera'\nSelect all: 'Markera allt'\nToggle Developer Tools: 'Växla utvecklarverktyg'\nActual size: 'Verklig storlek'\nZoom in: 'Zooma in'\nZoom out: 'Zooma ut'\nToggle fullscreen: 'Växla helskärmsläge'\nWindow: 'Fönster'\nMinimize: 'Minimera'\nClose: 'Stäng'\nBack: 'Tillbaka'\nForward: 'Framåt'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videor'\n  Shorts: Shorts\n  Live: Live\n  Posts: Inlägg\n  Sort By: Sortera efter\n\n  Counts:\n    Video Count: 1 video | {count} videor\n    Subscriber Count: 1 prenumerant | {count} prenumeranter\n    View Count: 1 visning | {count} visningar\n    Watching Count: 1 tittare | {count} tittare\n    Channel Count: 1 kanal | {count} kanaler\n    Like Count: 1 gillning | {count} gillningar\n    Comment Count: 1 kommentar | {count} kommentarer\nVersion {versionNumber} is now available!  Click for more details: 'Version {versionNumber} är nu tillgänglig!  Klicka för mer detaljer'\nDownload From Site: 'Ladda ner från webbplatsen'\nA new blog is now available, {blogTitle}. Click to view more: 'En ny blogg finns nu tillgänglig, {blogTitle}. Klicka för att se mer'\n\n# Search Bar\nSearch / Go to URL: 'Sök / Gå till URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Sökfilter'\n  Sort By:\n    Most Relevant: 'Mest relevanta'\n    Rating: 'Betyg'\n    Upload Date: 'Uppladdningsdatum'\n    View Count: 'Antal visningar'\n  Time:\n    Time: 'Tid'\n    Any Time: 'När som helst'\n    Last Hour: 'Senaste timmen'\n    Today: 'Idag'\n    This Week: 'Den här veckan'\n    This Month: 'Den här månaden'\n    This Year: 'I år'\n  Type:\n    Type: 'Typ'\n    All Types: 'Alla typer'\n    Videos: 'Videor'\n    Channels: 'Kanaler'\n    #& Playlists\n    Movies: Filmer\n  Duration:\n    Duration: 'Längd'\n    All Durations: 'Alla längder'\n    Short (< 4 minutes): 'Kort (< 4 minuter)'\n    Long (> 20 minutes): 'Lång (> 20 minuter)'\n  # On Search Page\n    Medium (4 - 20 minutes): Mellan (4 - 20 minuter)\n  Search Results: 'Sökresultat'\n  Fetching results. Please wait: 'Hämtar resultat. Vänta'\n  Fetch more results: 'Hämta fler resultat'\n# Sidebar\n  There are no more results for this search: Det finns inga fler resultat för denna sökning\n  Features:\n    360 Video: 360 Video\n    Location: Plats\n    HDR: HDR\n    HD: HD\n    Subtitles: Undertexter\n    Creative Commons: Creative Commons\n    3D: 3D\n    Live: Live\n    4K: 4K\n    VR180: VR180\n    Features: Funktioner\n  Clear Filters: Rensa filter\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Prenumerationer'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Din prenumerationslista är för närvarande tom. Om du vill importera dina prenumerationer kan du gå till Datainställningar och välja Importera prenumerationer eller så kan du söka efter en kanal och prenumerera på dem.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Denna profil har ett stort antal prenumerationer. Tvingar RSS för att undvika hastighetsbegränsning\n  Load More Videos: Se mer\n  Error Channels: Kanaler med fel\n  Disabled Automatic Fetching: Du har avaktiverat automatisk prenumerationshämtning. Uppdatera prenumerationerna för att se dem här.\n  Empty Channels: Dina prenumererade kanaler har inga filmer.\n  Subscriptions Tabs: Prenumerationsflikar\n  All Subscription Tabs Hidden: Alla prenumerationsflikar är dolda. För att se innehåll här, sluta dölja vissa flikar i avsnittet \"{subsection}\" i \"{settingsSection}\".\n  Load More Posts: Ladda fler inlägg\n  Empty Posts: Dina prenumererade kanaler har för närvarande inga inlägg.\nTrending:\n  Trending: 'Populärt'\n  Gaming: Spel\n  Trending Tabs: Populära flikar\n  Sports: Sport\nMost Popular: 'Mest populära'\nPlaylists: 'Spellistor'\nUser Playlists:\n  Your Playlists: 'Dina spellistor'\n  Search bar placeholder: Sök efter spellistor\n  Empty Search Message: Det finns inga videor i denna spellista som matchar din sökning\n  Playlist Name: Spellistenamn\n  Playlist Description: Spellistebeskrivning\n  Delete Playlist: Ta bort spellista\n  Create New Playlist: Skapa ny spellista\n  Save Changes: Spara ändringar\n  Cancel: Avbryt\n  Edit Playlist Info: Redigera spellisteinformation\n  Copy Playlist: Kopiera spellista\n  Add to Favorites: Lägg till {playlistName}\n  Remove from Favorites: Ta bort från {playlistName}\n  Move Video Up: Flytta upp video\n  Move Video Down: Flytta ner video\n  Remove from Playlist: Ta bort från spellista\n  You have no playlists. Click on the create new playlist button to create a new one.: Du har inga spellistor. Klicka på Skapa ny spellista-knappen för att skapa en ny.\n  This playlist currently has no videos.: Denna spellista har för närvarande inga videor.\n  Add to Playlist: Lägg till spellista\n  Sort By:\n    EarliestPlayedFirst: Datum spelad (äldst)\n    EarliestUpdatedFirst: Datum uppdaterad (äldst)\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: Datum skapad (nyast)\n    EarliestCreatedFirst: Datum skapad (äldst)\n    LatestUpdatedFirst: Datum uppdaterad (nyast)\n    LatestPlayedFirst: Datum spelad (nyast)\n  Are you sure you want to delete this playlist? This cannot be undone: Är du säker på att du vill ta bort den här spellistan? Detta kan inte ångras.\n  AddVideoPrompt:\n    Added {count} Times: Redan tillagd | Tillagd {count} gånger\n    Save: Spara\n    Search in Playlists: Sök i spellistor\n    Select a playlist to add your N videos to: Välj en spellista att lägga till din video i | Välj en spellista att lägga till dina {videoCount} videor i\n    N playlists selected: '{playlistCount} valda'\n    Toast:\n      You haven't selected any playlist yet.: Du har inte valt någon spellista ännu.\n      \"Video(s) added to {playlistCount} playlists\": \"Videor tillagda i 1 spellista | Videor tillagda i {playlistCount} spellistor\"\n    Allow Adding Duplicate Video(s): Tillåt tilläggning av dubblettvideor\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Videor Kommer Att Läggas Till'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Videor är redan tillagda'\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: Videon har tagits bort\n      \"{videoCount} video(s) have been removed\": 1 video har tagits bort | {videoCount} videor har tagits bort\n      There were no videos to remove.: Det fanns inga videor att ta bort.\n      This video cannot be moved up.: Den här videon kan inte flyttas upp.\n      There was a problem with removing this video: Det uppstod ett problem med att ta bort den här videon\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Den här spellistan används nu för snabbokmärke istället för {oldPlaylistName}. Klicka här för att ångra\n      This playlist is now used for quick bookmark: Den här spellistan används nu för snabbokmärke\n      Reverted to use {oldPlaylistName} for quick bookmark: Återgått till att använda {oldPlaylistName} för snabbokmärke\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Vissa videor i spellistan är inte inlästa ännu. Klicka här för att kopiera ändå.\n      Playlist name cannot be empty. Please input a name.: Spellistans namn får inte vara tomt. Ange ett namn.\n      Playlist has been updated.: Spellistan har uppdaterats.\n      There was an issue with updating this playlist.: Det uppstod ett problem med uppdateringen av den här spellistan.\n      This playlist is protected and cannot be removed.: Den här spellistan är skyddad och kan inte tas bort.\n      Playlist {playlistName} has been deleted.: Spellistan {playlistName} har tagits bort.\n      This playlist does not exist: Den här spellistan finns inte\n      This video cannot be moved down.: Den här videon kan inte flyttas nedåt.\n      Video has been removed. Click here to undo.: Videon har tagits bort. Klicka här för att ångra.\n      This playlist has a video with a duration error: Den här spellistan innehåller minst en video som inte har någon varaktighet, den sorteras som om deras varaktighet är noll.\n      This playlist is already being used for quick bookmark.: Den här spellistan används redan för snabbbokmärken.\n    Search for Videos: Sök efter videor\n  Playlists with Matching Videos: Spellistor med passande videor\n  Enable Quick Bookmark With This Playlist: Aktivera snabbokmärke med den här spellistan\n  Remove Watched Videos: Ta bort sedda videor\n  CreatePlaylistPrompt:\n    Create: Skapa\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: Det finns redan en spellista med detta namn. Välj ett annat namn.\n      There was an issue with creating the playlist.: Det uppstod ett problem med skapandet av spellistan.\n      Playlist {playlistName} has been successfully created.: Spellistan {playlistName} har skapats med framgång.\n    New Playlist Name: Nytt spellistanamn\n  The playlist has been successfully exported: Spellistan har exporterats\n  Export Playlist: Exportera denna spellista\n  Quick Bookmark Enabled: Snabbokmärke aktiverat\n  TotalTimePlaylist: 'Total tid: {duration}'\n  Remove Duplicate Videos: Ta bort dubbletter av videor\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Är du säker på att du vill ta bort 1 dubblettvideo från den här spellistan? Detta kan inte ångras. | Är du säker på att du vill ta bort {playlistItemCount} dubblettvideor från den här spellistan? Detta kan inte ångras.\n  Cannot delete the quick bookmark target playlist.: Det går inte att ta bort målspellistan för snabbokmärken.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Är du säker på att du vill ta bort 1 sedd video från den här spellistan? Detta kan inte ångras. | Är du säker på att du vill ta bort {playlistItemCount} sedda videor från den här spellistan? Detta kan inte ångras.\n  Export list of URLs: Exportera lista med URL:er\nHistory:\n  # On History Page\n  History: 'Historik'\n  Watch History: 'Visningshistorik'\n  Your history list is currently empty.: 'Historiken är för närvarande tom.'\n  Empty Search Message: Det finns inga videor i din historik som matchar din sökning\n  Search bar placeholder: Sök i historiken\n  Case Sensitive Search: Skiftlägeskänslig Sökning\n  DateOldestHistory: Datum sedda (äldst)\n  DateNewestHistory: Datum sedda (nyast)\nSettings:\n  # On Settings Page\n  Settings: 'Inställningar'\n  General Settings:\n    General Settings: 'Allmänt'\n    Check for Updates: 'Sök efter uppdateringar'\n    Check for Latest Blog Posts: 'Sök efter de senaste blogginläggen'\n    Fallback to Non-Preferred Backend on Failure: 'Falla tillbaka till icke-föredragen Backend vid felet'\n    Enable Search Suggestions: 'Aktivera sökförslag'\n    Default Landing Page: 'Standardsida'\n    Locale Preference: 'Språk'\n    Preferred API Backend:\n      Preferred API Backend: 'Föredragen API-backend'\n      Local API: 'Lokalt API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Video visningtypen'\n      Grid: 'Rutnät'\n      List: 'Lista'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Miniatyrinställning'\n      Default: 'Standard'\n      Beginning: 'Början'\n      Middle: 'Mitten'\n      End: 'Slutet'\n      Hidden: Dold\n      Blur: Oskärpa\n    Region for Trending: 'Region för trender'\n        #! List countries\n    View all Invidious instance information: Visa all Invidious-instansinformation\n    System Default: Standardinställningar\n    Clear Default Instance: Rensa standardinstansen\n    Set Current Instance as Default: Välj den nuvarande instansen som standard\n    Current instance will be randomized on startup: Instansen kommer att väljas slumpmässigt vid start\n    No default instance has been set: Ingen standardinstans är vald\n    The currently set default instance is {instance}: Den nuvarande aktiva instansen är {instance}\n    Current Invidious Instance: Aktiv Invidious-instans\n    External Link Handling:\n      No Action: Ingen åtgärd\n      Ask Before Opening Link: Fråga innan du öppnar länk\n      Open Link: Öppna länk\n      External Link Handling: Hantering av extern länk\n    Auto Load Next Page:\n      Tooltip: Ladda ytterligare sidor och kommentarer automatiskt.\n      Label: Ladda Nästa Sida Automatiskt\n    Open Deep Links In New Window: Öppna URL:er som skickats till FreeTube i ett nytt fönster\n    Minimize to system tray: Minimera till systemfältet\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Matcha toppfältet med huvudfärgen'\n    Base Theme:\n      Base Theme: 'Grundtema'\n      Black: 'Svart'\n      Dark: 'Mörkt'\n      Light: 'Ljust'\n      Dracula: 'Dracula'\n      System Default: Systemstandard\n      Catppuccin Mocha: Catppuccin Mocha\n      Hot Pink: Het Rosa\n      Pastel Pink: Pastell Rosa\n      Solarized Dark: Solarized mörk\n      Nordic: Nordisk\n      Everforest Dark Hard: Everforest mörk stark\n      Gruvbox Dark: Gruvbox mörk\n      Gruvbox Light: Gruvbox ljus\n      Solarized Light: Solarized ljus\n      Everforest Dark Medium: Everforest mörk medium\n      Everforest Dark Low: Everforest mörk låg\n      Everforest Light Hard: Everforest ljus svår\n      Everforest Light Medium: Everforest ljus medium\n      Everforest Light Low: Everforest ljus låg\n      Catppuccin Frappe: Catppuccin Frappe\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Huvudfärg'\n      Red: 'Röd'\n      Pink: 'Rosa'\n      Purple: 'Lila'\n      Deep Purple: 'Mörklila'\n      Indigo: 'Indigo'\n      Blue: 'Blå'\n      Light Blue: 'Ljusblå'\n      Cyan: 'Cyangrön'\n      Teal: 'Turkos'\n      Green: 'Grön'\n      Light Green: 'Ljusgrön'\n      Lime: 'Limegrön'\n      Yellow: 'Gul'\n      Amber: 'Bärnsten'\n      Orange: 'Brandgul'\n      Deep Orange: 'Djup Orange'\n      Dracula Cyan: 'Dracula cyangrön'\n      Dracula Green: 'Dracula grön'\n      Dracula Orange: 'Dracula orange'\n      Dracula Pink: 'Dracula rosa'\n      Dracula Purple: 'Dracula lila'\n      Dracula Red: 'Dracula röd'\n      Dracula Yellow: 'Dracula gul'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha rosenvatten\n      Catppuccin Mocha Flamingo: Catppuccin Mocha flamingo\n      Catppuccin Mocha Pink: Catppuccin Mocha rosa\n      Catppuccin Mocha Mauve: Catppuccin Mocha malva\n      Catppuccin Mocha Red: Catppuccin Mocha röd\n      Catppuccin Mocha Maroon: Catppuccin Mocha rödbrun\n      Catppuccin Mocha Peach: Catppuccin Mocha persika\n      Catppuccin Mocha Yellow: Catppuccin Mocha gul\n      Catppuccin Mocha Green: Catppuccin Mocha grön\n      Catppuccin Mocha Sapphire: Catppuccin Mocha safir\n      Catppuccin Mocha Lavender: Catppuccin Mocha lavender\n      Catppuccin Mocha Blue: Catppuccin Mocha blå\n      Catppuccin Mocha Teal: Catppuccin Mocha turkos\n      Catppuccin Mocha Sky: Catppuccin Mocha himmel\n      Catppuccin Frappe Mauve: Catppuccin Frappe malva\n      Catppuccin Frappe Red: Catppuccin Frappe röd\n      Catppuccin Frappe Blue: Catppuccin Frappe blå\n      Catppuccin Frappe Lavender: Catppuccin Frappe lavendel\n      Solarized Cyan: Solariserad cyangrön\n      Solarized Red: Solariserad röd\n      Gruvbox Dark Green: Gruvbox mörkgrön\n      Gruvbox Dark Yellow: Gruvbox mörkgul\n      Gruvbox Dark Orange: Gruvbox mörkorange\n      Solarized Blue: Solariserad blå\n      Gruvbox Dark Purple: Gruvbox mörklila\n      Gruvbox Light Purple: Gruvbox ljuslila\n      Everforest Light Blue: Everforest ljusblå\n      Everforest Light Purple: Everforest ljuslila\n      Catppuccin Frappe Rosewater: Catppuccin Frappe rosenvatten\n      Catppuccin Frappe Flamingo: Catppuccin Frappe flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe rosa\n      Catppuccin Frappe Sky: Catppuccin Frappe himmel\n      Catppuccin Frappe Sapphire: Catppuccin Frappe safir\n      Catppuccin Frappe Yellow: Catppuccin Frappe gul\n      Catppuccin Frappe Green: Catppuccin Frappe grön\n      Catppuccin Frappe Teal: Catppuccin Frappe turkos\n      Gruvbox Dark Blue: Gruvbox mörkblå\n      Gruvbox Light Red: Gruvbox ljusröd\n      Gruvbox Light Blue: Gruvbox ljusblå\n      Catppuccin Frappe Maroon: Catppuccin Frappe rödbrun\n      Catppuccin Frappe Peach: Catppuccin Frappe persika\n      Gruvbox Light Orange: Gruvbox ljusorange\n      Solarized Yellow: Solariserad gul\n      Solarized Magenta: Solariserad magenta\n      Solarized Green: Solariserad grön\n      Everforest Dark Red: Everforest mörkröd\n      Everforest Dark Yellow: Everforest mörkgul\n      Everforest Dark Green: Everforest mörkgrön\n      Everforest Dark Blue: Everforest mörkblå\n      Everforest Dark Purple: Everforest mörklila\n      Everforest Light Red: Everforest ljusröd\n      Everforest Light Green: Everforest ljusgrön\n      Everforest Light Aqua: Everforest ljusakva\n      Everforest Light Yellow: Everforest ljusgul\n      Gruvbox Dark Aqua: Gruvbox mörkakva\n      Solarized Orange: Solariserad orange\n      Everforest Dark Aqua: Everforest mörkakva\n      Solarized Violet: Solariserad violett\n      Everforest Dark Orange: Everforest mörkorange\n      Everforest Light Orange: Everforest ljusorange\n      Catppuccin Latte Red: Catppuccin Latte Röd\n      Catppuccin Latte Mauve: Catppuccin Latte Malva\n    Secondary Color Theme: 'Sekundärfärg'\n        #* Main Color Theme\n    UI Scale: Skala för användargränssnitt\n    Expand Side Bar by Default: Expandera sidpanelen som standard\n    Disable Smooth Scrolling: Inaktivera mjuk rullning\n    Hide Side Bar Labels: Dölj etiketter i sidpanelen\n    Hide FreeTube Header Logo: Dölj FreeTube-sidhuvudlogotypen\n  Player Settings:\n    Player Settings: 'Spelare'\n    Play Next Video: 'Autospela Rekommenderade Videor'\n    Turn on Subtitles by Default: 'Aktivera undertexter som standard'\n    Autoplay Videos: 'Starta Videor Automatiskt'\n    Proxy Videos Through Invidious: 'Proxyvideor via Invidious'\n    Autoplay Playlists: 'Spela upp videor i spellistan automatiskt'\n    Enable Theatre Mode by Default: 'Aktivera Bioläge som standard'\n    Default Volume: 'Standardvolym'\n    Default Playback Rate: 'Standard uppspelningshastighet'\n    Default Video Format:\n      Default Video Format: 'Standard videoformat'\n      Dash Formats: 'DASH-format'\n      Legacy Formats: 'Äldre format'\n      Audio Formats: 'Ljudformat'\n    Default Quality:\n      Default Quality: 'Standardkvalitet'\n      Auto: 'Automatisk'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Autospela Nedräkningstimer\n    Display Play Button In Video Player: Visa uppspelningsknappen i videospelaren\n    Scroll Volume Over Video Player: Rullvolym i videospelaren\n    Fast-Forward / Rewind Interval: Spola fram / spola bak intervall\n    Screenshot:\n      File Name Label: Filnamnsformat\n      Enable: Aktivera skärmdump\n      Error:\n        Empty File Name: Tomt filnamn\n        Forbidden Characters: Förbjudna symboler\n      Ask Path: Fråga efter sparmapp\n      Folder Label: Skärmdumpsmapp\n      Quality Label: Skärmdumpskvalité\n      Format Label: Skärmdumpsformat\n      File Name Tooltip: Du kan använda variablerna nedan. %Y År 4 siffror. %M Månad 2 siffror. %D Dag 2 siffror. %H Timme 2 siffror. %N Minut 2 siffror. %S Sekund 2 siffror. %T Millisekund 3 siffror. %s Video Sekund. %t Video Millisekund 3 siffror. %i Video ID.\n      Folder Button: Välj mapp\n    Skip by Scrolling Over Video Player: Hoppa över genom att skrolla över videospelaren\n    Max Video Playback Rate: Maximal uppspelningshastighet\n    Video Playback Rate Interval: Uppspelningshastighetsintervall\n    Scroll Playback Rate Over Video Player: Skrolla uppspelningshastighet över videospelaren\n    Enter Fullscreen on Display Rotate: Fullskärm vid skärmrotation\n    Default Viewing Mode:\n      Default Viewing Mode: Standardvisningsläge\n      Theater: Teater\n      Picture in Picture: Bild i Bild\n      Full Screen: Helskärm\n      External Player: Extern Spelare ({externalPlayerName})\n    Autoplay Interruption Timer: Autoplay Avbrottstimer\n  Privacy Settings:\n    Privacy Settings: 'Integritet'\n    Remember History: 'Kom ihåg visningshistorik'\n    Save Watched Progress: 'Spara visningsframsteg'\n    Clear Search Cache: 'Rensa sökcache'\n    Are you sure you want to clear out your search cache?: 'Vill du verkligen rensa din sökcache?'\n    Search cache has been cleared: 'Sök cachen har blivit rensad'\n    Remove Watch History: 'Rensa hela visningshistoriken'\n    Are you sure you want to remove your entire watch history?: 'Vill du verkligen rensa hela visningshistoriken?'\n    Watch history has been cleared: 'Visningshistoriken är rensad'\n    Remove All Subscriptions / Profiles: 'Ta bort alla prenumerationer / profiler'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Vill du verkligen ta bort alla prenumerationer och profiler?  Detta kan inte ångras.'\n    Save Watched Videos With Last Viewed Playlist: Spara visade videor med senast visade spellista\n    Remember Search History: Kom ihåg sökhistorik\n    Clear Search History and Cache: Rensa sökhistorik och cache\n    All playlists have been removed: Alla spellistor har tagits bort\n    Are you sure you want to remove all your playlists?: Är du säker på att du vill ta bort alla dina spellistor?\n    Search history and cache have been cleared: Sökhistorik och cache har rensats\n    Remove All Playlists: Ta bort alla spellistor\n    Are you sure you want to clear out your search history and cache?: Är du säker på att du vill rensa din sökhistorik och cache?\n    Watched Progress Saving Mode:\n      Tooltip: Automatiskt = Sparar vid varje avslut av en videosida, när videon avslutas och vid fel (t.ex. hastighetsbegränsning eller utgången tittarsession). Semiautomatiskt = Som automatiskt, förutom vid avslut av videosida. Framsteg kan sparas manuellt via en knapp som heter Spara tittade framsteg, placerad under videospelaren.\n      Modes:\n        Semi-auto: Semiautomatiskt\n        Auto: Automatiskt\n        Never: Aldrig\n  Subscription Settings:\n    Subscription Settings: 'Prenumeration'\n    Fetch Feeds from RSS: 'Hämta flöden från RSS'\n    Fetch Automatically: Hämta flödet automatiskt\n    'Limit the number of videos displayed for each channel': Begränsa antalet videor som visas för varje kanal\n    To: Till\n    Confirm Before Unsubscribing: Bekräfta innan du avslutar prenumerationen\n  Data Settings:\n    Data Settings: 'Data'\n    Select Export Type: 'Välj export-typen'\n    Import Subscriptions: 'Importera prenumerationer'\n    Export Subscriptions: 'Exportera prenumerationer'\n    Export FreeTube: 'Exportera FreeTube'\n    Export YouTube: 'Exportera YouTube'\n    Export NewPipe: 'Exportera NewPipe'\n    Import History: 'Importera historik'\n    Export History: 'Exportera historik'\n    Profile object has insufficient data, skipping item: 'Profilobjekt har otillräckliga data, hoppar över objekt'\n    All subscriptions and profiles have been successfully imported: 'Alla prenumerationer och profiler har importerats'\n    All subscriptions have been successfully imported: 'Alla prenumerationer har importerats'\n    Invalid subscriptions file: 'Ogiltigt prenumerationsarkiv'\n    Invalid history file: 'Ogiltigt historikarkiv'\n    Subscriptions have been successfully exported: 'Alla prenumerationer har exporterats'\n    History object has insufficient data, skipping item: 'Historikarkivet har otillräcklig data, objektet utelämnas'\n    All watched history has been successfully imported: 'Hela visningshistoriken har importerats'\n    All watched history has been successfully exported: 'Hela visningshistoriken har exporterats'\n    Unable to read file: 'Kan inte läsa arkivet'\n    Unable to write file: 'Kunde inte skriva filen'\n    Unknown data key: 'Okänd datanyckel'\n    How do I import my subscriptions?: 'Hur importerar jag mina prenumerationer?'\n    Manage Subscriptions: Hantera prenumerationer\n    History File: Historikfil\n    Subscription File: Prenumerationsfil\n    Playlist File: Spellistefil\n    Export Playlists: Exportera spellistor\n    All playlists has been successfully imported: Alla spellistor har importerats\n    All playlists has been successfully exported: Alla spellistor har exporterats\n    Import Playlists: Importera spellistor\n    Playlist insufficient data: Otillräcklig data för \"{playlist}\" spellista, hoppar över objekt\n\n    Export Playlists For Older FreeTube Versions:\n      Label: Exportera spellistor för äldre versioner av FreeTube\n      Tooltip: \"Det här alternativet exporterar videor från alla spellistor till en spellista med namnet \\\"Favoriter\\\".\\nSå här exporterar och importerar du videor i spellistor för en äldre version av FreeTube:\\n1. Exportera dina spellistor med det här alternativet aktiverat.\\n2. Ta bort alla dina befintliga spellistor med alternativet Ta bort alla spellistor under Sekretessinställningar.\\n3. Starta den äldre versionen av FreeTube och importera de exporterade spellistorna.\\\"\"\n    Search history file: Sökhistorikfil\n    Search history: Sökhistorik\n    Import search history: Importera sökhistorik\n    Export search history: Exportera sökhistorik\n    All search history has been successfully imported: All sökhistorik har importerats\n    All search history has been successfully exported: All sökhistorik har exporterats\n  Distraction Free Settings:\n    Hide Live Chat: Dölj livechatt\n    Hide Popular Videos: Dölj mest populära\n    Hide Trending Videos: Dölj trendiga videor\n    Hide Recommended Videos: Dölj rekommenderade videor\n    Hide Comment Likes: Dölj kommentargillamarkeringar\n    Hide Video Likes And Dislikes: Dölj gilla- och ogillamarkeringar för videor\n    Hide Channel Subscribers: Dölj kanalprenumeranter\n    Hide Video Views: Dölj videovisningar\n    Distraction Free Settings: Distraktionsfri\n    Hide Active Subscriptions: Dölj aktiva prenumerationer\n    Hide Playlists: Dölj spellistor\n    Hide Comments: Dölj kommentarer\n    Hide Chapters: Dölj kapitel\n    Hide Channels: Dölj videor från kanaler\n    Hide Video Description: Dölj videobeskrivning\n    Hide Sharing Actions: Dölj delningsåtgärder\n    Hide Videos on Watch: 'Dölj videor under visning'\n    Hide Live Streams: Dölj liveströmningar\n    Hide Upcoming Premieres: Dölj kommande premiärer\n    Display Titles Without Excessive Capitalisation: Visa titlar utan överdriven användning av versaler och interpunktion\n    Hide Channels Placeholder: Kanal-ID\n    Hide Featured Channels: Dölj utvalda kanaler\n    Hide Channel Shorts: Dölj kanalfliken \"Shorts\"\n    Sections:\n      Side Bar: Sidpanel\n      General: Allmänt\n      Channel Page: Kanalsida\n      Watch Page: Visningssida\n      Subscriptions Page: Prenumerationssida\n    Hide Channel Playlists: Dölj kanalfliken \"Spellistor\"\n    Hide Channel Podcasts: Dölj kanalfliken \"Poddsändningar\"\n    Hide Channel Releases: Dölj kanalfliken \"Utgåvor\"\n    Hide Subscriptions Videos: Dölj prenumerationsvideor\n    Hide Subscriptions Shorts: Dölj prenumerationsshorts\n    Hide Subscriptions Live: Dölj prenumerationer live-sändningar\n    Hide Profile Pictures in Comments: Dölj profilbilder i kommentarer\n    Hide Channels Invalid: Det angivna kanal-ID:t var ogiltigt\n    Hide Channels Disabled Message: Vissa kanaler blockerades med ID och bearbetades inte. Funktionen är blockerad medan dessa ID:n uppdateras\n    Hide Channels Already Exists: Kanal-ID finns redan\n    Hide Channels API Error: Fel vid hämtning av användaren med det angivna ID:t. Kontrollera igen om ID:t är korrekt.\n    Hide Videos, Playlists and Channels Containing Text: Dölj videor och spellistor som innehåller text\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Ord, ordfragment eller fras\n    Hide Channel Courses: Dölj kanalfliken \"Kurser\"\n    Hide Channel Home: Dölj kanalfliken \"Hem\"\n    Show Added Items: Visa tillagda objekt\n    Hide Subscriptions Posts: Dölj prenumerationsinlägg\n    Hide Channel Posts: Dölj kanalfliken \"Inlägg\"\n  The app needs to restart for changes to take effect. Restart and apply change?: Appen måste startas om för att ändringarna ska träda i kraft. Starta om och tillämpa ändringen?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Fel uppstod vid hämtning av nätverksinformationen. Är din proxy korrekt konfigurerad?\n    City: Stad\n    Region: Område\n    Country: Land\n    Ip: IP\n    Your Info: Din info\n    Test Proxy: Testa proxy\n    Clicking on Test Proxy will send a request to: Om du klickar på TestProxy skickas en begäran till\n    Proxy Port Number: Proxy-portnummer\n    Proxy Host: Proxyvärd\n    Proxy Protocol: Proxy-protokoll\n    Enable Tor / Proxy: Aktivera Tor / Proxy\n    Proxy Settings: Proxy\n    Proxy Warning: FreeTube har ingen inbyggd proxy men kan ansluta till en extern proxy, till exempel en som körs på din maskin som Tor eller en extern proxy, såsom en SOCKS5 proxy som tillhandahålls av vissa VPN. Om den är aktiverad, se till att din proxy/Tor är korrekt konfigurerad, annars kommer FreeTube inte att kunna hämta någon data.\n    Proxy Username: Proxy användarnamn\n    Proxy Password: Proxy lösenord\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Notifikation när sponsorsegmentet är åsidosatt\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API-URL (standard är https://sponsor.ajay.app)\n    Enable SponsorBlock: Använd sponsorblockering (SponsorBlock)\n    SponsorBlock Settings: Sponsorblockering\n    Skip Options:\n      Skip Option: Hoppa över-alternativ\n      Show In Seek Bar: Visa i sökpanelen\n      Do Nothing: Gör ingenting\n      Auto Skip: Hoppa över automatiskt\n      Prompt To Skip: Prompt för att hoppa över\n    Category Color: Kategorifärg\n    UseDeArrowTitles: Använd DeArrow-videotitlar\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow-miniatyrbildsgenerator API-URL (standard är https://dearrow-thumb.ajay.app)\n    UseDeArrowThumbnails: Använd DeArrow för miniatyrer\n  External Player Settings:\n    Ignore Unsupported Action Warnings: Ignorera händelsevarningar som inte stöds\n    External Player: Extern spelare\n    External Player Settings: Extern Spelare\n    Custom External Player Arguments: Anpassade externa spelargument\n    Custom External Player Executable: Anpassad extern spelare körbar\n    Players:\n      None:\n        Name: Ingen\n    Ignore Default Arguments: Ignorera standardargument\n  Parental Control Settings:\n    Hide Unsubscribe Button: Dölj knappen Avprenumerera\n    Parental Control Settings: Föräldrakontroll\n    Show Family Friendly Only: Visa endast barnvänligt innehåll\n    Hide Search Bar: Dölj sökpanel\n    Hide Uploader on Watch page: Dölj uppladdaren på visningssidan\n  Password Dialog:\n    Password: Lösenord\n    Enter Password To Unlock: Ange lösenord för att låsa upp inställningar\n  Password Settings:\n    Remove Password: Ta bort lösenord\n    Password Settings: Lösenord\n    Set Password: Välj lösenord\n    Set Password To Prevent Access: Ange lösenord för att förhindra tillgång till inställningar\n  Experimental Settings:\n    Experimental Settings: Experimentella\n    Warning: Dessa inställningar är experimentella och kan orsaka krascher när de är aktiverade. Det rekommenderas starkt att säkerhetskopiera. Användning sker på egen risk!\n    Replace HTTP Cache: Ersätt HTTP-cache\n  Return to Settings Menu: Återgå till inställningsmenyn\n  Sort Settings Sections (A-Z): Sortera inställningssektioner (A-Ö)\nAbout:\n  #On About page\n  About: 'Om'\n  #& About\n  Donate: Donera\n  these people and projects: dessa människor och projekt\n  Credits: Erkännande\n  Translate: Översätt\n  room rules: Rumsregler\n  Chat on Matrix: Chatta på Matrix\n  Mastodon: Mastodon\n  Email: E-post\n  Blog: Blogg\n  Website: Webbplats\n  Please check for duplicates before posting: Kontrollera om det finns dubbletter innan du publicerar\n  GitHub issues: GitHub-problem\n  Report a problem: Rapportera ett problem\n  FAQ: Frågor och svar\n  FreeTube Wiki: FreeTube Wiki\n  Help: Hjälp\n  GitHub releases: GitHub-utgåvor\n  Downloads / Changelog: Nedladdningar / Ändringslogg\n  Source code: Källkod\n  Beta: Beta\n  Discussions: Diskussioner\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: Licensierad under {licenseLink}\n  Please read the {roomRulesLink}: Läs {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: FreeTube möjliggörs av {creditsPageLink}\nProfile:\n  Profile Select: 'Välj profil'\n  All Channels: 'Alla kanaler'\n  Profile Manager: 'Profilhanterare'\n  Create New Profile: 'Skapa ny profil'\n  Edit Profile: 'Redigera profil'\n  Color Picker: 'Färgväljare'\n  Custom Color: 'Anpassad färg'\n  Profile Preview: 'Förhandsvisa profil'\n  Create Profile: 'Skapa profil'\n  Update Profile: 'Uppdatera profil'\n  Make Default Profile: 'Skapa standardprofil'\n  Delete Profile: 'Ta bort profil'\n  Are you sure you want to delete this profile?: 'Vill du verkligen ta bort profilen?'\n  All subscriptions will also be deleted.: 'Alla prenumerationer raderas också.'\n  Your profile name cannot be empty: 'Ditt profilnamn får inte vara tomt'\n  Profile has been created: 'Profil har skapats'\n  Profile has been updated: 'Profilen har uppdaterats'\n  Your default profile has been set to {profile}: 'Din standardprofil har ställts in på {profile}'\n  Removed {profile} from your profiles: 'Borttagen {profile} från dina profiler'\n  Your default profile has been changed to your primary profile: 'Din standardprofil har ändrats till din primära profil'\n  '{profile} is now the active profile': '{profile} är nu den aktiva profilen'\n  Subscription List: 'Prenumerationslista'\n  Other Channels: 'Andra kanaler'\n  '{number} selected': '{number} markerade'\n  Select All: 'Markera alla'\n  Select None: 'Markera ingen'\n  Delete Selected: 'Ta bort markerade'\n  Add Selected To Profile: 'Lägg till markerade i profilen'\n  No channel(s) have been selected: 'Ingen kanal(er) har markerats'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Det här är din primära profil.  Är du säker på att du vill ta bort de valda kanalerna?  Samma kanaler kommer att tas bort i alla profiler där de finns.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Är du säker på att du vill ta bort de markerade kanalerna?   Detta tar inte bort kanalen från någon annan profil.'\n#On Channel Page\n  Profile Filter: Profilfilter\n  Profile Settings: Profil\n  Toggle Profile List: Aktivera profillista\n  Open Profile Dropdown: Öppna profilrullgardinsmenyn\n  Close Profile Dropdown: Stäng profilrullgardinsmenyn\n  Profile Name: Profilnamn\n  Edit Profile Name: Redigera profilnamn\n  Create Profile Name: Skapa profilnamn\nChannel:\n  Subscribe: 'Prenumerera'\n  Unsubscribe: 'Avsluta prenumeration'\n  Channel has been removed from your subscriptions: 'Kanalen har tagits bort från dina prenumerationer'\n  Removed subscription from {count} other channel(s): 'Borttagen prenumeration från {count} annan kanal(er)'\n  Added channel to your subscriptions: 'Kanal tillagd i dina prenumerationer'\n  Search Channel: 'Sök i kanal'\n  Your search results have returned 0 results: 'Din sökning gav inget resultat'\n  Videos:\n    Videos: 'Videor'\n    This channel does not currently have any videos: 'Den här kanalen har för närvarande inga videor'\n    Sort Types:\n      Newest: 'Nyaste'\n      Oldest: 'Äldsta'\n      Most Popular: 'Mest populära'\n  Playlists:\n    Playlists: 'Spellistor'\n    This channel does not currently have any playlists: 'Den här kanalen har för närvarande inga spellistor'\n    Sort Types:\n      Last Video Added: 'Senaste video tillagd'\n      Newest: 'Nyaste'\n      Oldest: 'Äldsta'\n  About:\n    About: 'Om'\n    Channel Description: 'Kanalbeskrivning'\n    Featured Channels: 'Utvalda kanaler'\n    Tags:\n      Tags: Taggar\n      Search for: Sök efter ”{tag}”\n    Details: Detaljer\n    Joined: Gick med\n    Location: Plats\n  This channel does not exist: Denna kanalen finns inte\n  This channel does not allow searching: Denna kanalen tillåter inte sökning\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Denna kanalen är ålderbegränsad och kan inte ses i FreeTube.\n  Channel Tabs: Kanalflikar\n  Posts:\n    This channel currently does not have any posts: Denna kanal har för närvarande inga inlägg\n    votes: '{votes} röster'\n    Reveal Answers: Avslöja svar\n    Hide Answers: Dölj svar\n    View Full Post: Visa hela inlägget\n    Video hidden by FreeTube: Video dold av FreeTube\n    Viewing Posts Only Supported By Invidious: Visa Inlägg stöds endast av Invidious. Gå till en kanals community-flik för att se innehåll där utan Invidious.\n  Shorts:\n    This channel does not currently have any shorts: Den här kanalen har för närvarande inga shorts\n  Live:\n    Live: Live\n    This channel does not currently have any live streams: Den här kanalen har för närvarande inga liveströmmar\n  Releases:\n    Releases: Släpp\n    This channel does not currently have any releases: Den här kanalen har för närvarande inga släpp\n  Podcasts:\n    Podcasts: Poddsändningar\n    This channel does not currently have any podcasts: Den här kanalen har inga poddsändningar\n  Courses:\n    This channel does not currently have any courses: Den här kanalen har för närvarande inga kurser\n    Courses: Kurser\n  Home:\n    Home: Hem\n    View Playlist: Visa spellista\nVideo:\n  Mark As Watched: 'Markera som sedd'\n  Remove From History: 'Ta bort från historik'\n  Video has been marked as watched: 'Videon har markerats som sedd'\n  Video has been removed from your history: 'Videon har tagits bort från din visningshistorik'\n  Open in YouTube: 'Öppna på YouTube'\n  Copy YouTube Link: 'Kopiera YouTube-länk'\n  Open YouTube Embedded Player: 'Öppna YouTubes inbäddade spelare'\n  Copy YouTube Embedded Player Link: 'Kopiera länken till den inbäddade YouTube-spelaren'\n  Open in Invidious: 'Öppna på Invidious'\n  Copy Invidious Link: 'Kopiera Invidious-länk'\n  Views: 'Visningar'\n  Loop Playlist: 'Spellistan i slinga'\n  Shuffle Playlist: 'Blanda spellista'\n  Reverse Playlist: 'Omvänd spellista'\n  Previous: 'Föregående'\n  Next: 'Nästa'\n  Watched: 'Visad'\n  Autoplay: 'Autospelning'\n  Starting soon, please refresh the page to check again: 'Börjar snart, uppdatera sidan för att kontrollera igen'\n  # As in a Live Video\n  Live: 'Live-visning'\n  Live Now: 'Live nu'\n  Live Chat: 'Livechatt'\n  Enable Live Chat: 'Aktivera livechatt'\n  Live Chat is currently not supported in this build.: 'Livechatt stöds för närvarande inte i denna version.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Livechatt är aktiverad.   Chattmeddelanden visas här när de har skickats.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Livechatt stöds för närvarande inte med Invidious API. En direktanslutning till YouTube krävs.'\n  Published:\n    In less than a minute: Mindre än en minut\n  Published on: 'Publicerad den'\n#& Videos\n  Copy Invidious Channel Link: Kopiera Invidious-kanallänk\n  Open Channel in Invidious: Öppna kanalen i Invidious\n  Copy YouTube Channel Link: Kopiera YouTube-kanallänk\n  Open Channel in YouTube: Öppna kanal i YouTube\n  Started streaming on: Började streamas på\n  Streamed on: Strömmas på\n  Video has been removed from your saved list: Videon har tagits bort från din sparade lista\n  Video has been saved: Videon har sparats\n  Save Video: Spara video\n  Sponsor Block category:\n    music offtopic: Musikfritt segment\n    interaction: Interaktion\n    self-promotion: Självbefordran\n    outro: Avslut\n    intro: intro\n    sponsor: sponsor\n    recap: Sammanfattning\n    filler: Utfyllnad\n  External Player:\n    Unsupported Actions:\n      shuffling playlists: blandar spellistor\n      reversing playlists: vända spellistor\n      opening specific video in a playlist (falling back to opening the video): öppna specifik video i en spellista (faller tillbaka till att öppna videon)\n      opening playlists: öppnar spellistor\n      setting a playback rate: ställer in en uppspelningshastighet\n      starting video at offset: startar video vid offset\n      looping playlists: Spellistor i slinga\n    UnsupportedActionTemplate: '{externalPlayer} stöder inte :{action}'\n    OpeningTemplate: Öppnar {videoOrPlaylist} i {externalPlayer}...\n    playlist: spellista\n    video: video\n    OpenInTemplate: Öppna i {externalPlayer}\n  Premieres: Premiärer\n  Upcoming: Kommande\n  Show Super Chat Comment: Visa Superchatt-kommentar\n  Scroll to Bottom: Skrolla till botten\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Livechatt är inte tillgängligt för den här strömmen. Den kan ha inaktiverats av uppladdaren.\n  Unhide Channel: Visa kanal\n  Hide Channel: Dölj kanal\n#& Playlists\n  Player:\n    Full Window: Helt Fönster\n    Exit Full Window: Stäng Hela Fönstret\n    Stats:\n      CodecAudio: 'Kodek: {audioCodec} ({audioItag})'\n      Media Formats: 'Mediaformat: {formats}'\n      Video ID: 'Video ID: {videoId}'\n      Player Dimensions: 'Spelarmått: {width}x{height}'\n      Bandwidth: 'Bandbredd: {bandwidth} kbps'\n      Buffered: 'Buffrad: {bufferedPercentage} %'\n      CodecsVideoAudioNoItags: 'Kodekar: {videoCodec} / {audioCodec}'\n      Resolution: 'Upplösning: {width}x{height}{''@''}{frameRate}'\n      Stats: Statistik\n      Bitrate: 'Bithastighet: {bitrate} kbps'\n      Volume: 'Volym: {volumePercentage}%'\n      CodecsVideoAudio: 'Kodekar: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Dropped Frames / Total Frames: 'Bildrutefall: {droppedFrames} / Totalt antal bildrutor: {totalFrames}'\n    Hide Stats: Dölj statistik\n    You appear to be offline: Du verkar vara frånkopplad.\n    Playback will resume automatically when your connection comes back: Uppspelningen återupptas automatiskt när din anslutning kommer tillbaka.\n    Skipped segment: Hoppade över {segmentCategory} segmentet\n    Audio Tracks: Ljudspår\n    Autoplay is off: Autouppspelning är avstängd\n    Autoplay is on: Autouppspelning är på\n    Theatre Mode: Teaterläge\n    Exit Theatre Mode: Avsluta Teaterläget\n    Take Screenshot: Ta Skärmdump\n    Show Stats: Visa statistik\n    TranslatedCaptionTemplate: '{language} (översatt från \"{originalLanguage}\")'\n  More Options: Fler Alternativ\n  AgeRestricted: Åldersbegränsade videor kan inte ses med FreeTube eftersom de kräver Google-inloggning och användning av ett åldersverifierat YouTube-konto.\n  IP block: YouTube har blockerat din IP-adress från att titta på videor. Försök att byta till en annan VPN eller proxy.\n  DRMProtected: DRM-skyddade videor kan inte spelas upp i FreeTube, eftersom de kräver proprietära, slutna källkodskomponenter. Om du vill titta på den här videon, se den på den officiella YouTube-webbplatsen i en DRM-aktiverad webbläsare.\n  DeArrow:\n    Show Original Details: Visa originaldetaljer\n    Show Modified Details: Visa ändrade detaljer\n  Unlisted: Olistade\n  MembersOnly: Videoklipp endast för medlemmar kan inte ses med FreeTube eftersom de kräver Google-inloggning och betalmedlemskap till uppladdarens kanal.\n  Watched Progress Saved: Tittade framsteg sparade\n  Save Watched Progress: Spara tittade framsteg\n  Popout Live Chat: Popout-chatt\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Återstående tid före annonsstart: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Återstående SABR-återställningstid: {remindingTimeSeconds}s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Visa hela spellistan'\n  Last Updated On: 'Senast uppdaterad den'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Spellista\n  Sort By:\n    AuthorAscending: Upphovsman (A-Ö)\n    VideoDurationDescending: Varaktighet (längst)\n    AuthorDescending: Upphovsman (Ö-A)\n    VideoDurationAscending: Varaktighet (kortast)\n    DateAddedOldest: Datum tillagd (äldst)\n    VideoTitleAscending: Titel (A-Ö)\n    VideoTitleDescending: Titel (Ö-A)\n    DateAddedNewest: Datum tillagd (nyast)\n    PublishedNewest: Datum publicerad (nyast)\n    PublishedOldest: Datum publicerad (äldst)\n    Custom: Anpassad\nChange Format:\n  Change Media Formats: 'Ändra videoformat'\n  Use Dash Formats: 'Använd DASH-format'\n  Use Legacy Formats: 'Använd äldre format'\n  Use Audio Formats: 'Endast ljud'\n  Dash formats are not available for this video: 'DASH-format är inte tillgängliga för den här videon'\n  Audio formats are not available for this video: 'Ljudformat är inte tillgängliga för den här videon'\n  Legacy formats are not available for this video: Äldre format är inte tillgängliga för den här videon\nShare:\n  Share Video: 'Dela video'\n  Share Playlist: 'Dela spellista'\n  Include Timestamp: 'Inkludera tidsstämpel'\n  Copy Link: 'Kopiera länk'\n  Open Link: 'Öppna länk'\n  Copy Embed: 'Kopiera inbäddad'\n  Open Embed: 'Öppna inbäddad'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious-URL kopierad till urklipp'\n  Invidious Embed URL copied to clipboard: 'Invidious-inbäddnings-URL kopierad till urklipp'\n  YouTube URL copied to clipboard: 'Youtube-URL kopierad till urklipp'\n  YouTube Embed URL copied to clipboard: 'YouTube-inbäddnings-URL kopierad till urklipp'\n  YouTube Channel URL copied to clipboard: YouTube-kanalens URL kopierad till urklipp\n  Invidious Channel URL copied to clipboard: Invidious kanal-URL kopierad till urklipp\n  Share Channel: Dela Kanal\n  Share Post: Dela inlägg\nMini Player: 'Minispelare'\nComments:\n  Comments: 'Kommentarer'\n  Click to View Comments: 'Klicka för att visa kommentarer'\n  Getting comment replies, please wait: 'Tar emot svar på kommentarer, vänta'\n  There are no more comments for this video: 'Det finns inga fler kommentarer för videon'\n  Hide Comments: 'Dölj kommentarer'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Det finns inga kommentarer tillgängliga för videon'\n  Load More Comments: 'Fler kommentarer'\n  Newest first: Nyaste först\n  Top comments: Toppkommentarer\n  Show More Replies: Visa fler svar\n  Member: Medlem\n  View {replyCount} replies: Visa 1 svar | Visa {replyCount} svar\n  Pinned by: Nålad av\n  Hearted: Hjärtade\n  Subscribed: Prenumererar\n  There are no comments available for this post: Det finns inga kommentarer tillgängliga för detta inlägg\n  Hide {replyCount} replies: Dölj 1 svar | Dölj {replyCount} svar\n  View 1 reply from {channelName}: Visa 1 svar från {channelName}\n  View {replyCount} replies from {channelName} and others: Visa {replyCount} svar från {channelName} och andra\nUp Next: 'Kommer härnäst'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Lokalt API-fel (Klicka för att kopiera koden)'\nInvidious API Error (Click to copy): 'Invidious API-fel (klicka för att kopiera)'\nFalling back to Invidious API: 'Faller tillbaka till Invidious API'\nFalling back to Local API: 'Faller tillbaka till lokal API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Den här videon är inte tillgänglig på grund av format som saknas. Detta kan hända på grund av landets otillgänglighet.'\nLoop is now disabled: 'Slinga är nu inaktiverad'\nLoop is now enabled: 'Slinga är nu aktiverad'\nShuffle is now disabled: 'Blandning är nu inaktiverad'\nShuffle is now enabled: 'Blandning är nu aktiverad'\nThe playlist has been reversed: 'Spellistan är omvänd'\nPlaying Next Video: 'Spelar video'\nPlaying Previous Video: 'Spelar föregående video'\nCanceled next video autoplay: 'Avbröts nästa autoplay'\n'The playlist has ended. Enable loop to continue playing': 'Spellistan har avslutats.  Aktivera slinga för att fortsätta spela'\n\nYes: 'Ja'\nNo: 'Nej'\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: När det är aktiverat använder FreeTube RSS istället för standardmetoden för att hämta ditt prenumerationsflöde. RSS är snabbare och förhindrar IP-blockering, men ger inte viss information som videolängd, livestatus eller inlägg\n    Fetch Automatically: När det är aktiverat hämtar FreeTube automatiskt ditt prenumerationsflöde vid start och när ett nytt fönster öppnas.\n  Player Settings:\n    Default Video Format: Ställ in de format som används när en video spelas upp. DASH-format kan spela högre kvaliteter. Äldre format är begränsade till max 360p men använder mindre bandbredd. Ljudformat är endast ljudströmmningar.\n    Proxy Videos Through Invidious: Kommer att ansluta till Invidious för att visa videor istället för att skapa en direktanslutning till YouTube.\n    Skip by Scrolling Over Video Player: Använd scrollhjulet för att snabbspola igenom videon, MPV stil.\n    Scroll Playback Rate Over Video Player: Medan markören är över videon, håll ner Ctrl-tangenten (Kommandotangenten på Mac) och skrolla mushjulet framåt eller bakåt för att styra uppspelningshastigheten. Håll ner Ctrl-tangenten (Kommandotangenten på Mac) och vänsterklicka med musen för att snabbt återgå till standarduppspelningshastigheten (1x om den inte har ändrats i inställningarna).\n  General Settings:\n    Region for Trending: Med trenderegionen kan du välja vilket lands trendiga videor du vill ska visas.\n    Invidious Instance: Invidious-instansen som FreeTube kommer att ansluta till för API-anrop.\n    Thumbnail Preference: Alla miniatyrbilder på FreeTube kommer att ersättas med en bildruta från videon, suddig eller dold istället för standardminiatyrbilden.\n    Fallback to Non-Preferred Backend on Failure: När ditt föredragna API har ett problem, kommer FreeTube automatiskt att försöka använda ditt icke-föredragna API som reservmetod när det är aktiverat.\n    Preferred API Backend: Välj den resurs som FreeTube använder för att få fram data. Det lokala API:et är en inbyggd utdragare. Invidious API kräver en Invidious server att ansluta till.\n    External Link Handling: \"Välj standardbeteendet när en länk som inte kan öppnas i FreeTube klickas.\\nSom standard öppnar FreeTube den klickade länken i din standardwebbläsare.\\n\"\n    Open Deep Links In New Window: URL:er som skickas till FreeTube, till exempel via omdirigering av webbläsartillägg eller kommandoradsargument, öppnas i ett nytt fönster.\n  External Player Settings:\n    Custom External Player Arguments: Alla anpassade kommandoradsargument, ska skickas till den externa spelaren.\n    Ignore Warnings: Dämpa varningar för när den aktuella externa spelaren inte stöder den aktuella åtgärden (t.ex. backning av spellistor, etc.).\n    Custom External Player Executable: Som standard antar FreeTube att den valda externa spelaren kan hittas via PATH-miljövariabeln. Om det behövs kan en anpassad sökväg ställas in här.\n    External Player: Att välja en extern spelare visar en ikon för att öppna videon (spellista om den stöds) i den externa spelaren på miniatyrbilden. Varning, Invidious-inställningar påverkar inte externa videospelare.\n    DefaultCustomArgumentsTemplate: \"(Standard: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Skicka inga standardargument till den externa spelaren förutom videons URL (t.ex. uppspelningshastighet, spellista URL, etc.). Anpassade argument kommer fortfarande att föras vidare.\n  Distraction Free Settings:\n    Hide Channels: Ange ett kanal-ID för att dölja alla videor, spellistor och själva kanalen från att visas i sökningar, trender, mest populära och rekommenderade. Det angivna kanal-ID:t måste vara en fullständig matchning och är skiftlägeskänsligt.\n    Hide Subscriptions Live: Den här inställningen åsidosätts av den program omfattande \"{appWideSetting}\"-inställningen, i avsnittet \"{subsection}\" i \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Ange ett ord, ordfragment eller en fras (okänsligt för skiftlägen) för att dölja alla videor och spellistor vars originaltitlar innehåller det i hela FreeTube, exklusive endast historik, dina spellistor och videor i spellistor.\n    Hide Videos on Watch: Döljer visade videor från flikarna videor, shorts och live på sidorna prenumeration och kanal. Detta påverkar inte fliken hem på kanalsidorna\n  Experimental Settings:\n    Replace HTTP Cache: Inaktiverar Electrons diskbaserade HTTP-cache och aktiverar en anpassad bildcache i minnet. Kommer att leda till ökad RAM-användning.\n  SponsorBlock Settings:\n    UseDeArrowTitles: Ersätt videotitlar med titlar som användare har skickat in från DeArrow.\n    UseDeArrowThumbnails: Ersätt videominiatyrer med miniatyrer från DeArrow.\nMore: Mer\nOpen New Window: Öppna nytt fönster\nPlaying Next Video Interval: Spelar strax nästa video. Klicka för att stoppa. | Spelar nästa video om {nextVideoInterval} sekunder. Klicka för att stoppa. | Spelar nästa video om {nextVideoInterval} sekunder. Klicka för att stoppa.\nUnknown YouTube url type, cannot be opened in app: Okänd YouTube-URL-typ, kan inte öppnas i appen\nDefault Invidious instance has been cleared: Standard Invidious-instans har rensats\nDefault Invidious instance has been set to {instance}: Standard Invidious-instans har ställts in på {instance}\nExternal link opening has been disabled in the general settings: Öppning av externa länkar har inaktiverats i de allmänna inställningarna\nSearch Bar:\n  Clear Input: Rensa inmatning\n  Remove: Ta Bort\nAre you sure you want to open this link?: Är du säker på att du vill öppna den här länken?\nNew Window: Nytt fönster\nChannels:\n  Channels: Kanaler\n  Title: Kanallista\n  Search bar placeholder: Sök kanaler\n  Unsubscribe Prompt: Är du säker på att du vill avprenumerera från \"{channelName}\"?\n  Count: '{number} kanal(er) hittade.'\n  Empty: Din kanallista är tom.\nPreferences: Preferenser\nOk: Okej\nScreenshot Success: Sparad skärmdump\nScreenshot Error: Skärmdump misslyckades {error}\nClipboard:\n  Cannot access clipboard without a secure connection: Har inte tillgång till urklipp utan en säker anslutning\n  Copy failed: Kopiera till urklipp misslyckades\nChapters:\n  Chapters: Kapitel\n  Key Moments: Viktiga Ögonblick\nHashtag:\n  Hashtag: Hashtaggar\n  This hashtag does not currently have any videos: Den här hashtaggen har för närvarande inga videor\nChannel Hidden: '{channel} har lagts till i kanalfiltret'\nGo to page: Gå till {page}\nChannel Unhidden: '{channel} har tagits bort från kanalfiltret'\nClose Banner: Stäng bannern\nFeed:\n  Feed Last Updated: '{feedName} flödet senast uppdaterat: {date}'\n  Refresh Feed: Uppdatera {subscriptionName}\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Undertexter\n    VR180: VR180\n    360 Video: 360°\n    New: Ny\n    3D: 3D\n    8K: 8K\n    Closed Captions: Dold Bildtext\nYes, Open Link: Ja, öppna länken\nYes, Restart: Ja, starta om\nAge Restricted:\n  This video is age restricted: Den här videon är åldersbegränsad\n  This channel is age restricted: Denna kanal är åldersbegränsad\nMoments Ago: ögonblick sedan\nCancel: Avbryt\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nTag already exists: Taggen \"{tagName}\" finns redan\nTrimmed input must be at least N characters long: Trimmad inmatning måste vara minst 1 tecken lång | Trimmad inmatning måste vara minst {length} tecken lång\nDescription:\n  Expand Description: '...mer'\n  Collapse Description: Visa mindre\nYes, Delete: Ja, ta bort\nAutoplay Interruption Timer: Autouppspelningen avbröts på grund av {autoplayInterruptionIntervalHours} timmars inaktivitet\nshortcutJoinOperator: +\nshortcutLabelSeparator: ｜\nKeyboardShortcutPrompt:\n  Volume Up: Öka volymen\n  Next Chapter: Nästa kapitel\n  Small Fast Forward: Snabbspola framåt X antal sekunder baserat på snabbspolningsintervallet och aktuell videouppspelningshastighet\n  Play: Växla uppspelning/paus\n  Zoom In: Zooma in\n  Decrease Video Speed: Minska videohastigheten baserat på videouppspelningshastighetsintervall\n  Take Screenshot: Ta en skärmdump\n  Toggle Developer Tools: Växla utvecklarverktyg\n  History Forward: Gå framåt en sida\n  New Window: Skapa ett nytt fönster\n  History Backward: Gå tillbaka en sida\n  Captions: Växla bildtexter PÅ/AV\n  Stats: Visa videostatistik\n  Fullscreen: Växla helskärmsläge\n  Minimize Window: Minimera fönstret\n  Navigate to Settings: Navigera till sidan Inställningar\n  Focus Secondary Search: Fokusera på det sekundära sökfältet (om ett sådant finns)\n  Zoom Out: Zooma ut\n  Focus Search: Fokusera på sökfältet\n  Search in New Window: Sök i ett nytt fönster\n  Close Window: Stäng fönstret\n  Next Frame: Nästa bildruta (medan pausad)\n  Skip by Tenths: Hoppa igenom videon efter procentandel (3 hopp till 30 % av varaktigheten)\n  Keyboard Shortcuts: Tangentbordsgenvägar\n  Sections:\n    App:\n      General: 'App: Allmänt'\n      Situational: 'App: Situationsanpassad'\n    Video:\n      Playback: 'Video: Uppspelning'\n      General: 'Video: Allmänt'\n  Show Keyboard Shortcuts: Visa tangentbordsgenvägar\n  Large Fast Forward: Framåt 10 sekunder / Snabbspolning framåt baserat på aktuell videouppspelningshastighet\n  Increase Video Speed: Öka videohastigheten baserat på videouppspelningshastighetsintervall\n  Full Window: Växla helfönster\n  Theatre Mode: Växla teaterläge\n  Navigate to History: Navigera till sidan Historik\n  Last Frame: Föregående bildruta (medan pausad)\n  Refresh: Uppdatera flödet med det senaste innehållet\n  Mute: Växla av/på ljudet\n  Large Rewind: Spola tillbaka 10 sekunder / Spola tillbaka video baserat på aktuell videouppspelningshastighet\n  Reset Zoom: Återställ zoomnivå / Användargränssnittsskala\n  Volume Down: Minska volymen\n  Last Chapter: Sista kapitlet\n  Small Rewind: Spola tillbaka X antal sekunder baserat på återspolningsintervallet och aktuell videouppspelningshastighet\n  Picture in Picture: Växla Bild-i-Bild-läge\n  Home: Sök till början av videon\n  End: Sök till slutet av videon\n  Skip to Next Video: Hoppa till nästa video i en spellista eller nästa rekommenderade video\n  Skip to Previous Video: Hoppa till föregående video i en spellista\nSearch character limit: Sökfrågan överskrider {searchCharacterLimit} teckengränsen\nRight-click or hold to see history: Högerklicka eller håll ned för att se historik\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Plus\n  arrowdown: Nedåtpil\n  arrowleft: Vänsterpil\n  arrowright: Högerpil\n  arrowup: Uppåtpil\nCompact side navigation: Kompakt sidonavigering\nExpand side navigation: Expandera sidnavigeringen\n"
  },
  {
    "path": "static/locales/ta.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'தமிழ்'\n\n# Webkit Menu Bar\nFile: 'கோப்பு'\nNew Window: 'புதிய திரை'\nPreferences: 'விருப்பத்தேர்வுகள்'\nQuit: 'வெளியேறு'\nEdit: 'திருத்து'\nUndo: 'செயல்தவிர்'\nRedo: 'மீண்டும் செய்'\nCut: 'வெட்டு'\nCopy: 'நகலெடு'\nPaste: 'ஒட்டு'\nDelete: 'அழி'\nSelect all: 'அனைத்தையும் தேர்ந்தெடு'\nToggle Developer Tools: 'டெவலப்பர் கருவிகளை நிலைமாற்று'\nActual size: 'உண்மை அளவு'\nZoom in: 'பெரிதாக்கு'\nZoom out: 'சிறிதாக்கு'\nToggle fullscreen: 'மாற்று முழுத்திரை'\nWindow: 'சாளரம்'\nMinimize: 'குறைக்கவும்'\nClose: 'மூடு'\nBack: 'பின்'\nForward: 'முன்னோக்கி'\nOpen New Window: 'புதிய சாளரத்தைத் திறக்கவும்'\nGo to page: '{page} செல்லவும்'\nClose Banner: 'மூடு பேனர்'\n\nVersion {versionNumber} is now available!  Click for more details: 'பதிப்பு {versionNumber} இப்போது கிடைக்கிறது! மேலும் விவரங்களுக்கு சொடுக்கு செய்க'\nDownload From Site: 'தளத்திலிருந்து பதிவிறக்கவும்'\nA new blog is now available, {blogTitle}. Click to view more: 'ஒரு புதிய வலைப்பதிவு இப்போது கிடைக்கிறது, {blogTitle}. மேலும் காண சொடுக்கு செய்க'\nAre you sure you want to open this link?: 'இந்த இணைப்பை நீங்கள் திறக்க விரும்புகிறீர்களா?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'வீடியோக்கள்'\n  Shorts: 'குறுக்குகள்'\n  Live: 'நேரலை'\n  Posts: 'இடுகைகள்'\n  Sort By: 'வரிசைப்படுத்தவும்'\n  Counts:\n    Video Count: '1 வீடியோ | {count} வீடியோக்கள்'\n    Channel Count: '1 சேனல் | {count} சேனல்கள்'\n    Subscriber Count: '1 சந்தாதாரர் | {count} சந்தாதாரர்கள்'\n    View Count: '1 பார்வை | {count} காட்சிகள்'\n    Like Count: '1 லைக் | {count} விருப்பங்கள்'\n    Comment Count: '1 கருத்து | {count} கருத்துகள்'\n    Watching Count: '1 பார்ப்பது | {count} பார்ப்பது'\n\n# Search Bar\nSearch / Go to URL: 'தேடு / முகவரி க்குச் செல்லவும்'\nSearch Bar:\n  Clear Input: 'உள்ளீட்டை அழிக்கவும்'\n  Remove: அகற்று\nSearch character limit: 'தேடல் வினவல் {searchCharacterLimit} எழுத்து வரம்புக்கு மேல் உள்ளது'\nSearch Listing:\n  Label:\n    4K: 'எச்.சி.'\n    8K: '8 கே'\n    VR180: 'VR180'\n    360 Video: '360 °'\n    Subtitles: 'வசன வரிகள்'\n    New: 'புதிய'\n    3D: '3டி'\n    # Aria labels\n    Closed Captions: 'மூடிய தலைப்புகள்'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'வடிப்பான்களைத் தேடுங்கள்'\n  Sort By:\n    Most Relevant: 'மிகவும் பொருத்தமானது'\n    Rating: 'செயல்வரம்பு'\n    Upload Date: 'பதிவேற்ற தேதி'\n    View Count: 'எண்ணிக்கை காண்க'\n  Time:\n    Time: 'நேரம்'\n    Any Time: 'எந்த நேரத்திலும்'\n    Last Hour: 'கடைசி மணி'\n    Today: 'இன்று'\n    This Week: 'இந்த வாரம்'\n    This Month: 'இந்த மாதம்'\n    This Year: 'இந்த ஆண்டு'\n  Type:\n    Type: 'வகை'\n    All Types: 'அனைத்து வகைகளும்'\n    Videos: 'வீடியோக்கள்'\n    Channels: 'சேனல்கள்'\n    Movies: 'திரைப்படங்கள்'\n    #& Playlists\n  Duration:\n    Duration: 'காலம்'\n    All Durations: 'அனைத்து காலங்களும்'\n    Short (< 4 minutes): 'குறுகிய (<4 நிமிடங்கள்)'\n    Medium (4 - 20 minutes): 'நடுத்தர (4 - 20 நிமிடங்கள்)'\n    Long (> 20 minutes): 'நீண்ட (> 20 நிமிடங்கள்)'\n  Features:\n    Features: 'நற்பொருத்தங்கள்'\n    HD: 'எச்டி'\n    Subtitles: 'வசன வரிகள்'\n    Creative Commons: 'கிரியேட்டிவ் காமன்ச்'\n    3D: '3டி'\n    Live: 'வாழ'\n    4K: 'எச்.சி.'\n    360 Video: '360 வீடியோ'\n    Location: 'இடம்'\n    HDR: 'எச்.டி.ஆர்'\n    VR180: 'VR180'\n  # On Search Page\n  Search Results: 'தேடல் முடிவுகள்'\n  Fetching results. Please wait: 'முடிவுகளைப் பெறுதல். தயவுசெய்து காத்திருங்கள்'\n  Fetch more results: 'மேலும் முடிவுகளைப் பெறுங்கள்'\n  There are no more results for this search: 'இந்த தேடலுக்கு இனி முடிவுகள் இல்லை'\n# Sidebar\n  Clear Filters: தெளிவான வடிப்பான்கள்\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'சந்தாக்கள்'\n  # channels that were likely deleted\n  Error Channels: 'பிழைகள் கொண்ட சேனல்கள்'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'இந்த சுயவிவரத்தில் அதிக எண்ணிக்கையிலான சந்தாக்கள் உள்ளன. விகிதத்தைக் கட்டுப்படுத்துவதைத் தவிர்க்க ஆர்.எச்.எச்'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'உங்கள் சந்தா பட்டியல் தற்போது காலியாக உள்ளது. உங்கள் சந்தாக்களை இறக்குமதி செய்ய விரும்பினால், நீங்கள் தரவு அமைப்புகளுக்குச் சென்று இறக்குமதி சந்தாக்களைத் தேர்ந்தெடுக்கலாம் அல்லது நீங்கள் ஒரு சேனலைத் தேடி அவற்றில் குழுசேரலாம்.'\n  Disabled Automatic Fetching: 'தானியங்கி சந்தா பெறுவதை நீங்கள் முடக்கியுள்ளீர்கள். சந்தாக்களை இங்கே காண புதுப்பிக்கவும்.'\n  Empty Channels: 'உங்கள் சந்தா சேனல்களில் தற்போது எந்த வீடியோக்களும் இல்லை.'\n  Empty Posts: 'உங்கள் சந்தா சேனல்களில் தற்போது எந்த இடுகைகளும் இல்லை.'\n  Load More Videos: 'மேலும் வீடியோக்களை ஏற்றவும்'\n  Load More Posts: 'மேலும் இடுகைகளை ஏற்றவும்'\n  Subscriptions Tabs: 'சந்தா தாவல்கள்'\n  All Subscription Tabs Hidden: 'அனைத்து சந்தா தாவல்களும் மறைக்கப்பட்டுள்ளன. இங்கே உள்ளடக்கத்தைக் காண, \"{subsection}\" இல் உள்ள \"{settingsSection}\" பிரிவில் சில தாவல்களை மறைக்கவும்.'\nMore: 'மேலும்'\nChannels:\n  Channels: 'சேனல்கள்'\n  Title: 'சேனல் பட்டியல்'\n  Search bar placeholder: 'சேனல்களைத் தேடுங்கள்'\n  Count: '{number} சேனல் (கள்) காணப்படுகிறது.'\n  Empty: 'உங்கள் சேனல் பட்டியல் தற்போது காலியாக உள்ளது.'\n  Unsubscribe Prompt: '\"{channelName}\" இலிருந்து குழுவிலக விரும்புகிறீர்களா?'\nTrending:\n  Trending: 'டிரெண்டிங்'\n  Gaming: 'கேமிங்'\n  Trending Tabs: 'பிரபலமான தாவல்கள்'\n  Sports: விளையாட்டு\nMost Popular: 'மிகவும் பிரபலமானது'\nFeed:\n  Feed Last Updated: '{feedName} கடைசியாக புதுப்பிக்கப்பட்டது: {date}'\n  Refresh Feed: 'புதுப்பிக்கவும் {subscriptionName}'\nPlaylists: 'பிளேலிச்ட்கள்'\nUser Playlists:\n  Your Playlists: 'உங்கள் பிளேலிச்ட்கள்'\n  You have no playlists. Click on the create new playlist button to create a new one.: 'உங்களிடம் பிளேலிச்ட்கள் இல்லை. புதிய ஒன்றை உருவாக்க புதிய பிளேலிச்ட் பொத்தானைக் சொடுக்கு செய்க.'\n  Empty Search Message: 'உங்கள் தேடலுடன் பொருந்தக்கூடிய இந்த பிளேலிச்ட்டில் வீடியோக்கள் எதுவும் இல்லை'\n  Search bar placeholder: 'பிளேலிச்ட்களைத் தேடுங்கள்'\n  Playlists with Matching Videos: 'பொருந்தக்கூடிய வீடியோக்களுடன் பிளேலிச்ட்கள்'\n\n  This playlist currently has no videos.: 'இந்த பிளேலிச்ட்டில் தற்போது வீடியோக்கள் இல்லை.'\n\n  Create New Playlist: 'புதிய பிளேலிச்ட்டை உருவாக்கவும்'\n\n  Add to Playlist: 'பிளேலிச்ட்டில் சேர்க்கவும்'\n  Add to Favorites: '{playlistName} இல் சேர்க்கவும்'\n  Remove from Favorites: '{playlistName} இருந்து இலிருந்து அகற்று'\n\n  Move Video Up: 'வீடியோவை நகர்த்தவும்'\n  Move Video Down: 'வீடியோவை கீழே நகர்த்தவும்'\n  Remove from Playlist: 'பிளேலிச்ட்டிலிருந்து அகற்று'\n\n  Playlist Name: 'பிளேலிச்ட் பெயர்'\n  Playlist Description: 'பிளேலிச்ட் விளக்கம்'\n\n  Save Changes: 'மாற்றங்களைச் சேமிக்கவும்'\n  Cancel: 'ரத்துசெய்'\n  Edit Playlist Info: 'பிளேலிச்ட் தகவலைத் திருத்தவும்'\n  Copy Playlist: 'பிளேலிச்ட்டை நகலெடுக்கவும்'\n  Remove Duplicate Videos: 'நகல் வீடியோக்களை அகற்றவும்'\n  Remove Watched Videos: 'பார்த்த வீடியோக்களை அகற்று'\n  Enable Quick Bookmark With This Playlist: 'இந்த பிளேலிச்ட்டுடன் விரைவான புத்தகக்குறியை இயக்கவும்'\n  Quick Bookmark Enabled: 'விரைவான புத்தகக்குறி இயக்கப்பட்டது'\n  Export Playlist: 'இந்த பிளேலிச்ட்டை ஏற்றுமதி செய்யுங்கள்'\n  The playlist has been successfully exported: 'பிளேலிச்ட் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டுள்ளது'\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: 'இந்த பிளேலிச்ட்டிலிருந்து 1 நகல் வீடியோவை அகற்ற விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது. | இந்த பிளேலிச்ட்டிலிருந்து {playlistItemCount} நகல் வீடியோக்களை அகற்ற விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது.'\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 'இந்த பிளேலிச்ட்டிலிருந்து பார்த்த 1 வீடியோவை அகற்ற விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது. | இந்த பிளேலிச்ட்டிலிருந்து {playlistItemCount} பார்த்த வீடியோக்களை அகற்ற விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது.'\n  Delete Playlist: 'பிளேலிச்ட்டை நீக்கு'\n  Cannot delete the quick bookmark target playlist.: 'விரைவான புத்தகக்குறி இலக்கு பிளேலிச்ட்டை நீக்க முடியாது.'\n  Are you sure you want to delete this playlist? This cannot be undone: 'இந்த பிளேலிச்ட்டை நீக்க விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது.'\n\n  Sort By:\n    NameAscending: 'A-z'\n    NameDescending: 'Z-A.'\n\n    LatestCreatedFirst: 'உருவாக்கப்பட்ட தேதி (புதிது)'\n    EarliestCreatedFirst: 'உருவாக்கப்பட்ட தேதி (பழைமையானது)'\n\n    LatestUpdatedFirst: 'புதுப்பிக்கப்பட்ட தேதி (புதிய)'\n    EarliestUpdatedFirst: 'புதுப்பிக்கப்பட்ட தேதி (பழையது)'\n\n    LatestPlayedFirst: 'விளையாடிய தேதி (புதிது)'\n    EarliestPlayedFirst: 'விளையாடிய தேதி (பழைய)'\n  SinglePlaylistView:\n    Search for Videos: 'வீடியோக்களைத் தேடுங்கள்'\n\n    Toast:\n      This video cannot be moved up.: 'இந்த வீடியோவை நகர்த்த முடியாது.'\n      This video cannot be moved down.: 'இந்த வீடியோவை கீழே நகர்த்த முடியாது.'\n      Video has been removed: 'வீடியோ அகற்றப்பட்டது'\n      There was a problem with removing this video: 'இந்த வீடியோவை அகற்றுவதில் சிக்கல் இருந்தது'\n\n      This playlist is already being used for quick bookmark.: 'இந்த பிளேலிச்ட் ஏற்கனவே விரைவான புக்மார்க்குக்கு பயன்படுத்தப்படுகிறது.'\n      This playlist is now used for quick bookmark: 'இந்த பிளேலிச்ட் இப்போது விரைவான புக்மார்க்குக்கு பயன்படுத்தப்படுகிறது'\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: 'இந்தப் பிளேலிச்ட் இப்போது {oldPlaylistName} க்கு பதிலாக விரைவான புக்மார்க்குக்கு பயன்படுத்தப்படுகிறது. செயல்தவிர்க்க இங்கே சொடுக்கு செய்க'\n      Reverted to use {oldPlaylistName} for quick bookmark: 'விரைவான புக்மார்க்குக்கு {oldPlaylistName} bea ஐப் பயன்படுத்த மாற்றப்பட்டது'\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 'பிளேலிச்ட்டில் உள்ள சில வீடியோக்கள் இன்னும் ஏற்றப்படவில்லை. எப்படியும் நகலெடுக்க இங்கே சொடுக்கு செய்க.'\n      Playlist name cannot be empty. Please input a name.: 'பிளேலிச்ட் பெயர் காலியாக இருக்க முடியாது. தயவுசெய்து ஒரு பெயரை உள்ளிடவும்.'\n      Playlist has been updated.: 'பிளேலிச்ட் புதுப்பிக்கப்பட்டுள்ளது.'\n      There was an issue with updating this playlist.: 'இந்த பிளேலிச்ட்டைப் புதுப்பிப்பதில் சிக்கல் இருந்தது.'\n      \"{videoCount} video(s) have been removed\": \"1 வீடியோ அகற்றப்பட்டது | {videoCount} வீடியோக்கள் அகற்றப்பட்டுள்ளன\"\n      There were no videos to remove.: 'அகற்ற வீடியோக்கள் எதுவும் இல்லை.'\n      This playlist is protected and cannot be removed.: 'இந்த பிளேலிச்ட் பாதுகாக்கப்படுகிறது மற்றும் அகற்ற முடியாது.'\n      Playlist {playlistName} has been deleted.: 'பிளேலிச்ட் {playlistName} நீக்கப்பட்டது.'\n\n      This playlist does not exist: 'இந்த பிளேலிச்ட் இல்லை'\n\n      This playlist has a video with a duration error: 'இந்த பிளேலிச்ட்டில் குறைந்தது ஒரு வீடியோவைக் கொண்டுள்ளது, அது காலம் இல்லை, அவற்றின் காலம் பூச்சியமாக இருப்பதைப் போல வரிசைப்படுத்தப்படும்.'\n      Video has been removed. Click here to undo.: வீடியோ அகற்றப்பட்டது. செயல்தவிர்க்க இங்கே சொடுக்கு செய்க.\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: 'உங்கள் வீடியோவை | இல் சேர்க்க பிளேலிச்ட்டைத் தேர்ந்தெடுக்கவும் உங்கள் {videoCount} வீடியோக்களைச் சேர்க்க பிளேலிச்ட்டைத் தேர்ந்தெடுக்கவும்'\n    N playlists selected: '{playlistCount} தேர்ந்தெடுக்கப்பட்டது'\n    Search in Playlists: 'பிளேலிச்ட்களில் தேடுங்கள்'\n    Allow Adding Duplicate Video(s): 'நகல் வீடியோக்களைச் சேர்க்க அனுமதிக்கவும்)'\n    Save: 'சேமி'\n\n    Added {count} Times: 'ஏற்கனவே சேர்க்கப்பட்டது | சேர்க்கப்பட்டது {count} முறை'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} வீடியோக்கள் சேர்க்கப்படும்'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} வீடியோக்கள் ஏற்கனவே சேர்க்கப்பட்டுள்ளன'\n\n    Toast:\n      You haven't selected any playlist yet.: 'நீங்கள் இதுவரை எந்த பிளேலிச்ட்டையும் தேர்வு செய்யவில்லை.'\n      \"Video(s) added to {playlistCount} playlists\": \"வீடியோ(கள்) 1 பிளேலிச்ட்டில் சேர்க்கப்பட்டது | {playlistCount} பிளேலிச்ட்களில் வீடியோ(கள்) சேர்க்கப்பட்டது\"\n  CreatePlaylistPrompt:\n    New Playlist Name: 'புதிய பிளேலிச்ட் பெயர்'\n    Create: 'உருவாக்கு'\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: 'இந்த பெயருடன் ஏற்கனவே ஒரு பிளேலிச்ட் உள்ளது. தயவுசெய்து வேறு பெயரைத் தேர்ந்தெடுங்கள்.'\n      Playlist {playlistName} has been successfully created.: 'பிளேலிச்ட் {playlistName} வெற்றிகரமாக உருவாக்கப்பட்டுள்ளது.'\n      There was an issue with creating the playlist.: 'பிளேலிச்ட்டை உருவாக்குவதில் சிக்கல் இருந்தது.'\n  TotalTimePlaylist: 'மொத்த நேரம்: {duration}'\n  Export list of URLs: முகவரிகளின் பட்டியலை ஏற்றுமதி\nHistory:\n  # On History Page\n  History: 'வரலாறு'\n  Watch History: 'வரலாற்றைப் பாருங்கள்'\n  Your history list is currently empty.: 'உங்கள் வரலாற்று பட்டியல் தற்போது காலியாக உள்ளது.'\n  Empty Search Message: 'உங்கள் வரலாற்றில் உங்கள் தேடலுடன் பொருந்தக்கூடிய வீடியோக்கள் எதுவும் இல்லை'\n  Search bar placeholder: \"வரலாற்றில் தேடுங்கள்\"\n  Case Sensitive Search: 'வழக்கு உணர்திறன் தேடல்'\n  DateOldestHistory: பார்த்த தேதி (பழையது)\n  DateNewestHistory: பார்த்த தேதி (புதிது)\nSettings:\n  # On Settings Page\n  Settings: 'அமைப்புகள்'\n  Sort Settings Sections (A-Z): 'அமைப்புகள் பிரிவுகளை வரிசைப்படுத்துங்கள் (A-Z)'\n  Return to Settings Menu: 'அமைப்புகள் மெனுவுக்குத் திரும்பு'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'மாற்றங்கள் நடைமுறைக்கு வருவதற்கு பயன்பாடு மறுதொடக்கம் செய்ய வேண்டும். மறுதொடக்கம் செய்து மாற்றத்தை பயன்படுத்தவா?'\n  General Settings:\n    General Settings: 'பொது'\n    Check for Updates: 'புதுப்பிப்புகளை சரிபார்க்கவும்'\n    Check for Latest Blog Posts: 'அண்மைக் கால வலைப்பதிவு இடுகைகளை சரிபார்க்கவும்'\n    Fallback to Non-Preferred Backend on Failure: 'தோல்வியில் முதலீடு செய்யப்படாத பின்தளத்தில் குறைவடையும்'\n    Enable Search Suggestions: 'தேடல் பரிந்துரைகளை இயக்கவும்'\n    Auto Load Next Page:\n      Label: 'ஆட்டோ சுமை அடுத்த பக்கம்'\n      Tooltip: 'கூடுதல் பக்கங்கள் மற்றும் கருத்துகளை தானாக ஏற்றவும்.'\n    Default Landing Page: 'இயல்புநிலை இறங்கும் பக்கம்'\n    Locale Preference: 'இருப்பிட விருப்பம்'\n    System Default: 'கணினி இயல்புநிலை'\n    Preferred API Backend:\n      Preferred API Backend: 'விருப்பமான பநிஇ பின்தளத்தில்'\n      Local API: 'உள்ளக பநிஇ'\n      Invidious API: 'வெகுவாக பநிஇ'\n    Video View Type:\n      Video View Type: 'வீடியோ பார்வை வகை'\n      Grid: 'வலைவாய்'\n      List: 'பட்டியல்'\n    Thumbnail Preference:\n      Thumbnail Preference: 'சிறு விருப்பம்'\n      Default: 'இயல்புநிலை'\n      Beginning: 'துவக்கம்'\n      Middle: 'நடுத்தர'\n      End: 'முடிவு'\n      Hidden: 'மறைக்கப்பட்ட'\n      Blur: 'மங்கலானது'\n    Current Invidious Instance: 'தற்போதைய ஆவேசமான நிகழ்வு'\n    The currently set default instance is {instance}: 'தற்போது அமைக்கப்பட்ட இயல்புநிலை நிகழ்வு {instance}'\n    No default instance has been set: 'இயல்புநிலை நிகழ்வு எதுவும் அமைக்கப்படவில்லை'\n    Current instance will be randomized on startup: 'தற்போதைய நிகழ்வு தொடக்கத்தில் சீரற்றதாக இருக்கும்'\n    Set Current Instance as Default: 'தற்போதைய நிகழ்வை இயல்புநிலையாக அமைக்கவும்'\n    Clear Default Instance: 'இயல்புநிலை நிகழ்வை அழிக்கவும்'\n    View all Invidious instance information: 'அனைத்து விலக்கப்பட்ட நிகழ்வு தகவல்களையும் காண்க'\n    Region for Trending: 'பிரபலமான பகுதி'\n    #! List countries\n    External Link Handling:\n      External Link Handling: 'வெளிப்புற இணைப்பு கையாளுதல்'\n      Open Link: 'இணைப்பை திற'\n      Ask Before Opening Link: 'இணைப்பைத் திறப்பதற்கு முன் கேளுங்கள்'\n      No Action: 'நடவடிக்கை இல்லை'\n    Open Deep Links In New Window: திறந்த முகவரி கள் புதிய சாளரத்தில் ஃப்ரீட்யூப்பிற்கு அனுப்பப்பட்டன\n    Minimize to system tray: கணினி தட்டில் குறை\n  Theme Settings:\n    Theme Settings: 'கருப்பொருள்'\n    Match Top Bar with Main Color: 'முதன்மையான வண்ணத்துடன் மேல் பட்டியை பொருத்துங்கள்'\n    Expand Side Bar by Default: 'இயல்பாக பக்க பட்டியை விரிவாக்குங்கள்'\n    Disable Smooth Scrolling: 'மென்மையான ச்க்ரோலிங் முடக்கு'\n    UI Scale: 'இடைமுகம் அளவுகோல்'\n    Hide Side Bar Labels: 'பக்க பார் லேபிள்களை மறைக்கவும்'\n    Hide FreeTube Header Logo: 'ஃப்ரீட்யூப் தலைப்பு லோகோவை மறைக்கவும்'\n    Base Theme:\n      Base Theme: 'அடிப்படை கருப்பொருள்'\n      Black: 'கருப்பு'\n      Dark: 'இருண்ட'\n      System Default: 'கணினி இயல்புநிலை'\n      Light: 'ஒளி'\n      Dracula: 'டிராகுலா'\n      Catppuccin Mocha: 'Catppuccin mocha'\n      Pastel Pink: 'வெளிர் இளஞ்சிவப்பு'\n      Hot Pink: 'சூடான இளஞ்சிவப்பு'\n      Nordic: 'நோர்டிக்'\n      Solarized Dark: 'சோலரிச் இருண்ட'\n      Solarized Light: 'சோலரிச் லைட்'\n      Gruvbox Dark: கிரைண்ட்பாக்ச் இருண்ட\n      Gruvbox Light: சுரங்கபெட்டி ஒளி\n      Catppuccin Frappe: Catppuccin வேலைநிறுத்தங்கள்\n      Everforest Dark Hard: எவர் ஃபாரச்ட் டார்க் ஆர்ட்\n      Everforest Dark Medium: எப்போதும் இருண்ட நடுத்தர\n      Everforest Dark Low: எப்போதும் இருண்ட குறைந்த\n      Everforest Light Hard: எப்போதும் ஒளி கடினமானது\n      Everforest Light Medium: எப்போதும் ஒளி நடுத்தர\n      Everforest Light Low: எப்போதும் ஒளி குறைந்த\n      Catppuccin Latte: கேட்பூசின் லேட்\n    Main Color Theme:\n      Main Color Theme: 'முதன்மையான வண்ண கருப்பொருள்'\n      Red: 'சிவப்பு'\n      Pink: 'இளஞ்சிவப்பு'\n      Purple: 'ஊதா'\n      Deep Purple: 'ஆழமான ஊதா'\n      Indigo: 'இண்டிகோ'\n      Blue: 'நீலம்'\n      Light Blue: 'வெளிர் நீலம்'\n      Cyan: 'சியான்'\n      Teal: 'டீல்'\n      Green: 'பச்சை'\n      Light Green: 'வெளிர் பச்சை'\n      Lime: 'சுண்ணாம்பு'\n      Yellow: 'மஞ்சள்'\n      Amber: 'அம்பர்'\n      Orange: 'ஆரஞ்சு'\n      Deep Orange: 'ஆழமான ஆரஞ்சு'\n      Dracula Cyan: 'டிராகுலா சியான்'\n      Dracula Green: 'டிராகுலா பச்சை'\n      Dracula Orange: 'டிராகுலா ஆரஞ்சு'\n      Dracula Pink: 'டிராகுலா பிங்க்'\n      Dracula Purple: 'டிராகுலா ஊதா'\n      Dracula Red: 'டிராகுலா சிவப்பு'\n      Dracula Yellow: 'டிராகுலா மஞ்சள்'\n      Catppuccin Mocha Rosewater: 'Catppuccin Mocha Roswater'\n      Catppuccin Mocha Flamingo: 'கட்டாபுசின் மொகா ஃபிளமிங்கோ'\n      Catppuccin Mocha Pink: 'Catppuccin mocha இளஞ்சிவப்பு'\n      Catppuccin Mocha Mauve: 'Catppuccin mocha mauve'\n      Catppuccin Mocha Red: 'Catppuccin Mocha சிவப்பு'\n      Catppuccin Mocha Maroon: 'Catppuccin Mocha மெரூன்'\n      Catppuccin Mocha Peach: 'Catppuccin mocha குழிப்பேரி'\n      Catppuccin Mocha Yellow: 'Catppuccin mocha மஞ்சள்'\n      Catppuccin Mocha Green: 'Catppuccin Mocha பச்சை'\n      Catppuccin Mocha Teal: 'Catppuccin mocha டீல்'\n      Catppuccin Mocha Sky: 'Catppuccin Mocha Skied'\n      Catppuccin Mocha Sapphire: 'Catppuccin mocha sapphire'\n      Catppuccin Mocha Blue: 'Catppuccin mocha நீலம்'\n      Catppuccin Mocha Lavender: 'Catppuccin mocha சுகந்தி'\n      Solarized Yellow: 'சோலரிச் மஞ்சள்'\n      Solarized Orange: 'சோலரிச் ஆரஞ்சு'\n      Solarized Red: 'சோலரிச் சிவப்பு'\n      Solarized Magenta: 'சூரிய ஒளிரும் மெசந்தா'\n      Solarized Violet: 'சூரிய ஒளிரும் வயலட்'\n      Solarized Blue: 'சோலரிச் ப்ளூ'\n      Solarized Cyan: 'சோலரிச் சியான்'\n      Solarized Green: 'சோலரிச் பச்சை'\n      Gruvbox Light Blue: க்ரூவ்பாக்ச் ஒளி நீலம்\n      Gruvbox Dark Purple: கிரைண்ட்பாக்ச் இருண்ட ஊதா\n      Gruvbox Dark Aqua: க்ரூவாக்ச் டார்க் அக்வா\n      Gruvbox Dark Blue: க்ரூவாக்ச் அடர் நீலம்\n      Gruvbox Dark Orange: கிரைண்ட்பாக்ச் இருண்ட ஆரஞ்சு\n      Gruvbox Dark Green: கிரைண்ட்பாக்ச் அடர் பச்சை\n      Gruvbox Dark Yellow: க்ரூவாக்ச் அடர் மஞ்சள்\n      Gruvbox Light Red: க்ரூவ்பாக்ச் ஒளி சிவப்பு\n      Gruvbox Light Purple: சுரங்கபெட்டி ஒளி ஊதா\n      Gruvbox Light Orange: கிரைண்ட்பாக்ச் லைட் ஆரஞ்சு\n      Catppuccin Frappe Rosewater: கேட் பியூசின் ரோச்வாட்டரைத் தாக்கியது\n      Catppuccin Frappe Flamingo: Catppuccin ஃபிளமிங்கோவைத் தாக்கியது\n      Catppuccin Frappe Pink: Catppuccin இளஞ்சிவப்பு நிறத்தில் அடிக்கிறது\n      Catppuccin Frappe Mauve: Catppuccin mavev ஐத் தாக்கியது\n      Catppuccin Frappe Red: கேட்பூசின் ஃப்ராப் சிவப்பு\n      Catppuccin Frappe Maroon: Catppuccin மெரூனைத் தாக்கியது\n      Catppuccin Frappe Peach: Catppuccin frappe பீச்\n      Catppuccin Frappe Yellow: Catppuccin frappe மஞ்சள்\n      Catppuccin Frappe Green: Catppuccin பச்சை நிறத்தில் உள்ளது\n      Catppuccin Frappe Teal: Catppuccin டீலைத் தாக்கியது\n      Catppuccin Frappe Sky: Catppuccin வானத்தைத் தாக்கும்\n      Catppuccin Frappe Sapphire: Catppuccin சபையரைத் தாக்கும்\n      Catppuccin Frappe Blue: Catppuccin நீல நிறத்தில் உள்ளது\n      Catppuccin Frappe Lavender: Catppuccin லாவ்டரைத் தாக்கியது\n      Everforest Dark Red: எப்போதும் இருண்ட சிவப்பு\n      Everforest Dark Orange: எப்போதும் இருண்ட ஆரஞ்சு\n      Everforest Dark Yellow: எவர் ஃபாரெச்ட் அடர் மஞ்சள்\n      Everforest Dark Green: எப்போதும் இருண்ட பச்சை\n      Everforest Dark Aqua: எப்போதும் டார்க் அக்வா\n      Everforest Dark Blue: எவர் ஃபாரெச்ட் அடர் நீலம்\n      Everforest Dark Purple: எப்போதும் இருண்ட ஊதா\n      Everforest Light Red: எப்போதும் ஒளி சிவப்பு\n      Everforest Light Orange: எப்போதும் ஒளி ஆரஞ்சு\n      Everforest Light Yellow: எப்போதும் வெளிச்சம் மஞ்சள்\n      Everforest Light Green: எப்போதும் வெளிச்சம் பச்சை\n      Everforest Light Aqua: எவர் ஃபாரெச்ட் லைட் அக்வா\n      Everforest Light Blue: எவர் ஃபாரெச்ட் லைட் நீலம்\n      Everforest Light Purple: எப்போதும் ஒளி ஊதா\n      Catppuccin Latte Mauve: கேட்பூசின் லட்டே மாவ்\n      Catppuccin Latte Red: கேட்பூசின் லேட் ரெட்\n    Secondary Color Theme: 'இரண்டாம் நிலை வண்ண கருப்பொருள்'\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: 'வீரர்'\n    Play Next Video: 'ஆட்டோபிளே பரிந்துரைக்கப்பட்ட வீடியோக்கள்'\n    Turn on Subtitles by Default: 'முன்னிருப்பாக வசன வரிகள் இயக்கவும்'\n    Autoplay Videos: 'வீடியோக்களை தானாகத் தொடங்கவும்'\n    Proxy Videos Through Invidious: 'ஆவேசத்தின் மூலம் பதிலாள் வீடியோக்கள்'\n    Autoplay Playlists: 'ஆட்டோபிளே பிளேலிச்ட் வீடியோக்கள்'\n    Enable Theatre Mode by Default: 'இயல்பாக தியேட்டர் பயன்முறையை இயக்கவும்'\n    Scroll Volume Over Video Player: 'வீடியோ பிளேயர் மீது அளவை உருட்டவும்'\n    Scroll Playback Rate Over Video Player: 'வீடியோ பிளேயரில் உருட்டல் பிளேபேக் வீதத்தை உருட்டவும்'\n    Skip by Scrolling Over Video Player: 'வீடியோ பிளேயரை ச்க்ரோலிங் செய்வதன் மூலம் தவிர்க்கவும்'\n    Display Play Button In Video Player: 'வீடியோ பிளேயரில் ப்ளே பொத்தானைக் காண்பி'\n    Enter Fullscreen on Display Rotate: 'காட்சி சுழற்சியில் முழுத்திரை உள்ளிடவும்'\n    Next Video Interval: 'ஆட்டோபிளே கவுண்டவுன் நேரங்குறிகருவி'\n    Fast-Forward / Rewind Interval: 'வேகமாக முன்னோக்கி / முன்னாடி இடைவெளி'\n    Default Volume: 'இயல்புநிலை தொகுதி'\n    Default Playback Rate: 'இயல்புநிலை பின்னணி வீதம்'\n    Max Video Playback Rate: 'அதிகபட்ச வீடியோ பிளேபேக் வீதம்'\n    Video Playback Rate Interval: 'வீடியோ பிளேபேக் வீத இடைவெளி'\n    Default Video Format:\n      Default Video Format: 'இயல்புநிலை வீடியோ வடிவம்'\n      Dash Formats: 'கோடு வடிவங்கள்'\n      Legacy Formats: 'மரபு வடிவங்கள்'\n      Audio Formats: 'ஆடியோ வடிவங்கள்'\n    Default Quality:\n      Default Quality: 'இயல்புநிலை தகுதி'\n      Auto: 'தானி'\n      144p: '144 ப'\n      240p: '240 ப'\n      360p: '360 ப'\n      480p: '480 ப'\n      720p: '720 ஆ'\n      1080p: '1080 ப'\n      1440p: '1440 ப'\n      4k: 'Chc'\n      8k: '8 கே'\n    Screenshot:\n      Enable: 'ச்கிரீன்சாட்டை இயக்கவும்'\n      Format Label: 'திரைக்காட்சி வடிவம்'\n      Quality Label: 'திரைக்காட்சி தகுதி'\n      Ask Path: 'சேமி கோப்புறையைக் கேளுங்கள்'\n      Folder Label: 'திரைக்காட்சி கோப்புறை'\n      Folder Button: 'கோப்புறையைத் தேர்ந்தெடு'\n      File Name Label: 'கோப்பு பெயர் முறை'\n      File Name Tooltip: 'நீங்கள் கீழே மாறிகளைப் பயன்படுத்தலாம். %Y ஆண்டு 4 இலக்கங்கள். %மீ மாதம் 2 இலக்கங்கள். %D நாள் 2 இலக்கங்கள். %H மணி 2 இலக்கங்கள். %N மணித்துளி 2 இலக்கங்கள். %s இரண்டாவது 2 இலக்கங்கள். %டி மில்லி நொடி 3 இலக்கங்கள். %s வீடியோ இரண்டாவது. %டி வீடியோ மில்லி நொடி 3 இலக்கங்கள். %நான் வீடியோ ஐடி.'\n      Error:\n        Forbidden Characters: 'தடைசெய்யப்பட்ட எழுத்துக்கள்'\n        Empty File Name: 'வெற்று கோப்பு பெயர்'\n    Autoplay Interruption Timer: ஆட்டோபிளே குறுக்கீடு நேரங்குறிகருவி\n    Default Viewing Mode:\n      Theater: தியேட்டர்\n      Default Viewing Mode: இயல்புநிலை பார்க்கும் முறை\n      Full Screen: முழுத் திரை\n      Picture in Picture: படத்தில் படம்\n      External Player: வெளிப்புற பிளேயர் ({externalPlayerName})\n  External Player Settings:\n    External Player Settings: 'வெளிப்புற பிளேயர்'\n    External Player: 'வெளிப்புற பிளேயர்'\n    Ignore Unsupported Action Warnings: 'ஆதரிக்கப்படாத செயல் எச்சரிக்கைகளை புறக்கணிக்கவும்'\n    Ignore Default Arguments: 'இயல்புநிலை வாதங்களை புறக்கணிக்கவும்'\n    Custom External Player Executable: 'தனிப்பயன் வெளிப்புற பிளேயர் இயங்கக்கூடியது'\n    Custom External Player Arguments: 'தனிப்பயன் வெளிப்புற பிளேயர் வாதங்கள்'\n    Players:\n      None:\n        Name: 'எதுவுமில்லை'\n  Privacy Settings:\n    Privacy Settings: 'தனியுரிமை'\n    Remember History: 'வாட்ச் இச்டரி நினைவில் கொள்ளுங்கள்'\n    Save Watched Progress: 'பார்த்த முன்னேற்றத்தை சேமிக்கவும்'\n    Save Watched Videos With Last Viewed Playlist: 'கடைசியாக பார்க்கப்பட்ட பிளேலிச்ட்டுடன் பார்த்த வீடியோக்களைச் சேமிக்கவும்'\n    Clear Search Cache: 'தேடல் தற்காலிக சேமிப்பை அழிக்கவும்'\n    Are you sure you want to clear out your search cache?: 'உங்கள் தேடல் தற்காலிக சேமிப்பை அழிக்க விரும்புகிறீர்களா?'\n    Search cache has been cleared: 'தேடல் தற்காலிக சேமிப்பு அழிக்கப்பட்டது'\n    Remove Watch History: 'வாட்ச் வரலாற்றை அகற்று'\n    Are you sure you want to remove your entire watch history?: 'உங்கள் முழு கடிகார வரலாற்றையும் அகற்ற விரும்புகிறீர்களா?'\n    Watch history has been cleared: 'வாட்ச் வரலாறு அழிக்கப்பட்டுவிட்டது'\n    Remove All Subscriptions / Profiles: 'அனைத்து சந்தாக்கள் / சுயவிவரங்களையும் அகற்று'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'அனைத்து சந்தாக்கள் மற்றும் சுயவிவரங்களை அகற்ற விரும்புகிறீர்களா? இதை செயல்தவிர்க்க முடியாது.'\n    Remove All Playlists: 'அனைத்து பிளேலிச்ட்களையும் அகற்றவும்'\n    All playlists have been removed: 'அனைத்து பிளேலிச்ட்களும் அகற்றப்பட்டுள்ளன'\n    Are you sure you want to remove all your playlists?: 'உங்கள் பிளேலிச்ட்கள் அனைத்தையும் அகற்ற விரும்புகிறீர்களா?'\n    Remember Search History: தேடல் வரலாற்றை நினைவில் கொள்க\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: தானி\n        Semi-auto: அரை கார்\n        Never: ஒருபோதும்\n      Tooltip: ஆட்டோ = ஒவ்வொரு வீடியோ பக்கத்திலும் வெளியேறும் போது, வீடியோ முடிந்ததும், பிழை ஏற்பட்டதும் (எ.கா. ரேடலிமிட்டட் மற்றும் வாட்ச் அமர்வு காலாவதியானது). வீடியோ பக்கத்திலிருந்து வெளியேறுவதைத் தவிர்த்து அரை ஆட்டோ = ஆட்டோ போன்றது மற்றும் வீடியோ பிளேயருக்கு அடியில் அமைந்துள்ள சேமி பார்த்த முன்னேற்றம் என்ற பொத்தானை வழியாக முன்னேற்றத்தை கைமுறையாக சேமிக்க முடியும்.\n    Clear Search History and Cache: தேடல் வரலாறு மற்றும் தற்காலிக சேமிப்பை அழிக்கவும்\n    Are you sure you want to clear out your search history and cache?: உங்கள் தேடல் வரலாறு மற்றும் தற்காலிக சேமிப்பை அழிக்க விரும்புகிறீர்களா?\n    Search history and cache have been cleared: தேடல் வரலாறு மற்றும் தற்காலிக சேமிப்பு ஆகியவை அழிக்கப்பட்டுள்ளன\n  Subscription Settings:\n    Subscription Settings: 'சந்தா'\n    Fetch Feeds from RSS: 'RSS இலிருந்து ஊட்டங்களைப் பெறுங்கள்'\n    Fetch Automatically: 'தானாகவே ஊட்டத்தைப் பெறுங்கள்'\n    Only Show Latest Video for Each Channel: ''\n    Confirm Before Unsubscribing: 'குழுவிலகும் முன் உறுதிப்படுத்தவும்'\n    'Limit the number of videos displayed for each channel': ஒவ்வொரு சேனலுக்கும் காட்டப்படும் வீடியோக்களின் எண்ணிக்கையை கட்டுப்படுத்துங்கள்\n    To: பெறுநர்\n  Distraction Free Settings:\n    Distraction Free Settings: 'கவனச்சிதறல் இல்லாதது'\n    Sections:\n      Side Bar: 'பக்க பட்டி'\n      Subscriptions Page: 'சந்தா பக்கம்'\n      Channel Page: 'சேனல் பக்கம்'\n      Watch Page: 'பார்க்கும் பக்கம்'\n      General: 'பொது'\n    Hide Video Views: 'வீடியோ காட்சிகளை மறைக்கவும்'\n    Hide Video Likes And Dislikes: 'வீடியோ விருப்பங்களையும் விருப்பு வெறுப்புகளையும் மறைக்கவும்'\n    Hide Channel Subscribers: 'சேனல் சந்தாதாரர்களை மறைக்கவும்'\n    Hide Comment Likes: 'கருத்து விருப்பங்களை மறைக்கவும்'\n    Hide Recommended Videos: 'பரிந்துரைக்கப்பட்ட வீடியோக்களை மறைக்கவும்'\n    Hide Trending Videos: 'பிரபலமான வீடியோக்களை மறைக்கவும்'\n    Hide Popular Videos: 'பிரபலமான வீடியோக்களை மறைக்கவும்'\n    Hide Playlists: 'பிளேலிச்ட்களை மறைக்கவும்'\n    Hide Live Chat: 'நேரடி அரட்டையை மறைக்கவும்'\n    Hide Active Subscriptions: 'செயலில் உள்ள சந்தாக்களை மறைக்கவும்'\n    Hide Video Description: 'வீடியோ விளக்கத்தை மறைக்கவும்'\n    Hide Comments: 'கருத்துகளை மறைக்கவும்'\n    Hide Profile Pictures in Comments: 'கருத்துகளில் சுயவிவர படங்களை மறைக்கவும்'\n    Display Titles Without Excessive Capitalisation: 'அதிக மூலதனமயமாக்கல் மற்றும் நிறுத்தற்குறி இல்லாமல் தலைப்புகளைக் காண்பி'\n    Hide Live Streams: 'நேரடி நீரோடைகளை மறைக்கவும்'\n    Hide Upcoming Premieres: 'வரவிருக்கும் பிரீமியர்சை மறைக்கவும்'\n    Hide Sharing Actions: 'பகிர்வு செயல்களை மறைக்கவும்'\n    Hide Videos on Watch: 'கடிகாரத்தில் வீடியோக்களை மறைக்கவும்'\n    Hide Chapters: 'அத்தியாயங்களை மறைக்கவும்'\n    Hide Channels: 'சேனல்களிலிருந்து வீடியோக்களை மறைக்கவும்'\n    Hide Channels Disabled Message: 'சில சேனல்கள் ஐடியைப் பயன்படுத்தி தடுக்கப்பட்டு செயலாக்கப்படவில்லை. அந்த ஐடிகள் புதுப்பிக்கும்போது நற்பொருத்தம் தடுக்கப்படுகிறது'\n    Hide Channels Placeholder: 'சேனல் ஐடி'\n    Hide Channels Invalid: 'வழங்கப்பட்ட சேனல் ஐடி தவறானது'\n    Hide Channels API Error: 'வழங்கப்பட்ட ஐடியுடன் பயனரை மீட்டெடுப்பதில் பிழை. ஐடி சரியாக இருந்தால் மீண்டும் சரிபார்க்கவும்.'\n    Hide Channels Already Exists: 'சேனல் ஐடி ஏற்கனவே உள்ளது'\n    Hide Featured Channels: 'பிரத்யேக சேனல்களை மறைக்கவும்'\n    Hide Channel Playlists: 'சேனல் \"பிளேலிச்ட்கள்\" தாவலை மறைக்கவும்'\n    Hide Channel Shorts: 'சேனல் \"சார்ட்ச்\" தாவலை மறைக்கவும்'\n    Hide Channel Podcasts: 'சேனல் \"பாட்காச்ட்கள்\" தாவலை மறைக்கவும்'\n    Hide Channel Releases: 'சேனல் \"வெளியீடுகள்\" தாவலை மறைக்கவும்'\n    Hide Videos, Playlists and Channels Containing Text: 'உரையைக் கொண்ட வீடியோக்கள் மற்றும் பிளேலிச்ட்களை மறைக்கவும்'\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 'சொல், சொல் துண்டு அல்லது சொற்றொடர்'\n    Hide Subscriptions Videos: 'சந்தா வீடியோக்களை மறைக்கவும்'\n    Hide Subscriptions Shorts: 'சந்தாக்கள் குறும்படங்களை மறைக்கவும்'\n    Hide Subscriptions Live: 'சந்தாக்களை நேரடியாக மறைக்கவும்'\n    Show Added Items: சேர்க்கப்பட்ட உருப்படிகளைக் காட்டு\n    Hide Channel Home: சேனல் \"முகப்பு\" தாவலை மறைக்கவும்\n    Hide Channel Posts: சேனல் \"இடுகைகள்\" தாவலை மறைக்கவும்\n    Hide Channel Courses: சேனல் \"படிப்புகள்\" தாவலை மறைக்கவும்\n    Hide Subscriptions Posts: சந்தாக்கள் இடுகைகளை மறைக்கவும்\n  Data Settings:\n    Data Settings: 'தகவல்கள்'\n    Select Export Type: 'ஏற்றுமதி வகையைத் தேர்ந்தெடுக்கவும்'\n    Import Subscriptions: 'சந்தாக்களை இறக்குமதி செய்யுங்கள்'\n    Subscription File: 'சந்தா கோப்பு'\n    History File: 'வரலாற்று கோப்பு'\n    Playlist File: 'பிளேலிச்ட் கோப்பு'\n    Export Subscriptions: 'ஏற்றுமதி சந்தாக்கள்'\n    Export FreeTube: 'ஃப்ரீட்யூப் ஏற்றுமதி'\n    Export YouTube: 'YouTube ஐ ஏற்றுமதி செய்யுங்கள்'\n    Export NewPipe: 'புதிய பக்கத்தை ஏற்றுமதி செய்யுங்கள்'\n    Import History: 'இறக்குமதி வரலாறு'\n    Export History: 'ஏற்றுமதி வரலாறு'\n    Import Playlists: 'பிளேலிச்ட்களை இறக்குமதி செய்யுங்கள்'\n    Export Playlists: 'பிளேலிச்ட்கள் ஏற்றுமதி'\n    Export Playlists For Older FreeTube Versions:\n      Label: 'பழைய ஃப்ரீட்யூப் பதிப்புகளுக்கான பிளேலிச்ட்களை ஏற்றுமதி செய்யுங்கள்'\n      # |- = Keep newlines, No newline at end\n      Tooltip: |-\n        இந்த விருப்பம் அனைத்து பிளேலிச்ட்களிலிருந்தும் வீடியோக்களை 'பிடித்தவை' என்ற பெயரில் ஒரு பிளேலிச்ட்டில் ஏற்றுமதி செய்கிறது.\n         ஃப்ரீட்யூப்பின் பழைய பதிப்பிற்கு பிளேலிச்ட்களில் வீடியோக்களை எவ்வாறு ஏற்றுமதி செய்வது மற்றும் இறக்குமதி செய்வது:\n         1. இந்த விருப்பத்துடன் உங்கள் பிளேலிச்ட்களை ஏற்றுமதி செய்யுங்கள்.\n         2. தனியுரிமை அமைப்புகளின் கீழ் அனைத்து பிளேலிச்ட்கள் விருப்பத்தையும் அகற்று பயன்படுத்தி உங்கள் இருக்கும் பிளேலிச்ட்கள் அனைத்தையும் நீக்கு.\n         3. ஃப்ரீட்யூப்பின் பழைய பதிப்பைத் தொடங்கி ஏற்றுமதி செய்யப்பட்ட பிளேலிச்ட்களை இறக்குமதி செய்யுங்கள். \"\n    Profile object has insufficient data, skipping item: 'சுயவிவரப் பொருளில் போதுமான தரவு இல்லை, உருப்படியைத் தவிர்க்கிறது'\n    All subscriptions and profiles have been successfully imported: 'அனைத்து சந்தாக்கள் மற்றும் சுயவிவரங்கள் வெற்றிகரமாக இறக்குமதி செய்யப்பட்டுள்ளன'\n    All subscriptions have been successfully imported: 'அனைத்து சந்தாக்களும் வெற்றிகரமாக இறக்குமதி செய்யப்பட்டுள்ளன'\n    Invalid subscriptions file: 'தவறான சந்தா கோப்பு'\n    Invalid history file: 'தவறான வரலாறு கோப்பு'\n    Subscriptions have been successfully exported: 'சந்தாக்கள் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டுள்ளன'\n    History object has insufficient data, skipping item: 'வரலாற்று பொருள் போதுமான தரவு, உருப்படியைத் தவிர்ப்பது'\n    All watched history has been successfully imported: 'பார்த்த அனைத்து வரலாறும் வெற்றிகரமாக இறக்குமதி செய்யப்பட்டுள்ளன'\n    All watched history has been successfully exported: 'பார்த்த அனைத்து வரலாறும் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டுள்ளன'\n    Playlist insufficient data: '\"{playlist}\" பிளேலிச்ட்டுக்கான போதிய தரவு, உருப்படியைத் தவிர்க்கிறது'\n    All playlists has been successfully imported: 'அனைத்து பிளேலிச்ட்களும் வெற்றிகரமாக இறக்குமதி செய்யப்பட்டுள்ளன'\n    All playlists has been successfully exported: 'அனைத்து பிளேலிச்ட்களும் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டுள்ளன'\n    Unable to read file: 'கோப்பைப் படிக்க முடியவில்லை'\n    Unable to write file: 'கோப்பு எழுத முடியவில்லை'\n    Unknown data key: 'அறியப்படாத தரவு விசை'\n    How do I import my subscriptions?: 'எனது சந்தாக்களை எவ்வாறு இறக்குமதி செய்வது?'\n    Manage Subscriptions: 'சந்தாக்களை நிர்வகிக்கவும்'\n    Search history file: தேடல் வரலாற்று கோப்பு\n    Search history: தேடல் வரலாறு\n    Import search history: தேடல் வரலாற்றை இறக்குமதி\n    Export search history: தேடல் வரலாறு ஏற்றுமதி\n    All search history has been successfully imported: அனைத்து தேடல் வரலாறும் வெற்றிகரமாக இறக்குமதி செய்யப்பட்டது\n    All search history has been successfully exported: அனைத்து தேடல் வரலாறும் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டது\n  Proxy Settings:\n    Proxy Settings: 'பதிலாள்'\n    Enable Tor / Proxy: 'டோர் / ப்ராக்சியை இயக்கவும்'\n    Proxy Protocol: 'பதிலாள் நெறிமுறை'\n    Proxy Host: 'பதிலாள் புரவலன்'\n    Proxy Port Number: 'பதிலாள் துறைமுகம் எண்'\n    Clicking on Test Proxy will send a request to: 'டெச்ட் ப்ராக்சியைக் சொடுக்கு செய்தால் ஒரு கோரிக்கையை அனுப்பும்'\n    Test Proxy: 'சோதனை பதிலாள்'\n    Your Info: 'உங்கள் செய்தி'\n    Ip: 'ஐபி'\n    Country: 'நாடு'\n    Region: 'பகுதி'\n    City: 'நகரம்'\n    Error getting network information. Is your proxy configured properly?: 'பிணைய தகவல்களைப் பெறுவதில் பிழை. உங்கள் பதிலாள் சரியாக கட்டமைக்கப்பட்டுள்ளதா?'\n    Proxy Warning: ஃப்ரீட்யூப்பில் ஒரு உள்ளமைக்கப்பட்ட பதிலாள் இல்லை, ஆனால் வெளிப்புற ப்ராக்சியுடன் இணைக்க முடியும், அதாவது உங்கள் கணினியில் டோர் போன்றவை அல்லது வெளிப்புற பதிலாள் போன்றவை-சில விபிஎன்களால் வழங்கப்பட்ட சாக்ச் 5 பதிலாள் போன்றவை. இயக்கப்பட்டிருந்தால், உங்கள் ப்ராக்சி/டோர் சரியாக கட்டமைக்கப்பட்டுள்ளதா என்பதை உறுதிப்படுத்திக் கொள்ளுங்கள், அல்லது ஃப்ரீட்யூப் எந்த தரவையும் பெற முடியாது.\n    Proxy Username: பதிலாள் பயனர்பெயர்\n    Proxy Password: பதிலாள் கடவுச்சொல்\n  SponsorBlock Settings:\n    SponsorBlock Settings: 'ஒப்புரவாளர் தொகுதி'\n    Enable SponsorBlock: 'ஒப்புரவாளர் பிளாக் இயக்கவும்'\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 'ஒப்புரவாளர் பிளாக் பநிஇ முகவரி (இயல்புநிலை https://sponsor.ajay.app)'\n    Notify when sponsor segment is skipped: 'ஒப்புரவாளர் பிரிவு தவிர்க்கப்படும்போது அறிவிக்கவும்'\n    UseDeArrowTitles: 'அன்புள்ள வீடியோ தலைப்புகளைப் பயன்படுத்தவும்'\n    UseDeArrowThumbnails: 'சிறுபடங்களுக்கு டியர்ரோவைப் பயன்படுத்தவும்'\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'அன்புள்ள சிறு செனரேட்டர் பநிஇ முகவரி (இயல்புநிலை https://dearrow-thumb.ajay.app)'\n    Skip Options:\n      Skip Option: 'விருப்பத்தைத் தவிர்க்கவும்'\n      Auto Skip: 'கார் ச்கிப்'\n      Show In Seek Bar: 'சீக் பட்டியில் காட்டு'\n      Prompt To Skip: 'தவிர்க்க தூண்டுதல்'\n      Do Nothing: 'எதுவும் செய்ய வேண்டாம்'\n    Category Color: 'வகை நிறம்'\n  Parental Control Settings:\n    Parental Control Settings: 'பெற்றோர் கட்டுப்பாடு'\n    Hide Unsubscribe Button: 'குழுவிலக பொத்தானை மறைக்கவும்'\n    Show Family Friendly Only: 'குடும்ப நட்பை மட்டும் காட்டு'\n    Hide Search Bar: 'தேடல் பட்டியை மறைக்கவும்'\n    Hide Uploader on Watch page: கண்காணிப்புப் பக்கத்தில் பதிவேற்றியவரை மறை\n  Experimental Settings:\n    Experimental Settings: 'சோதனை'\n    Warning: 'இந்த அமைப்புகள் சோதனைக்குரியவை, அவை இயக்கப்பட்டிருக்கும் போது செயலிழப்பை ஏற்படுத்தக்கூடும். காப்புப்பிரதிகளை உருவாக்குவது மிகவும் பரிந்துரைக்கப்படுகிறது. உங்கள் சொந்த ஆபத்தில் பயன்படுத்தவும்!'\n    Replace HTTP Cache: 'HTTP தற்காலிக சேமிப்பை மாற்றவும்'\n  Password Dialog:\n    Password: 'கடவுச்சொல்'\n    Enter Password To Unlock: 'அமைப்புகளைத் திறக்க கடவுச்சொல்லை உள்ளிடவும்'\n  Password Settings:\n    Password Settings: 'கடவுச்சொல்'\n    Set Password To Prevent Access: 'அமைப்புகளுக்கான அணுகலைத் தடுக்க கடவுச்சொல்லை அமைக்கவும்'\n    Set Password: 'கடவுச்சொல்லை அமைக்கவும்'\n    Remove Password: 'கடவுச்சொல்லை அகற்று'\nAbout:\n  #On About page\n  About: 'பற்றி'\n  Beta: 'பீட்டா'\n  Source code: 'மூலக் குறியீடு'\n  AGPLv3: 'Agplv3'\n  Downloads / Changelog: 'பதிவிறக்கங்கள் / சேஞ்ச்லாக்'\n  GitHub releases: 'அறிவிலிமைய வெளியீடுகள்'\n  Help: 'உதவி'\n  FreeTube Wiki: 'ஒரு வாரம் freetube'\n  FAQ: 'கேள்விகள்'\n  Discussions: 'விவாதங்கள்'\n  Report a problem: 'ஒரு சிக்கலைப் புகாரளிக்கவும்'\n  GitHub issues: 'அறிவிலிமையம் சிக்கல்கள்'\n  Please check for duplicates before posting: 'இடுகையிடுவதற்கு முன் நகல்களை சரிபார்க்கவும்'\n  Website: 'வலைத்தளம்'\n  Blog: 'வலைப்பதிவு'\n  Email: 'மின்னஞ்சல்'\n  Mastodon: 'மாச்டோடன்'\n  Chat on Matrix: 'மேட்ரிக்சில் அரட்டை'\n  room rules: 'அறை விதிகள்'\n  Translate: 'மொழிபெயர்த்திடு'\n  Credits: 'வரவு'\n  these people and projects: 'இந்த நபர்கள் மற்றும் திட்டங்கள்'\n  Donate: 'நன்கொடை'\n\n  Licensed under the {licenseLink}: '{licenseLink} இன் கீழ் உரிமம் பெற்றது'\n  Please read the {roomRulesLink}: '{roomRulesLink} ஐப் படிக்கவும்'\n  FreeTube is made possible by {creditsPageLink}: FreeTube ஆனது {creditsPageLink} மூலம் சாத்தியமானது\nProfile:\n  Profile Settings: 'சுயவிவரம்'\n  Toggle Profile List: 'சுயவிவர பட்டியலை மாற்றவும்'\n  Profile Select: 'சுயவிவரத் தேர்ந்தெடுக்கவும்'\n  Profile Filter: 'சுயவிவர வடிகட்டி'\n  All Channels: 'அனைத்து சேனல்களும்'\n  Profile Manager: 'சுயவிவர மேலாளர்'\n  Create New Profile: 'புதிய சுயவிவரத்தை உருவாக்கவும்'\n  Edit Profile: 'சுயவிவரத்தைத் திருத்து'\n  Edit Profile Name: 'சுயவிவரப் பெயரைத் திருத்தவும்'\n  Create Profile Name: 'சுயவிவர பெயரை உருவாக்கவும்'\n  Profile Name: 'சுயவிவர பெயர்'\n  Color Picker: 'வண்ண தேர்வாளர்'\n  Custom Color: 'தனிப்பயன் நிறம்'\n  Profile Preview: 'சுயவிவர முன்னோட்டம்'\n  Create Profile: 'சுயவிவரத்தை உருவாக்கவும்'\n  Update Profile: 'சுயவிவரத்தைப் புதுப்பிக்கவும்'\n  Make Default Profile: 'இயல்புநிலை சுயவிவரத்தை உருவாக்குங்கள்'\n  Delete Profile: 'சுயவிவரத்தை நீக்கு'\n  Are you sure you want to delete this profile?: 'இந்த சுயவிவரத்தை நீக்க விரும்புகிறீர்களா?'\n  All subscriptions will also be deleted.: 'அனைத்து சந்தாக்களும் நீக்கப்படும்.'\n  Your profile name cannot be empty: 'உங்கள் சுயவிவர பெயர் காலியாக இருக்க முடியாது'\n  Profile has been created: 'சுயவிவரம் உருவாக்கப்பட்டுள்ளது'\n  Profile has been updated: 'சுயவிவரம் புதுப்பிக்கப்பட்டுள்ளது'\n  Your default profile has been set to {profile}: 'உங்கள் இயல்புநிலை சுயவிவரம் {profile} என அமைக்கப்பட்டுள்ளது'\n  Removed {profile} from your profiles: 'உங்கள் சுயவிவரங்களிலிருந்து {profile} அகற்றப்பட்டது'\n  Your default profile has been changed to your primary profile: 'உங்கள் இயல்புநிலை சுயவிவரம் உங்கள் முதன்மை சுயவிவரத்திற்கு மாற்றப்பட்டுள்ளது'\n  '{profile} is now the active profile': '{profile} இப்போது செயலில் உள்ள சுயவிவரம்'\n  Subscription List: 'சந்தா பட்டியல்'\n  Other Channels: 'பிற சேனல்கள்'\n  '{number} selected': '{number} தேர்ந்தெடுக்கப்பட்டது'\n  Select All: 'அனைத்தையும் தெரிவுசெய்'\n  Select None: 'எதுவுமில்லை என்பதைத் தேர்ந்தெடுக்கவும்'\n  Delete Selected: 'தேர்ந்தெடுக்கப்பட்டதை நீக்கு'\n  Add Selected To Profile: 'சுயவிவரத்தில் தேர்ந்தெடுக்கப்பட்டதைச் சேர்க்கவும்'\n  No channel(s) have been selected: 'சேனல் (கள்) எதுவும் தேர்ந்தெடுக்கப்படவில்லை'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'இது உங்கள் முதன்மை சுயவிவரம். தேர்ந்தெடுக்கப்பட்ட சேனல்களை நீக்க விரும்புகிறீர்களா? அதே சேனல்கள் அவை காணப்படும் எந்த சுயவிவரத்திலும் நீக்கப்படும்.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'தேர்ந்தெடுக்கப்பட்ட சேனல்களை நீக்க விரும்புகிறீர்களா? இது வேறு எந்த சுயவிவரத்திலிருந்தும் சேனலை நீக்காது.'\n  Close Profile Dropdown: 'சுயவிவர வீழ்ச்சியை மூடு'\n  Open Profile Dropdown: 'திறந்த சுயவிவர வீழ்ச்சி'\n#On Channel Page\nChannel:\n  Subscribe: 'குழுசேர்'\n  Unsubscribe: 'குழுவிலகவும்'\n  Channel has been removed from your subscriptions: 'உங்கள் சந்தாக்களிலிருந்து சேனல் அகற்றப்பட்டுள்ளது'\n  Removed subscription from {count} other channel(s): '{count} பிற சேனல்களிலிருந்து சந்தாவை அகற்று)'\n  Added channel to your subscriptions: 'உங்கள் சந்தாக்களில் சேனல் சேர்க்கப்பட்டது'\n  Search Channel: 'சேனல் தேடல்'\n  Your search results have returned 0 results: 'உங்கள் தேடல் முடிவுகள் 0 முடிவுகளைத் தருகின்றன'\n  This channel does not exist: 'இந்த சேனல் இல்லை'\n  This channel does not allow searching: 'இந்த சேனல் தேடலை அனுமதிக்காது'\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 'இந்த சேனல் வயதுக்கு தடை விதிக்கப்பட்டுள்ளது, தற்போது ஃப்ரீட்யூப்பில் பார்க்க முடியாது.'\n  Channel Tabs: 'சேனல் தாவல்கள்'\n  Videos:\n    Videos: 'வீடியோக்கள்'\n    This channel does not currently have any videos: 'இந்த சேனலில் தற்போது எந்த வீடியோக்களும் இல்லை'\n    Sort Types:\n      Newest: 'புதியது'\n      Oldest: 'பழமையானது'\n      Most Popular: 'மிகவும் பிரபலமானது'\n  Shorts:\n    This channel does not currently have any shorts: 'இந்த சேனலில் தற்போது குறும்படங்கள் இல்லை'\n  Live:\n    Live: 'வாழ'\n    This channel does not currently have any live streams: 'இந்த சேனலில் தற்போது நேரடி நீரோடைகள் இல்லை'\n  Playlists:\n    Playlists: 'பிளேலிச்ட்கள்'\n    This channel does not currently have any playlists: 'இந்த சேனலில் தற்போது எந்த பிளேலிச்ட்களும் இல்லை'\n    Sort Types:\n      Last Video Added: 'கடைசி வீடியோ சேர்க்கப்பட்டது'\n      Newest: 'புதியது'\n      Oldest: 'பழமையானது'\n  Podcasts:\n    Podcasts: 'பாட்காச்ட்கள்'\n    This channel does not currently have any podcasts: 'இந்த சேனலில் தற்போது எந்த பாட்காச்ட்களும் இல்லை'\n  Releases:\n    Releases: 'வெளியீடுகள்'\n    This channel does not currently have any releases: 'இந்த சேனலில் தற்போது எந்த வெளியீடுகளும் இல்லை'\n  About:\n    About: 'பற்றி'\n    Channel Description: 'சேனல் விளக்கம்'\n    Tags:\n      Tags: 'குறிச்சொற்கள்'\n      Search for: '\"{tag}\" ஐத் தேடுங்கள்'\n    Details: 'விவரங்கள்'\n    Joined: 'இணைந்தது'\n    Location: 'இடம்'\n    Featured Channels: 'பிரத்யேக சேனல்கள்'\n  Posts:\n    This channel currently does not have any posts: 'இந்த சேனலில் தற்போது எந்த இடுகைகளும் இல்லை'\n    votes: '{votes} வாக்குகள்'\n    View Full Post: 'முழு இடுகையைக் காண்க'\n    Reveal Answers: 'பதில்களை வெளிப்படுத்துங்கள்'\n    Hide Answers: 'பதில்களை மறைக்கவும்'\n    Video hidden by FreeTube: 'ஃப்ரீட்யூப் மறைத்த வீடியோ'\n    Viewing Posts Only Supported By Invidious: 'இடுகைகளைப் பார்ப்பது வெறுப்புடன் மட்டுமே ஆதரிக்கப்படுகிறது. வன்கவர்வு இல்லாமல் உள்ளடக்கத்தைக் காண சேனலின் சமூக தாவலுக்குச் செல்லுங்கள்.'\n  Home:\n    Home: வீடு\n    View Playlist: பிளேலிச்ட்டைக் காண்க\n  Courses:\n    Courses: படிப்புகள்\n    This channel does not currently have any courses: இந்த சேனலில் தற்போது எந்த படிப்புகளும் இல்லை\nVideo:\n  IP block: 'உங்கள் ஐபி முகவரியை வீடியோக்களைப் பார்ப்பதிலிருந்து YouTube தடுத்துள்ளது. தயவுசெய்து வேறு VPN அல்லது ப்ராக்சிக்கு மாற முயற்சிக்கவும்.'\n  MembersOnly: 'கூகிள் உள்நுழைவு மற்றும் பதிவேற்றியவரின் சேனலுக்கு பணம் செலுத்தும் உறுப்பினர் தேவைப்படுவதால் உறுப்பினர்கள் மட்டும் வீடியோக்களைப் பார்க்க முடியாது.'\n  AgeRestricted: 'கூகிள் உள்நுழைவு தேவைப்படுவதால், வயதுக்குட்பட்ட வீடியோக்களைப் பார்க்க முடியாது, ஏனெனில் அவை கூகிள் உள்நுழைவு மற்றும் அகவை சரிபார்க்கப்பட்ட யூடியூப் கணக்கைப் பயன்படுத்துகின்றன.'\n  More Options: 'மேலும் விருப்பங்கள்'\n  Mark As Watched: 'பார்த்தபடி குறி'\n  Remove From History: 'வரலாற்றிலிருந்து அகற்று'\n  Video has been marked as watched: 'வீடியோ பார்த்தபடி குறிக்கப்பட்டுள்ளது'\n  Video has been removed from your history: 'உங்கள் வரலாற்றிலிருந்து வீடியோ அகற்றப்பட்டுள்ளது'\n  Save Video: 'வீடியோவை சேமிக்கவும்'\n  Video has been saved: 'வீடியோ சேமிக்கப்பட்டுள்ளது'\n  Video has been removed from your saved list: 'உங்கள் சேமித்த பட்டியலிலிருந்து வீடியோ அகற்றப்பட்டுள்ளது'\n  Open in YouTube: 'YouTube இல் திறக்கவும்'\n  Copy YouTube Link: 'YouTube இணைப்பை நகலெடுக்கவும்'\n  Open YouTube Embedded Player: 'YouTube உட்பொதிக்கப்பட்ட பிளேயரைத் திறக்கவும்'\n  Copy YouTube Embedded Player Link: 'YouTube உட்பொதிக்கப்பட்ட பிளேயர் இணைப்பை நகலெடுக்கவும்'\n  Open in Invidious: 'ஆவேசமாக திறந்திருக்கும்'\n  Copy Invidious Link: 'ஆவேசமான இணைப்பை நகலெடுக்கவும்'\n  Open Channel in YouTube: 'YouTube இல் சேனலைத் திறக்கவும்'\n  Copy YouTube Channel Link: 'YouTube சேனல் இணைப்பை நகலெடுக்கவும்'\n  Open Channel in Invidious: 'திறமைக்கு திறந்த சேனல்'\n  Copy Invidious Channel Link: 'ஆவேசமான சேனல் இணைப்பை நகலெடுக்கவும்'\n  Hide Channel: 'சேனலை மறைக்கவும்'\n  Unhide Channel: 'சேனலைக் காட்டு'\n  Views: 'காட்சிகள்'\n  Loop Playlist: 'லூப் பிளேலிச்ட்'\n  Shuffle Playlist: 'கலக்கு பிளேலிச்ட்'\n  Reverse Playlist: 'தலைகீழ் பிளேலிச்ட்'\n  Previous: 'முந்தையது'\n  Next: 'அடுத்து'\n  Watched: 'பார்த்தேன்'\n  Autoplay: 'ஆட்டோபிளே'\n  Starting soon, please refresh the page to check again: 'விரைவில் தொடங்கி, மீண்டும் சரிபார்க்க பக்கத்தைப் புதுப்பிக்கவும்'\n  # As in a Live Video\n  Premieres: 'பிரீமியர்ச்'\n  Upcoming: 'வரவிருக்கும்'\n  Unlisted: 'பட்டியலிடப்படாதது'\n  Live: 'வாழ'\n  Live Now: 'இப்போது வாழ்க'\n  Live Chat: 'நேரடி அரட்டை'\n  Enable Live Chat: 'நேரடி அரட்டையை இயக்கவும்'\n  Live Chat is currently not supported in this build.: 'இந்த கட்டமைப்பில் நேரடி அரட்டை தற்போது ஆதரிக்கப்படவில்லை.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'நேரடி அரட்டை இயக்கப்பட்டது. அரட்டை செய்திகள் அனுப்பப்பட்டவுடன் இங்கே தோன்றும்.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'லைவ் அரட்டை தற்போது ஆக்ச் பநிஇ உடன் ஆதரிக்கப்படவில்லை. YouTube க்கு நேரடி இணைப்பு தேவை.'\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 'இந்த ச்ட்ரீமுக்கு நேரடி அரட்டை கிடைக்கவில்லை. இது பதிவேற்றியவரால் முடக்கப்பட்டிருக்கலாம்.'\n  Show Super Chat Comment: 'சூப்பர் அரட்டை கருத்தைக் காட்டு'\n  Scroll to Bottom: 'கீழே உருட்டவும்'\n  Published:\n    Jan: ''\n    Feb: ''\n    Mar: ''\n    Apr: ''\n    May: ''\n    Jun: ''\n    Jul: ''\n    Aug: ''\n    Sep: ''\n    Oct: ''\n    Nov: ''\n    Dec: ''\n    Second: ''\n    Seconds: ''\n    Minute: ''\n    Minutes: ''\n    Hour: ''\n    Hours: ''\n    Day: ''\n    Days: ''\n    Week: ''\n    Weeks: ''\n    Month: ''\n    Months: ''\n    Year: ''\n    Years: ''\n    Ago: ''\n    Upcoming: ''\n    In less than a minute: 'ஒரு நிமிடத்திற்குள்'\n  Published on: 'வெளியிடப்பட்டது'\n  Streamed on: 'ச்ட்ரீம் செய்யப்பட்டது'\n  Started streaming on: 'ச்ட்ரீமிங் செய்யத் தொடங்கியது'\n  Publicationtemplate: ''\n  Sponsor Block category:\n    sponsor: 'ஒப்புரவாளர்'\n    intro: 'அறிமுகம்'\n    outro: 'மற்றொன்று'\n    self-promotion: 'தன்வய ஊக்குவிப்பு'\n    interaction: 'உள்வினை'\n    music offtopic: 'மியூசிக் ஆஃப் டோபிக்'\n    recap: 'மறுபரிசீலனை செய்யுங்கள்'\n    filler: 'தடி'\n  External Player:\n    OpenInTemplate: '{externalPlayer} இல் திறக்கவும்'\n    video: 'ஒளிதோற்றம்'\n    playlist: 'பிளேலிச்ட்'\n    OpeningTemplate: '{videoOrPlaylist} இல் {externalPlayer} ஐ திறக்கிறது ...'\n    UnsupportedActionTemplate: '{externalPlayer} ஆதரிக்கவில்லை: {action}'\n    Unsupported Actions:\n      starting video at offset: 'ஆஃப்செட்டில் வீடியோவைத் தொடங்குகிறது'\n      setting a playback rate: 'பிளேபேக் வீதத்தை அமைத்தல்'\n      opening playlists: 'பிளேலிச்ட்களைத் திறக்கிறது'\n      opening specific video in a playlist (falling back to opening the video): 'ஒரு பிளேலிச்ட்டில் குறிப்பிட்ட வீடியோவைத் திறக்கிறது (வீடியோவைத் திறக்க மீண்டும் விழுகிறது)'\n      reversing playlists: 'பிளேலிச்ட்களை மாற்றியமைத்தல்'\n      shuffling playlists: 'பிளேலிச்ட்களை மாற்றவும்'\n      looping playlists: 'பிளேலிச்ட்கள் வளையங்கள்'\n  Player:\n    TranslatedCaptionTemplate: '{language} (\"{originalLanguage}\" இலிருந்து மொழிபெயர்க்கப்பட்டுள்ளது)'\n    Audio Tracks: 'ஆடியோ தடங்கள்'\n    Theatre Mode: 'தியேட்டர் பயன்முறை'\n    Exit Theatre Mode: 'தியேட்டர் பயன்முறையில் இருந்து வெளியேறவும்'\n    Full Window: 'முழு சாளரம்'\n    Exit Full Window: 'முழு சாளரத்திலிருந்து வெளியேறவும்'\n    Take Screenshot: 'திரைக்காட்சி எடுத்துக் கொள்ளுங்கள்'\n    Show Stats: 'புள்ளிவிவரங்களைக் காட்டு'\n    Hide Stats: 'புள்ளிவிவரங்களை மறைக்கவும்'\n    Stats:\n      Stats: 'புள்ளிவிவரங்கள்'\n      Video ID: 'வீடியோ ஐடி: {videoId}'\n      Media Formats: 'ஊடக வடிவங்கள்: {formats}'\n      Resolution: 'தீர்மானம்: {width} ஃச் {height}{''@''}{frameRate}'\n      Player Dimensions: 'பிளேயர் பரிமாணங்கள்: {width} ஃச் {height}'\n      Bitrate: 'பிட்ரேட்: {bitrate} kbps'\n      Volume: 'தொகுதி: {volumePercentage}%'\n      Bandwidth: 'அலைவரிசை: {bandwidth} kbps'\n      Buffered: 'இடையக: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'கைவிடப்பட்ட பிரேம்கள்: {droppedFrames} / மொத்த பிரேம்கள்: {totalFrames}'\n      CodecAudio: 'கோடெக்: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'கோடெக்குகள்: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'கோடெக்குகள்: {videoCodec} / {audioCodec}'\n    You appear to be offline: 'நீங்கள் ஆஃப்லைனில் இருப்பதாகத் தெரிகிறது.'\n    Playback will resume automatically when your connection comes back: 'உங்கள் இணைப்பு மீண்டும் வரும்போது பிளேபேக் தானாகவே மீண்டும் தொடங்கும்.'\n    Skipped segment: '{segmentCategory} பிரிவு தவிர்க்கப்பட்டது'\n#& Videos\n    Autoplay is off: ஆட்டோபிளே முடக்கப்பட்டுள்ளது\n    Autoplay is on: ஆட்டோபிளே இயக்கத்தில் உள்ளது\n  DeArrow:\n    Show Original Details: அசல் விவரங்களைக் காட்டு\n    Show Modified Details: மாற்றியமைக்கப்பட்ட விவரங்களைக் காட்டு\n#& Playlists\n  DRMProtected: டி.ஆர்.எம் பாதுகாக்கப்பட்ட வீடியோக்களை ஃப்ரீட்யூப்பில் இயக்க முடியாது, ஏனெனில் அவற்றுக்கு தனியுரிம, மூடிய மூல கூறுகள் தேவைப்படுகின்றன. இந்த வீடியோவைப் பார்க்க விரும்பினால், அதை அதிகாரப்பூர்வ YouTube இணையதளத்தில் DRM இயக்கப்பட்ட வலை உலாவியில் பார்க்கவும்.\n  Save Watched Progress: பார்த்த முன்னேற்றத்தை சேமிக்கவும்\n  Watched Progress Saved: முன்னேற்றம் காப்பாற்றப்பட்டது\n  Popout Live Chat: பாப்அவுட் அரட்டை\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'மீதமுள்ள முன் விளம்பர நேரம்: {நினைவூட்டும் நேர விநாடிகள்'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'மீதமுள்ள SABR பேக்ஆஃப் நேரம்: {remindingTimeSeconds}கள்'\nPlaylist:\n  #& About\n  Playlist: 'பிளேலிச்ட்'\n  View Full Playlist: 'முழு பிளேலிச்ட்டைக் காண்க'\n  Last Updated On: 'கடைசியாக புதுப்பிக்கப்பட்டது'\n  Sort By:\n    DateAddedNewest: 'சேர்க்கப்பட்ட தேதி (புதிது)'\n    DateAddedOldest: 'சேர்க்கப்பட்ட தேதி (பழையது)'\n    AuthorAscending: 'ஆசிரியர் (A-Z)'\n    AuthorDescending: 'ஆசிரியர் (Z-A)'\n    VideoTitleAscending: 'தலைப்பு (A-Z)'\n    VideoTitleDescending: 'தலைப்பு (Z-A)'\n    VideoDurationAscending: 'கால அளவு (குறுகிய)'\n    VideoDurationDescending: 'கால அளவு (நீண்ட)'\n    Custom: 'தனிப்பயன்'\n\n# On Video Watch Page\n#* Published\n#& Views\n    PublishedNewest: வெளியிடப்பட்ட தேதி (புதிது)\n    PublishedOldest: வெளியிடப்பட்ட தேதி (பழையது)\nChange Format:\n  Change Media Formats: 'ஊடக வடிவங்களை மாற்றவும்'\n  Use Dash Formats: 'கோடு வடிவங்களைப் பயன்படுத்துங்கள்'\n  Use Legacy Formats: 'மரபு வடிவங்களைப் பயன்படுத்துங்கள்'\n  Use Audio Formats: 'ஆடியோ வடிவங்களைப் பயன்படுத்துங்கள்'\n  Dash formats are not available for this video: 'இந்த வீடியோவுக்கு கோடு வடிவங்கள் கிடைக்கவில்லை'\n  Audio formats are not available for this video: 'இந்த வீடியோவுக்கு ஆடியோ வடிவங்கள் கிடைக்கவில்லை'\n  Legacy formats are not available for this video: 'இந்த வீடியோவுக்கு மரபு வடிவங்கள் கிடைக்கவில்லை'\nShare:\n  Share Video: 'வீடியோவைப் பகிரவும்'\n  Share Channel: 'சேனலைப் பகிரவும்'\n  Share Playlist: 'பிளேலிச்ட்டைப் பகிரவும்'\n  Include Timestamp: 'நேர முத்திரை சேர்க்கவும்'\n  Copy Link: 'இணைப்பை நகலெடுக்கவும்'\n  Open Link: 'இணைப்பை திற'\n  Copy Embed: 'நகல் உட்பொதிக்க'\n  Open Embed: 'திறந்த உட்பொதி'\n  # On Click\n  Invidious URL copied to clipboard: 'இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்ட ஆவேசம் முகவரி'\n  Invidious Embed URL copied to clipboard: 'இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்ட ஆக்ச்டிடச் உட்பொதிக்கப்பட்ட முகவரி'\n  Invidious Channel URL copied to clipboard: 'இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்ட ஆப்ச்டிடச் சேனல் முகவரி'\n  YouTube URL copied to clipboard: 'YouTube முகவரி இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டது'\n  YouTube Embed URL copied to clipboard: 'YouTube உட்பொதிக்கப்பட்ட முகவரி இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டது'\n  YouTube Channel URL copied to clipboard: 'YouTube சேனல் முகவரி இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டது'\n  Share Post: இடுகையைப் பகிரவும்\nClipboard:\n  Copy failed: 'இடைநிலைப்பலகைக்கு நகல் தோல்வியடைந்தது'\n  Cannot access clipboard without a secure connection: 'பாதுகாப்பான இணைப்பு இல்லாமல் கிளிப்போர்டை அணுக முடியாது'\n\nChapters:\n  Chapters: 'பாடங்கள்'\n\n  Key Moments: முக்கிய தருணங்கள்\nMini Player: 'மினி பிளேயர்'\nComments:\n  Comments: 'கருத்துகள்'\n  Click to View Comments: 'கருத்துகளைக் காண சொடுக்கு செய்க'\n  Getting comment replies, please wait: 'கருத்து பதில்களைப் பெறுதல், தயவுசெய்து காத்திருங்கள்'\n  There are no more comments for this video: 'இந்த வீடியோவுக்கு இனி கருத்துகள் இல்லை'\n  Hide Comments: 'கருத்துகளை மறைக்கவும்'\n  Top comments: 'சிறந்த கருத்துகள்'\n  Newest first: 'புதிய முதல்'\n  View {replyCount} replies: '1 பதிலைக் காண்க | {replyCount} பதில்களைக் காண்க'\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: 'மேலும் பதில்களைக் காட்டு'\n  There are no comments available for this video: 'இந்த வீடியோவுக்கு எந்தக் கருத்தும் கிடைக்கவில்லை'\n  There are no comments available for this post: 'இந்த இடுகைக்கு எந்தக் கருத்தும் கிடைக்கவில்லை'\n  Load More Comments: 'மேலும் கருத்துகளை ஏற்றவும்'\n  Pinned by: 'பின்'\n  Member: 'உறுப்பினர்'\n  Subscribed: 'சந்தா கட்டப்பட்டது'\n  Hearted: 'இதயமுள்ள'\n\n  Hide {replyCount} replies: 1 பதிலை மறை | {replyCount} பதில்களை மறை\n  View 1 reply from {channelName}: '{channelName} இடமிருந்து 1 பதிலைக் காண்க'\n  View {replyCount} replies from {channelName} and others: '{channelName} மற்றும் பிறவற்றின் {replyCount} பதில்களைப் பார்க்கவும்'\nUp Next: 'அடுத்து'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'தரவைப் பெற ஃப்ரீட்யூப் பயன்படுத்தும் பின்தளத்தில் தேர்வு செய்யவும். உள்ளக பநிஇ ஒரு உள்ளமைக்கப்பட்ட பிரித்தெடுத்தல். வன்கவர்வு பநிஇ உடன் இணைக்க ஒரு விலக்கப்பட்ட சேவையகம் தேவைப்படுகிறது.'\n    Fallback to Non-Preferred Backend on Failure: 'உங்களுக்கு விருப்பமான பநிஇ க்கு சிக்கல் இருக்கும்போது, உங்கள் விருப்பமில்லாத பநிஇ ஐ இயக்கும்போது குறைவடையும் முறையாக FREETube தானாகவே பயன்படுத்த முயற்சிக்கும்.'\n    Thumbnail Preference: 'ஃப்ரீட்யூப் முழுவதும் உள்ள அனைத்து சிறு உருவங்களும் வீடியோவின் சட்டத்துடன் மாற்றப்படும், இயல்புநிலை சிறுபடத்திற்கு பதிலாக மங்கலாக அல்லது மறைக்கப்படும்.'\n    Invidious Instance: 'பநிஇ அழைப்புகளுக்காக ஃப்ரீட்யூப் இணைக்கும் மோசமான நிகழ்வு.'\n    Region for Trending: 'நீங்கள் காண்பிக்க விரும்பும் நாட்டின் பிரபலமான வீடியோக்களைத் தேர்வுசெய்ய போக்குகளின் பகுதி உங்களை அனுமதிக்கிறது.'\n    External Link Handling: |\n      ஃப்ரீட்யூப்பில் திறக்க முடியாத ஒரு இணைப்பு சொடுக்கு செய்யப்படும்போது இயல்புநிலை நடத்தையைத் தேர்வுசெய்க.\n       இயல்பாக ஃப்ரீட்யூப் உங்கள் இயல்புநிலை உலாவியில் சொடுக்கு செய்யப்பட்ட இணைப்பைத் திறக்கும்.\n    Open Deep Links In New Window: முகவரி கள் ஃப்ரீட்யூப்பிற்கு அனுப்பப்பட்டன, அதாவது திருப்பி உலாவி நீட்டிப்புகள் அல்லது கட்டளை வரி வாதங்கள் போன்றவை புதிய சாளரத்தில் திறக்கப்படுகின்றன.\n  Player Settings:\n    Proxy Videos Through Invidious: 'YouTube உடன் நேரடி இணைப்பை உருவாக்குவதற்கு பதிலாக வீடியோக்களை வழங்குவதற்கு ஆக்கிரமிப்புடன் இணைக்கும்.'\n    Default Video Format: 'வீடியோ விளையாடும்போது பயன்படுத்தப்படும் வடிவங்களை அமைக்கவும். கோடு வடிவங்கள் அதிக குணங்களை விளையாடலாம். மரபு வடிவங்கள் அதிகபட்சம் 360p க்கு மட்டுப்படுத்தப்பட்டுள்ளன, ஆனால் குறைந்த அலைவரிசையைப் பயன்படுத்துகின்றன. ஆடியோ வடிவங்கள் ஆடியோ மட்டுமே ச்ட்ரீம்கள்.'\n    Scroll Playback Rate Over Video Player: 'கர்சர் வீடியோவின் மேல் இருக்கும்போது, கட்டுப்பாட்டு விசையை (மேக்கில் கட்டளை விசை) அழுத்திப் பிடித்து, பின்னணி விகிதத்தைக் கட்டுப்படுத்த சுட்டி சக்கரத்தை முன்னோக்கி அல்லது பின்னோக்கி உருட்டவும். கட்டுப்பாட்டு விசையை (மேக்கில் கட்டளை விசை) அழுத்திப் பிடித்துக் கொள்ளுங்கள் மற்றும் இயல்புநிலை பின்னணி விகிதத்திற்கு விரைவாக திரும்புவதற்கு சுட்டியைக் சொடுக்கு செய்க (அமைப்புகளில் மாற்றப்படாவிட்டால் 1x).'\n    Skip by Scrolling Over Video Player: 'வீடியோ, எம்.பி.வி பாணி மூலம் தவிர்க்க உருள் சக்கரத்தைப் பயன்படுத்தவும்.'\n  External Player Settings:\n    External Player: 'வெளிப்புற பிளேயரைத் தேர்ந்தெடுப்பது ஒரு ஐகானைக் காண்பிக்கும், சிறுபடத்தில் வெளிப்புற பிளேயரில் வீடியோவை (பிளேலிச்ட் என்றால்) திறக்க வேண்டும். எச்சரிக்கை, அடக்கமற்ற அமைப்புகள் வெளிப்புற வீரர்களை பாதிக்காது.'\n    Custom External Player Executable: 'இயல்பாக, தேர்ந்தெடுக்கப்பட்ட வெளிப்புற பிளேயரை பாதை சூழல் மாறி வழியாகக் காணலாம் என்று ஃப்ரீட்யூப் கருதுகிறது. தேவைப்பட்டால், தனிப்பயன் பாதையை இங்கே அமைக்கலாம்.'\n    Ignore Warnings: 'தற்போதைய வெளிப்புற பிளேயர் தற்போதைய செயலை ஆதரிக்காதபோது எச்சரிக்கைகளை அடக்கவும் (எ.கா. பிளேலிச்ட்களை மாற்றியமைத்தல் போன்றவை).'\n    Ignore Default Arguments: 'வீடியோ முகவரி (எ.கா. பிளேபேக் வீதம், பிளேலிச்ட் முகவரி, முதலியன) தவிர்த்து வெளிப்புற பிளேயருக்கு எந்த இயல்புநிலை வாதங்களையும் அனுப்ப வேண்டாம். தனிப்பயன் வாதங்கள் இன்னும் அனுப்பப்படும்.'\n    Custom External Player Arguments: 'எந்தவொரு தனிப்பயன் கட்டளை வரி வாதங்களும் நீங்கள் வெளிப்புற பிளேயருக்கு அனுப்பப்பட வேண்டும்.'\n    DefaultCustomArgumentsTemplate: \"(இயல்புநிலை: '{defaultCustomArguments}')\"\n  Distraction Free Settings:\n    Hide Channels: 'அனைத்து வீடியோக்கள், பிளேலிச்ட்கள் மற்றும் சேனலை தேட, பிரபலமான, மிகவும் பிரபலமான மற்றும் பரிந்துரைக்கப்படுவதிலிருந்து மறைக்க ஒரு சேனல் ஐடியை உள்ளிடவும். உள்ளிடப்பட்ட சேனல் ஐடி ஒரு முழுமையான பொருத்தமாக இருக்க வேண்டும் மற்றும் வழக்கு உணர்திறன் கொண்டது.'\n    Hide Subscriptions Live: 'இந்த அமைப்பு \"{appWideSetting}\" இன் \"{subsection}\" பிரிவில், பயன்பாட்டு அளவிலான \"{settingsSection}\" அமைப்பால் மீறப்பட்டுள்ளது'\n    Hide Videos, Playlists and Channels Containing Text: 'அனைத்து வீடியோக்களையும் பிளேலிச்ட்களையும் மறைக்க ஒரு சொல், சொல் துண்டு அல்லது சொற்றொடர் (வழக்கு உணர்வற்றது) உள்ளிடவும், அதன் அசல் தலைப்புகள் அனைத்து ஃப்ரீட்யூப் முழுவதும் உள்ளன, வரலாறு, உங்கள் பிளேலிச்ட்கள் மற்றும் வீடியோக்களை பிளேலிச்ட்களுக்குள் தவிர்த்து.'\n    Hide Videos on Watch: சந்தா மற்றும் சேனல் பக்கங்களில் உள்ள வீடியோ, சார்ட்ச் மற்றும் லைவ் டேப்களில் இருந்து பார்த்த வீடியோக்களை மறைக்கவும். இது சேனல் பக்கங்களில் உள்ள முகப்பு தாவலைப் பாதிக்காது\n  Subscription Settings:\n    Fetch Feeds from RSS: 'இயக்கப்பட்டால், உங்கள் சந்தா ஊட்டத்தைப் பிடிக்க அதன் இயல்புநிலை முறைக்கு பதிலாக RSS ஐப் பயன்படுத்தும். ஆர்எச்எச் வேகமானது மற்றும் ஐபி தடுப்பதைத் தடுக்கிறது, ஆனால் வீடியோ காலம், நேரடி நிலை அல்லது இடுகைகள் போன்ற சில தகவல்களை வழங்காது'\n    Fetch Automatically: 'இயக்கப்பட்டால், தொடக்கத்தில் உங்கள் சந்தா ஊட்டத்தையும் புதிய சாளரம் திறக்கப்படும் போது ஃப்ரீட்யூப் தானாகவே பெறும்.'\n  Experimental Settings:\n    Replace HTTP Cache: 'எலக்ட்ரானின் வட்டு அடிப்படையிலான HTTP தற்காலிக சேமிப்பை முடக்குகிறது மற்றும் தனிப்பயன் இன்-மெமரி பட தற்காலிக சேமிப்பை செயல்படுத்துகிறது. ரேம் பயன்பாடு அதிகரிக்க வழிவகுக்கும்.'\n  SponsorBlock Settings:\n    UseDeArrowTitles: 'டியரோவிலிருந்து பயனர் சமர்ப்பித்த தலைப்புகளுடன் வீடியோ தலைப்புகளை மாற்றவும்.'\n    UseDeArrowThumbnails: 'டியர்ரோவிலிருந்து சிறுபடங்களுடன் வீடியோ சிறு உருவங்களை மாற்றவும்.'\n\n# Toast Messages\nLocal API Error (Click to copy): 'உள்ளக பநிஇ பிழை (நகலெடுக்க சொடுக்கு செய்க)'\nInvidious API Error (Click to copy): 'ஆவேசம் பநிஇ பிழை (நகலெடுக்க சொடுக்கு செய்க)'\nFalling back to Invidious API: 'அகங்காத ஏபிஐக்கு மீண்டும் விழுகிறது'\nFalling back to Local API: 'உள்ளக ஏபிஐக்கு மீண்டும் விழுகிறது'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'வடிவங்கள் காணாமல் போனதால் இந்த வீடியோ கிடைக்கவில்லை. நாடு கிடைக்காததால் இது நிகழலாம்.'\nUnknown YouTube url type, cannot be opened in app: 'அறியப்படாத YouTube முகவரி வகை, பயன்பாட்டில் திறக்க முடியாது'\nLoop is now disabled: 'லூப் இப்போது முடக்கப்பட்டுள்ளது'\nLoop is now enabled: 'லூப் இப்போது இயக்கப்பட்டது'\nShuffle is now disabled: 'கலக்கு இப்போது முடக்கப்பட்டுள்ளது'\nShuffle is now enabled: 'கலக்கு இப்போது இயக்கப்பட்டது'\nThe playlist has been reversed: 'பிளேலிச்ட் தலைகீழாக மாற்றப்பட்டுள்ளது'\nPlaying Next Video: 'அடுத்த வீடியோவை வாசித்தல்'\nPlaying Previous Video: 'முந்தைய வீடியோவை வாசித்தல்'\nPlaying Next Video Interval: 'எந்த நேரத்திலும் அடுத்த வீடியோவை இயக்குகிறது. ரத்து செய்ய சொடுக்கு செய்க. | அடுத்த வீடியோவை {nextVideoInterval} இரண்டாவதாக இயக்குகிறது. ரத்து செய்ய சொடுக்கு செய்க. | அடுத்த வீடியோவை {nextVideoInterval} வினாடிகளில் வாசித்தல். ரத்து செய்ய சொடுக்கு செய்க.'\nCanceled next video autoplay: 'அடுத்த வீடியோ ஆட்டோபிளே ரத்து செய்யப்பட்டது'\n\nDefault Invidious instance has been set to {instance}: 'இயல்புநிலை விலக்கு நிகழ்வு {instance} என அமைக்கப்பட்டுள்ளது'\nDefault Invidious instance has been cleared: 'இயல்புநிலை வன்கவர்வு நிகழ்வு அழிக்கப்பட்டது'\n'The playlist has ended. Enable loop to continue playing': 'பிளேலிச்ட் முடிந்தது. தொடர்ந்து விளையாடுவதற்கு லூப் இயக்கவும்'\nAge Restricted:\n  This channel is age restricted: 'இந்த சேனல் அகவை தடைசெய்யப்பட்டுள்ளது'\n  This video is age restricted: 'இந்த வீடியோ அகவை தடைசெய்யப்பட்டுள்ளது'\nExternal link opening has been disabled in the general settings: 'பொது அமைப்புகளில் வெளிப்புற இணைப்பு திறப்பு முடக்கப்பட்டுள்ளது'\nScreenshot Success: 'சேமித்த திரை காட்சி'\nScreenshot Error: 'திரைக்காட்சி தோல்வியடைந்தது. {error}'\nChannel Hidden: '{channel} the சேனல் வடிகட்டியில் சேர்க்கப்பட்டுள்ளது'\nChannel Unhidden: '{channel} the சேனல் வடிகட்டியிலிருந்து அகற்றப்பட்டது'\nTrimmed input must be at least N characters long: 'ஒழுங்கமைக்கப்பட்ட உள்ளீடு குறைந்தது 1 எழுத்து நீளமாக இருக்க வேண்டும் | ஒழுங்கமைக்கப்பட்ட உள்ளீடு குறைந்தது {length} எழுத்துக்கள் நீளமாக இருக்க வேண்டும்'\nTag already exists: '\"{tagName}\" குறிச்சொல் ஏற்கனவே உள்ளது'\n\nHashtag:\n  Hashtag: 'ஏச்டேக்'\n  This hashtag does not currently have any videos: 'இந்த ஏச்டேக்கில் தற்போது எந்த வீடியோக்களும் இல்லை'\nMoments Ago: 'தருணங்களுக்கு முன்பு'\nYes: 'ஆம்'\nNo: 'இல்லை'\nOk: 'சரி'\nYes, Delete: 'ஆம், நீக்கு'\nYes, Restart: 'ஆம், மறுதொடக்கம் செய்யுங்கள்'\nYes, Open Link: 'ஆம், திறந்த இணைப்பு'\nCancel: 'ரத்துசெய்'\n# symbol used to indicate that an item is correct\ncheckmark: '✓'\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: '{label}: {value}'\nDescription:\n  Expand Description: '... மேலும்'\n  Collapse Description: குறைவாகக் காட்டு\nAutoplay Interruption Timer: '{autoplayInterruptionIntervalHours} மணிநேர செயலற்ற தன்மை காரணமாக ஆட்டோபிளே ரத்து செய்யப்பட்டது'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nKeys:\n  arrowup: அம்பு\n  alt: மாற்று\n  arrowdown: கீழ் அம்பு\n  arrowleft: இடது அம்பு\n  ctrl: கட்டுப்பாடு\n  arrowright: வலது அம்பு\n  shift: உயர்த்து\n  enter: உள்ளிடவும்\n  plus: பிளச்\nshortcutJoinOperator: +\nRight-click or hold to see history: வரலாற்றைக் காண வலது சொடுக்கு செய்யவும் அல்லது வைத்திருங்கள்\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: டெவலப்பர் கருவிகளை நிலைமாற்று\n  Zoom In: பெரிதாக்கு\n  Zoom Out: சிறிதாக்கு\n  Fullscreen: மாற்று முழுத்திரை\n  Keyboard Shortcuts: விசைப்பலகை குறுக்குவழிகள்\n  Sections:\n    Video:\n      Playback: 'வீடியோ: பின்னணி'\n      General: 'வீடியோ: பொது'\n    App:\n      Situational: 'பயன்பாடு: சூழ்நிலை'\n      General: 'பயன்பாடு: பொது'\n  Show Keyboard Shortcuts: விசைப்பலகை குறுக்குவழிகளைக் காட்டு\n  History Backward: ஒரு பக்கத்திற்கு திரும்பிச் செல்லுங்கள்\n  History Forward: ஒரு பக்கத்தை முன்னோக்கி செல்லுங்கள்\n  New Window: புதிய சாளரத்தை உருவாக்கவும்\n  Navigate to Settings: அமைப்புகள் பக்கத்திற்கு செல்லவும்\n  Navigate to History: வரலாற்று பக்கத்திற்கு செல்லவும்\n  Refresh: அண்மைக் கால உள்ளடக்கத்துடன் ஊட்டத்தைப் புதுப்பிக்கவும்\n  Focus Secondary Search: இரண்டாம் நிலை தேடல் பட்டியில் கவனம் செலுத்துங்கள் (ஒன்று இருந்தால்)\n  Captions: தலைப்புகளை/முடக்கவும்\n  Stats: வீடியோ புள்ளிவிவரங்களைக் காட்டு\n  Picture in Picture: படம்-இன்-பட பயன்முறையை மாற்றவும்\n  Large Rewind: தற்போதைய வீடியோ பிளேபேக் வீதத்தின் அடிப்படையில் 10 வினாடிகள் / ரிவைண்ட் வீடியோ\n  Play: விளையாட்டு/இடைநிறுத்தத்தை மாற்றவும்\n  Large Fast Forward: தற்போதைய வீடியோ பிளேபேக் வீதத்தின் அடிப்படையில் 10 வினாடிகள் / வேகமாக முன்னோக்கி வீடியோ\n  Mute: ஊமியை மாற்றவும்\n  Decrease Video Speed: வீடியோ பிளேபேக் வீத இடைவெளியின் அடிப்படையில் வீடியோ வேகத்தைக் குறைக்கவும்\n  Increase Video Speed: வீடியோ பிளேபேக் வீத இடைவெளியின் அடிப்படையில் வீடியோ வேகத்தை அதிகரிக்கவும்\n  Full Window: முழு சாளரத்தையும் மாற்றவும்\n  Theatre Mode: தியேட்டர் பயன்முறையை மாற்றவும்\n  Take Screenshot: திரைக்காட்சி எடுத்துக் கொள்ளுங்கள்\n  Minimize Window: சாளரத்தைக் குறைக்கவும்\n  Close Window: சாளரத்தை மூடு\n  Reset Zoom: சூம் நிலை / இடைமுகம் அளவை மீட்டமைக்கவும்\n  Focus Search: தேடல் பட்டியில் கவனம் செலுத்துங்கள்\n  Search in New Window: புதிய சாளரத்தில் தேடுங்கள்\n  Last Frame: முந்தைய சட்டகம் (இடைநிறுத்தப்படும்போது)\n  Next Frame: அடுத்த சட்டகம் (இடைநிறுத்தப்படும்போது)\n  Volume Up: அளவை அதிகரிக்கவும்\n  Volume Down: அளவைக் குறைக்கவும்\n  Small Rewind: ரிவைண்ட் இடைவெளி மற்றும் தற்போதைய வீடியோ பிளேபேக் வீதத்தின் அடிப்படையில் ஃச் விநாடிகளை முன்னெடு\n  Small Fast Forward: வேகமான முன்னோக்கி ஃச் வினாடிகள் வேகமான முன்னோக்கி இடைவெளி மற்றும் தற்போதைய வீடியோ பிளேபேக் வீதத்தின் அடிப்படையில்\n  Last Chapter: கடைசி அத்தியாயம்\n  Next Chapter: அடுத்த அத்தியாயம்\n  Skip by Tenths: விழுக்காடு மூலம் வீடியோ மூலம் தவிர்க்கவும் (3 காலத்தின் 30% வரை)\n  Home: வீடியோவின் தொடக்கத்தைத் தேடுங்கள்\n  End: வீடியோவின் முடிவைத் தேடுங்கள்\n  Skip to Next Video: பிளேலிச்ட் அல்லது அடுத்த பரிந்துரைக்கப்பட்ட வீடியோவில் அடுத்த வீடியோவைத் தவிர்க்கவும்\n  Skip to Previous Video: பிளேலிச்ட்டில் உள்ள முந்தைய வீடியோவிற்கு செல்க\nshortcutLabelSeparator: ｜\nCompact side navigation: சிறிய பக்க வழிசெலுத்தல்\nExpand side navigation: பக்க வழிசெலுத்தலை விரிவாக்கு\n"
  },
  {
    "path": "static/locales/ti.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'ትግርኛ'\n\n# Webkit Menu Bar\nFile: 'ፋይል'\nNew Window: 'ሓድሽ ገጽ'\nPreferences: 'ምርጫታት'\nQuit: 'ውጻእ'\nUndo: 'ንድሕሪት'\nCut: 'ቍረጽ'\nCopy: 'ቅዳሕ'\nPaste: 'ኣቀብል'\nDelete: 'ደምስሶ'\nSelect all: 'ንዅሉ ምረጽ'\nToggle Developer Tools: 'መሳርሒታት'\nActual size: 'ናይ ሓቂ መጠን'\nToggle fullscreen: 'ምሉእ ኤለክትሮኒካዊ መሳርሒ'\nSearch Filters: {}\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\n  Player Settings: {}\n  SponsorBlock Settings: {}\nChannel:\n  Videos: {}\nVideo:\n  External Player: {}\nTooltips: {}\nAbout:\n  Email: ኢመይል\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: መሳርሒታት\n  Fullscreen: ምሉእ ኤለክትሮኒካዊ መሳርሒ\nProfile:\n  Select All: ንዅሉ ምረጽ\n"
  },
  {
    "path": "static/locales/tok.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'toki pona'\n\n# Webkit Menu Bar\nFile: 'ijo'\nQuit: 'tawa'\nEdit: 'ante'\nUndo: 'tawa monsi'\nRedo: 'tawa sinpin'\nCut: 'kama jo e ni'\nCopy: 'jasima'\nPaste: 'pali jasima'\nDelete: 'weka'\nSelect all: 'kama jo e sitelin ale'\nToggle Developer Tools: 'ante e ilo pi jan nasin'\nActual size: 'suli lon'\nZoom in: 'lukin suli'\nZoom out: 'lukin lili'\nToggle fullscreen: 'ante e sitelin suli'\nWindow: 'lupa'\nMinimize: 'kama lili'\nClose: 'pini'\nBack: 'tawa monsi'\nForward: 'tawa sinpin'\nOpen New Window: 'open lon lupa sin'\n\nVersion {versionNumber} is now available!  Click for more details: 'ilo pi nanpa {versionNumber}\n  li lon! open la, sina ken sona mute'\nDownload From Site: 'kama jo tan lipu'\nA new blog is now available, {blogTitle}. Click to view more: 'lipu sin li lon. ona\n  li {blogTitle}. open la, sina ken lukin mute.'\nAre you sure you want to open this link?: 'sina wile ala wile open e ni?'\n\n# Search Bar\nSearch / Go to URL: 'alasa / tawa lupa'\nSearch Bar:\n  Clear Input: 'weka e sitelin'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'alasa kepeken nasin'\n  Sort By:\n    Most Relevant: 'sama e wile sina'\n    Rating: 'pona'\n  Duration:\n    All Durations: tenpo ali\n    Duration: tenpo\n  Features:\n    Live: tenpo ni\n    3D: 3D\n    4K: 4K\n    HD: HD\n    HDR: HDR\n    VR180: VR180\n  Time:\n    Any Time: tenpo ali\n    Time: tenpo\nSettings:\n  # On Settings Page\n  General Settings: {}\n  Theme Settings: {}\n  Player Settings:\n    Screenshot: {}\n    Default Quality:\n      4k: 4K\n  SponsorBlock Settings: {}\nVideo:\n  External Player: {}\n  Live: tenpo ni\nTooltips: {}\nGlobal:\n  Videos: sitelen tawa\n  Shorts: lili\n  Live: tenpo ni\n  Sort By: 'nasin li seme?'\n  Counts:\n    Video Count: 1 sitelen tawa | {count} sitelen tawa\n    Subscriber Count: 1 jan li kama jo | {count} jan li kama jo\n    View Count: 1 lukin | {count} lukin\n    Watching Count: 1 jan li lukin | {count} jan li lukin\n    Channel Count: 1 toki nasin | {count} toki nasin\n    Like Count: 1 musi | {count} musi\n    Comment Count: 1 toki | {count} toki\nClose Banner: pini e sitelen esun\nNew Window: lupa sin\nPreferences: wile\nGo to page: tawa lipu\nSearch Listing:\n  Label:\n    New: sin\n    4K: 4K\n    8K: 8K\n    360 Video: 360°\nChannel:\n  Live:\n    Live: tenpo ni\nMore: mute\nProfile:\n  Select All: kama jo e sitelin ale\n"
  },
  {
    "path": "static/locales/tr.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Türkçe'\n\n# Webkit Menu Bar\nFile: 'Dosya'\nQuit: 'Çık'\nEdit: 'Düzenle'\nUndo: 'Geri al'\nRedo: 'Yinele'\nCut: 'Kes'\nCopy: 'Kopyala'\nPaste: 'Yapıştır'\nDelete: 'Sil'\nSelect all: 'Tümünü seç'\nToggle Developer Tools: 'Geliştirici Araçlarını Aç/Kapat'\nActual size: 'Gerçek boyut'\nZoom in: 'Yakınlaştır'\nZoom out: 'Uzaklaştır'\nToggle fullscreen: 'Tam Ekran'\nWindow: 'Pencere'\nMinimize: 'Küçült'\nClose: 'Kapat'\nBack: 'Geri'\nForward: 'İleri'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videolar'\n  Shorts: Kısa Videolar\n  Live: Canlı\n  Posts: Gönderiler\n  Sort By: Sıralama ölçütü\n\n  Counts:\n    Video Count: 1 video | {count} video\n    Channel Count: 1 kanal | {count} kanal\n    Subscriber Count: 1 abone | {count} abone\n    View Count: 1 izlenme | {count} izlenme\n    Watching Count: 1 izliyor | {count} izliyor\n    Like Count: 1 beğenme | {count} beğenme\n    Comment Count: 1 yorum | {count} yorum\nVersion {versionNumber} is now available!  Click for more details: '{versionNumber} sürümü çıktı!  Daha fazla ayrıntı için tıklayın'\nDownload From Site: 'Siteden indir'\nA new blog is now available, {blogTitle}. Click to view more: 'Yeni blog gönderisi var, {blogTitle}. Daha fazlasını görüntülemek için tıklayın'\n\n# Search Bar\nSearch / Go to URL: 'Ara / URL''ye git'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Arama Süzgeçleri'\n  Sort By:\n    Most Relevant: 'En Uygun'\n    Rating: 'Derecelendirme'\n    Upload Date: 'Yükleme Tarihi'\n    View Count: 'İzlenme Sayısı'\n  Time:\n    Time: 'Zaman'\n    Any Time: 'Herhangi Bir Zaman'\n    Last Hour: 'Son Bir Saat'\n    Today: 'Bugün'\n    This Week: 'Bu Hafta'\n    This Month: 'Bu Ay'\n    This Year: 'Bu Yıl'\n  Type:\n    Type: 'Tür'\n    All Types: 'Tüm Türler'\n    Videos: 'Videolar'\n    Channels: 'Kanallar'\n    #& Playlists\n    Movies: Film\n  Duration:\n    Duration: 'Süre'\n    All Durations: 'Tüm Süreler'\n    Short (< 4 minutes): 'Kısa (4 dakikadan az)'\n    Long (> 20 minutes): 'Uzun (20 dakikadan fazla)'\n  # On Search Page\n    Medium (4 - 20 minutes): Orta (4 - 20 dakika)\n  Search Results: 'Arama Sonuçları'\n  Fetching results. Please wait: 'Sonuçlar getiriliyor. Lütfen bekleyin'\n  Fetch more results: 'Daha fazla sonuç getir'\n# Sidebar\n  There are no more results for this search: Bu arama için başka sonuç yok\n  Features:\n    HD: HD\n    Subtitles: Alt Yazılar\n    Live: Canlı\n    4K: 4K\n    HDR: HDR\n    Features: Özellikler\n    Creative Commons: Creative Commons\n    3D: 3B\n    360 Video: 360 Video\n    Location: Konum\n    VR180: VR180\n  Clear Filters: Süzgeci Temizle\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonelikler'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Abonelik listeniz şu anda boş. Aboneliklerinizi içe aktarmak istiyorsanız Veri Ayarları''na gidip Abonelikleri İçe Aktar''ı seçebilir veya bir kanal arayıp abone olabilirsiniz.'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Bu profilin çok sayıda abonesi var.  Hız sınırlamalarından kaçınmak için RSS zorlanıyor\n  Load More Videos: Daha Fazla Video Yükle\n  Error Channels: Hatalı Kanallar\n  Disabled Automatic Fetching: Otomatik abonelik getirmeyi devre dışı bıraktınız. Abonelikleri burada görmek için yenileyin.\n  Empty Channels: Abone olduğunuz kanallarda şu anda herhangi bir video yok.\n  Subscriptions Tabs: Abonelikler Sekmeleri\n  All Subscription Tabs Hidden: Tüm abonelik sekmeleri gizlidir. Buradaki içeriği görmek için lütfen \"{settingsSection}\" içindeki \"{subsection}\" bölümündeki bazı sekmelerin gizliliğini kaldırın.\n  Load More Posts: Daha Fazla Gönderi Yükle\n  Empty Posts: Abone olduğunuz kanallarda şu anda herhangi bir gönderi yok.\nTrending:\n  Trending: 'Öne Çıkanlar'\n  Trending Tabs: Öne Çıkanlar Sekmeleri\n  Gaming: Oyun\n  Sports: Spor\nMost Popular: 'Popüler Olanlar'\nPlaylists: 'Oynatma Listeleri'\nUser Playlists:\n  Your Playlists: 'Oynatma Listelerin'\n  Search bar placeholder: Oynatma Listesi Ara\n  Empty Search Message: Bu oynatma listesinde aramanızla eşleşen video yok\n  This playlist currently has no videos.: Bu oynatma listesinde şu anda hiç video yok.\n  Create New Playlist: Yeni Oynatma Listesi Oluştur\n  Add to Playlist: Oynatma Listesine Ekle\n  Remove from Playlist: Oynatma Listesinden Kaldır\n  Playlist Name: Oynatma Listesi Adı\n  Save Changes: Değişiklikleri Kaydet\n  Delete Playlist: Oynatma Listesini Sil\n  Sort By:\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: Oluşturulma Tarihi (En Yeni)\n    EarliestCreatedFirst: Oluşturulma Tarihi (En Eski)\n    LatestUpdatedFirst: Güncellenme Tarihi (En Yeni)\n    EarliestUpdatedFirst: Güncellenme Tarihi (En Eski)\n    LatestPlayedFirst: Oynatılma Tarihi (En Yeni)\n    EarliestPlayedFirst: Oynatılma Tarihi (En Eski)\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: Bu video yukarı taşınamaz.\n      This video cannot be moved down.: Bu video aşağı taşınamaz.\n      Playlist name cannot be empty. Please input a name.: Oynatma listesi adı boş olamaz. Lütfen bir ad girin.\n      Playlist has been updated.: Oynatma listesi güncellendi.\n      There was an issue with updating this playlist.: Bu oynatma listesi güncellenirken bir sorun oluştu.\n      \"{videoCount} video(s) have been removed\": 1 video kaldırıldı | {videoCount} video kaldırıldı\n      Playlist {playlistName} has been deleted.: '{playlistName} oynatma listesi silindi.'\n      Video has been removed: Video kaldırıldı\n      There was a problem with removing this video: Bu videoyu kaldırırken bir sorun oluştu\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Oynatma listesindeki bazı videolar henüz yüklenmedi. Yine de kopyalamak için buraya tıklayın.\n      This playlist is protected and cannot be removed.: Bu oynatma listesi korumalıdır ve kaldırılamaz.\n      There were no videos to remove.: Kaldırılacak video yok.\n      This playlist does not exist: Bu oynatma listesi yok\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Bu oynatma listesi artık {oldPlaylistName} yerine hızlı yer imi için kullanılıyor. Geri almak için buraya tıklayın\n      Reverted to use {oldPlaylistName} for quick bookmark: Hızlı yer imi için {oldPlaylistName} kullanımına geri dönüldü\n      This playlist is now used for quick bookmark: Bu oynatma listesi artık hızlı yer imi için kullanılıyor\n      This playlist is already being used for quick bookmark.: Bu oynatma listesi zaten hızlı yer imi için kullanılıyor.\n      This playlist has a video with a duration error: Bu oynatma listesi süresi olmayan en az bir video içeriyor, süreleri sıfırmış gibi sıralanacaktır.\n      Video has been removed. Click here to undo.: Video kaldırıldı. Geri almak için buraya tıklayın.\n    Search for Videos: Video Ara\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: Videonuzu eklemek için bir oynatma listesi seçin | {videoCount} videonuzu eklemek için bir oynatma listesi seçin\n    Save: Kaydet\n    Toast:\n      You haven't selected any playlist yet.: Henüz bir oynatma listesi seçmediniz.\n      \"Video(s) added to {playlistCount} playlists\": \"Video(lar) 1 oynatma listesine eklendi | Video(lar) {playlistCount} oynatma listesine eklendi\"\n    N playlists selected: '{playlistCount} Seçildi'\n    Search in Playlists: Oynatma Listelerinde Ara\n    Added {count} Times: 'Zaten Eklendi | {count} Defa Eklendi'\n    Allow Adding Duplicate Video(s): Yinelenen Video(lar) Eklemeye İzin Ver\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Video Zaten Eklendi'\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Video Eklenecek'\n  CreatePlaylistPrompt:\n    New Playlist Name: Yeni Oynatma Listesi Adı\n    Create: Oluştur\n    Toast:\n      There was an issue with creating the playlist.: Oynatma listesi oluşturulurken bir sorun oluştu.\n      There is already a playlist with this name. Please pick a different name.: Bu ada sahip bir oynatma listesi zaten var. Lütfen farklı bir ad seçin.\n      Playlist {playlistName} has been successfully created.: '{playlistName} oynatma listesi başarıyla oluşturuldu.'\n  You have no playlists. Click on the create new playlist button to create a new one.: Hiç oynatma listeniz yok. Yeni bir oynatma listesi oluşturmak için yeni oynatma listesi oluştur düğmesine tıklayın.\n  Are you sure you want to delete this playlist? This cannot be undone: Bu oynatma listesini silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.\n  Move Video Up: Videoyu Yukarı Taşı\n  Move Video Down: Videoyu Aşağı Taşı\n  Playlist Description: Oynatma Listesi Açıklaması\n  Cancel: İptal\n  Edit Playlist Info: Oynatma Listesi Bilgilerini Düzenle\n  Copy Playlist: Oynatma Listesini Kopyala\n  Remove Watched Videos: İzlenen Videoları Kaldır\n  Add to Favorites: '{playlistName} listesine ekle'\n  Remove from Favorites: '{playlistName} listesinden kaldır'\n  Enable Quick Bookmark With This Playlist: Bu Oynatma Listesiyle Hızlı Yer İmini Etkinleştir\n  Playlists with Matching Videos: Eşleşen Videoları İçeren Oynatma Listeleri\n  Quick Bookmark Enabled: Hızlı Yer İmi Etkin\n  Cannot delete the quick bookmark target playlist.: Hızlı yer imi hedef oynatma listesi silinemiyor.\n  Remove Duplicate Videos: Yinelenen Videoları Kaldır\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Bu oynatma listesinden izlenen 1 videoyu kaldırmak istediğinizden emin misiniz? Bu geri alınamaz. | Bu oynatma listesinden izlenen {playlistItemCount} videoyu kaldırmak istediğinizden emin misiniz? Bu geri alınamaz.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Bu oynatma listesinden 1 yinelenen videoyu kaldırmak istediğinizden emin misiniz? Bu geri alınamaz. | Bu oynatma listesinden {playlistItemCount} yinelenen videoyu kaldırmak istediğinizden emin misiniz? Bu geri alınamaz.\n  Export Playlist: Bu Oynatma Listesini Dışa Aktar\n  The playlist has been successfully exported: Oynatma listesi başarılı bir şekilde dışa aktarıldı\n  TotalTimePlaylist: 'Toplam süre: {duration}'\n  Export list of URLs: URL'lerin listesini dışa aktar\nHistory:\n  # On History Page\n  History: 'Geçmiş'\n  Watch History: 'İzleme Geçmişi'\n  Your history list is currently empty.: 'Geçmişin şu anda boş.'\n  Search bar placeholder: Geçmişte Ara\n  Empty Search Message: Geçmişinizde aramanızla eşleşen video yok\n  Case Sensitive Search: Büyük/Küçük Harfe Duyarlı Ara\n  DateOldestHistory: İzlenme Tarihi (En Eski)\n  DateNewestHistory: İzlenme Tarihi (En Yeni)\nSettings:\n  # On Settings Page\n  Settings: 'Ayarlar'\n  General Settings:\n    General Settings: 'Genel'\n    Check for Updates: 'Güncellemeleri Denetle'\n    Check for Latest Blog Posts: 'En Yeni Blog Gönderilerini Denetle'\n    Fallback to Non-Preferred Backend on Failure: 'Hata Durumunda Tercih Edilmeyen Arka Uca Geç'\n    Enable Search Suggestions: 'Arama Önerilerini Etkinleştir'\n    Default Landing Page: 'Öntanımlı Açılış Ekranı'\n    Locale Preference: 'Tercih Edilen Yerel Ayar'\n    Preferred API Backend:\n      Preferred API Backend: 'Tercih Edilen API Arka Ucu'\n      Local API: 'Yerel API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Video Görüntüleme Düzeni'\n      Grid: 'Izgara'\n      List: 'Liste'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Önizleme Görseli Tercihi'\n      Default: 'Öntanımlı'\n      Beginning: 'Başlangıç'\n      Middle: 'Orta'\n      End: 'Bitiş'\n      Hidden: Gizli\n      Blur: Bulanıklık\n    Region for Trending: 'Öne Çıkanlar İçin Bölge Tercihi'\n        #! List countries\n    View all Invidious instance information: Tüm Invidious örnek bilgilerini görüntüle\n    System Default: Sistem Öntanımlı Değeri\n    Clear Default Instance: Öntanımlı Örneği Temizle\n    Set Current Instance as Default: Geçerli Örneği Öntanımlı Olarak Ayarla\n    Current instance will be randomized on startup: Geçerli örnek başlangıçta rastgele olacak\n    No default instance has been set: Öntanımlı örnek ayarlanmadı\n    The currently set default instance is {instance}: Şu anda ayarlanan öntanımlı örnek {instance}\n    Current Invidious Instance: Geçerli Invidious Örneği\n    External Link Handling:\n      No Action: Eylem Yok\n      Ask Before Opening Link: Bağlantıyı Açmadan Önce Sor\n      Open Link: Bağlantıyı Aç\n      External Link Handling: Harici Bağlantı İşleme\n    Auto Load Next Page:\n      Label: Sonraki Sayfayı Otomatik Yükle\n      Tooltip: Sonraki sayfaları ve yorumları otomatik olarak yükle.\n    Open Deep Links In New Window: FreeTube'a Geçen URL'leri Yeni Pencerede Aç\n    Minimize to system tray: Sistem tepsisine küçült\n  Theme Settings:\n    Theme Settings: 'Tema'\n    Match Top Bar with Main Color: 'Üst Barı Ana Renk ile Eşleştir'\n    Base Theme:\n      Base Theme: 'Uygulama Teması'\n      Black: 'Siyah'\n      Dark: 'Koyu'\n      Light: 'Açık'\n      Dracula: 'Drakula'\n      System Default: Sistem Varsayılanı\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: Pastel Pembe\n      Hot Pink: Sıcak Pembe\n      Nordic: Kuzey\n      Solarized Light: Solarized Açık\n      Solarized Dark: Solarized Koyu\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Aydınlık\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Medium: Everforest Koyu Orta\n      Everforest Dark Hard: Everforest Koyu Sert\n      Everforest Dark Low: Everforest Koyu Düşük\n      Everforest Light Hard: Everforest Açık Sert\n      Everforest Light Medium: Everforest Açık Orta\n      Everforest Light Low: Everforest Açık Düşük\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Ana Renk Teması'\n      Red: 'Kırmızı'\n      Pink: 'Pembe'\n      Purple: 'Mor'\n      Deep Purple: 'Koyu Mor'\n      Indigo: 'Çivit Mavisi'\n      Blue: 'Mavi'\n      Light Blue: 'Açık Mavi'\n      Cyan: 'Camgöbeği'\n      Teal: 'Deniz Mavisi'\n      Green: 'Yeşil'\n      Light Green: 'Açık Yeşil'\n      Lime: 'Limon Yeşili'\n      Yellow: 'Sarı'\n      Amber: 'Kehribar Rengi'\n      Orange: 'Turuncu'\n      Deep Orange: 'Koyu Turuncu'\n      Dracula Cyan: 'Drakula Camgöbeği'\n      Dracula Green: 'Drakula Yeşil'\n      Dracula Orange: 'Drakula Turuncu'\n      Dracula Pink: 'Drakula Pembe'\n      Dracula Purple: 'Drakula Mor'\n      Dracula Red: 'Drakula Kırmızı'\n      Dracula Yellow: 'Drakula Sarı'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Gül Suyu\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Mauve: Catppuccin Mocha Eflatun\n      Catppuccin Mocha Red: Catppuccin Mocha Kırmızı\n      Catppuccin Mocha Maroon: Catppuccin Mocha Bordo\n      Catppuccin Mocha Peach: Catppuccin Mocha Şeftali\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sky: Catppuccin Mocha Gökyüzü\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Safir\n      Catppuccin Mocha Blue: Catppuccin Mocha Mavi\n      Catppuccin Mocha Pink: Catppuccin Mocha Pembe\n      Catppuccin Mocha Yellow: Catppuccin Mocha Sarı\n      Catppuccin Mocha Green: Catppuccin Mocha Yeşil\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavanta\n      Solarized Yellow: Güneş Yanığı Sarısı\n      Solarized Orange: Güneş Yanığı Turuncusu\n      Solarized Magenta: Güneş Yanığı Eflatunu\n      Solarized Violet: Güneş Yanığı Menekşesi\n      Solarized Red: Güneş Yanığı Kırmızısı\n      Solarized Blue: Güneş Yanığı Mavisi\n      Solarized Cyan: Güneş Yanığı Camgöbeği\n      Solarized Green: Güneş Yanığı Yeşili\n      Gruvbox Dark Green: Gruvbox Koyu Yeşil\n      Gruvbox Dark Yellow: Gruvbox Koyu Sarı\n      Gruvbox Dark Aqua: Gruvbox Koyu Deniz Mavisi\n      Gruvbox Dark Blue: Gruvbox Koyu Mavi\n      Gruvbox Dark Purple: Gruvbox Koyu Mor\n      Gruvbox Dark Orange: Gruvbox Koyu Turuncu\n      Gruvbox Light Purple: Gruvbox Açık Mor\n      Gruvbox Light Orange: Gruvbox Açık Turuncu\n      Gruvbox Light Red: Gruvbox Parlak Kırmızı\n      Gruvbox Light Blue: Gruvbox Açık Mavi\n      Catppuccin Frappe Pink: Catppuccin Frappe Pembe\n      Catppuccin Frappe Red: Catppuccin Frappe Kırmızı\n      Catppuccin Frappe Maroon: Catppuccin Frappe Bordo\n      Catppuccin Frappe Peach: Catppuccin Frappe Şeftali\n      Catppuccin Frappe Sky: Catppuccin Frappe Gök\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Safir\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavanta\n      Catppuccin Frappe Teal: Catppuccin Frappe Deniz\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Gül Rengi\n      Catppuccin Frappe Yellow: Catppuccin Frappe Sarı\n      Catppuccin Frappe Mauve: Catppuccin Frappe Eflatun\n      Catppuccin Frappe Green: Catppuccin Frappe Yeşil\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Blue: Catppuccin Frappe Mavi\n      Everforest Dark Red: Everforest Koyu Kırmızı\n      Everforest Dark Orange: Everforest Koyu Portakal\n      Everforest Dark Yellow: Everforest Koyu Sarı\n      Everforest Dark Green: Everforest Koyu Yeşil\n      Everforest Dark Aqua: Everforest Koyu Deniz\n      Everforest Dark Blue: Everforest Koyu Mavi\n      Everforest Dark Purple: Everforest Koyu Mor\n      Everforest Light Red: Everforest Açık Kırmızı\n      Everforest Light Orange: Everforest Açık Portakal\n      Everforest Light Yellow: Everforest Açık Sarı\n      Everforest Light Green: Everforest Açık Yeşil\n      Everforest Light Aqua: Everforest Açık Deniz\n      Everforest Light Blue: Everforest Açık Mavi\n      Everforest Light Purple: Everforest Açık Mor\n      Catppuccin Latte Mauve: Catppuccin Latte Eflatun\n      Catppuccin Latte Red: Catppuccin Latte Kırmızı\n    Secondary Color Theme: 'İkincil Renk Teması'\n        #* Main Color Theme\n    UI Scale: Kullanıcı Arayüzü Ölçeği\n    Expand Side Bar by Default: Kenar Çubuğunu Öntanımlı Olarak Genişlet\n    Disable Smooth Scrolling: Düzgün Kaydırmayı Devre Dışı Bırak\n    Hide Side Bar Labels: Kenar Çubuğu Etiketlerini Gizle\n    Hide FreeTube Header Logo: FreeTube Başlık Logosunu Gizle\n  Player Settings:\n    Player Settings: 'Oynatıcı'\n    Play Next Video: 'Önerilen Videoları Otomatik Oynat'\n    Turn on Subtitles by Default: 'Altyazıları Sürekli Etkinleştir'\n    Autoplay Videos: 'Videoları Otomatik Oynat'\n    Proxy Videos Through Invidious: 'Videolari Invidious Üzerinden Aktar'\n    Autoplay Playlists: 'Oynatma Listelerini Otomatik Oynat'\n    Enable Theatre Mode by Default: 'Sinema Modunu Öntanımlı Olarak Etkinleştir'\n    Default Volume: 'Öntanımlı Ses Düzeyi'\n    Default Playback Rate: 'Öntanımlı Oynatma Hızı'\n    Default Video Format:\n      Default Video Format: 'Öntanımlı Video Biçimi'\n      Dash Formats: 'DASH Biçimleri'\n      Legacy Formats: 'Eski Biçimler'\n      Audio Formats: 'Ses Biçimleri'\n    Default Quality:\n      Default Quality: 'Öntanımlı Kalite'\n      Auto: 'Otomatik'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Otomatik Oynatma Geri Sayım Sayacı\n    Scroll Volume Over Video Player: Ses Düzeyini Video Oynatıcı Üzerinden Kaydır\n    Display Play Button In Video Player: Video Oynatıcıda Oynatma Düğmesini Göster\n    Fast-Forward / Rewind Interval: Hızlı İleri / Geri Sarma Aralığı\n    Scroll Playback Rate Over Video Player: Video Oynatıcı Üzerinde Kaydırma Oynatma Oranı\n    Video Playback Rate Interval: Video Oynatma Hızı Aralığı\n    Max Video Playback Rate: En Yüksek Video Oynatma Hızı\n    Screenshot:\n      Quality Label: Ekran Görüntüsü Kalitesi\n      Ask Path: Kaydedileceği Klasörü Sor\n      Folder Label: Ekran Görüntüsü Klasörü\n      File Name Label: Dosya Adı Kalıbı\n      Error:\n        Forbidden Characters: Yasak Karakterler\n        Empty File Name: Boş Dosya Adı\n      Format Label: Ekran Görüntüsü Biçimi\n      Enable: Ekran Görüntüsünü Etkinleştir\n      Folder Button: Klasör Seç\n      File Name Tooltip: Aşağıda değişkenleri kullanabilirsiniz. %Y Yıl 4 basamak. %M Ay 2 basamak. %D Gün 2 basamak. %H Saat 2 basamak. %N Dakika 2 basamak. %S Saniye 2 basamak. %T Milisaniye 3 basamak. %s Video Saniyesi. %t Video Milisaniyesi 3 basamak. %i Video Kimliği.\n    Enter Fullscreen on Display Rotate: Ekran Döndürüldüğünde Tam Ekrana Geç\n    Skip by Scrolling Over Video Player: Video Oynatıcı Üzerinde Kaydırarak Atla\n    Autoplay Interruption Timer: Otomatik Oynatma Durdurma Sayacı\n    Default Viewing Mode:\n      Picture in Picture: Resim içinde Resim\n      Full Screen: Tam Ekran\n      Default Viewing Mode: Varsayılan Görüntüleme Modu\n      Theater: Sinema\n      External Player: Harici Oynatıcı ({externalPlayerName})\n  Privacy Settings:\n    Privacy Settings: 'Gizlilik'\n    Remember History: 'İzleme Geçmişini Hatırla'\n    Save Watched Progress: 'Kaldığım Yeri Hatırla'\n    Clear Search Cache: 'Arama Önbelleğini Temizle'\n    Are you sure you want to clear out your search cache?: 'Arama önbelleğini temizlemek istediğinizden emin misiniz?'\n    Search cache has been cleared: 'Arama önbelleği temizlendi'\n    Remove Watch History: 'İzleme Geçmişini Temizle'\n    Are you sure you want to remove your entire watch history?: 'Tüm izleme geçmişini silmek istediğinizden emin misiniz?'\n    Watch history has been cleared: 'İzleme geçmişi temizlendi'\n    Remove All Subscriptions / Profiles: 'Tüm Abonelikler/Profilleri Temizle'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Tüm abonelikler/profilleri temizlemek istediğinizden emin misiniz?  Geri alınamaz.'\n    Save Watched Videos With Last Viewed Playlist: İzlenen Videoları Son Görüntülenen Oynatma Listesiyle Kaydet\n    All playlists have been removed: Tüm oynatma listeleri kaldırıldı\n    Remove All Playlists: Tüm Oynatma Listelerini Kaldır\n    Are you sure you want to remove all your playlists?: Tüm oynatma listelerinizi kaldırmak istediğinizden emin misiniz?\n    Remember Search History: Arama Geçmişini Hatırla\n    Are you sure you want to clear out your search history and cache?: Arama geçmişinizi ve önbelleğinizi temizlemek istediğinizden emin misiniz?\n    Search history and cache have been cleared: Arama geçmişi ve önbellek temizlendi\n    Clear Search History and Cache: Arama Geçmişini ve Önbelleği Temizle\n    Watched Progress Saving Mode:\n      Modes:\n        Never: Asla\n        Auto: Otomatik\n        Semi-auto: Yarı otomatik\n      Tooltip: Otomatik = Video sona erdiğinde ve hatayla karşılaşıldığında (ör. hız sınırlı ve izleme oturumu sona erdiğinde) her video sayfası çıkışında kaydet. Yarı otomatik = Video sayfasından çıkış haricinde Otomatik gibi ve video oynatıcının altında bulunan İzlenen İlerlemeyi Kaydet adı verilen bir düğme aracılığıyla ilerlemeyi manuel olarak kaydedebilir.\n  Subscription Settings:\n    Subscription Settings: 'Abonelik'\n    Fetch Feeds from RSS: 'Akışları RSS''den Getir'\n    Fetch Automatically: Akışı Otomatik Olarak Getir\n    Confirm Before Unsubscribing: Abonelikten Çıkmadan Önce Onayla\n    'Limit the number of videos displayed for each channel': Her kanal için gösterilen video sayısını sınırlayın\n    To: To\n  Data Settings:\n    Data Settings: 'Veri'\n    Select Export Type: 'Dışa Aktarma Türünü Seç'\n    Import Subscriptions: 'Abonelikleri İçe Aktar'\n    Export Subscriptions: 'Abonelikleri Dışa Aktar'\n    Export FreeTube: 'Freetube Biçiminde Dışa Aktar'\n    Export YouTube: 'YouTube Biçiminde Dışa Aktar'\n    Export NewPipe: 'NewPipe Biçiminde Dışa Aktar'\n    Import History: 'Geçmişi İçe Aktar'\n    Export History: 'Geçmişi Dışa Aktar'\n    Profile object has insufficient data, skipping item: 'Profil nesnesinde yetersiz veri var, öğe atlanıyor'\n    All subscriptions and profiles have been successfully imported: 'Tüm abonelikler ve profiller başarılı bir şekilde içe aktarıldı'\n    All subscriptions have been successfully imported: 'Tüm abonelikler başarılı bir şekilde içe aktarıldı'\n    Invalid subscriptions file: 'Geçersiz aboneler dosyası'\n    Invalid history file: 'Geçersiz geçmiş dosyası'\n    Subscriptions have been successfully exported: 'Tüm abonelikler başarılı bir şekilde dışa aktarıldı'\n    History object has insufficient data, skipping item: 'Geçmiş nesnesinde yetersiz veri var, öğe atlanıyor'\n    All watched history has been successfully imported: 'Tüm izleme geçmişi başarılı bir şekilde içe aktarıldı'\n    All watched history has been successfully exported: 'Tüm izleme geçmişi başarılı bir şekilde dışa aktarıldı'\n    Unable to read file: 'Dosya okunamadı'\n    Unable to write file: 'Dosya yazılamadı'\n    Unknown data key: 'Bilinmeyen veri anahtarı'\n    How do I import my subscriptions?: 'Aboneliklerimi nasıl içe artarırım?'\n    Manage Subscriptions: Abonelikleri Yönet\n    Export Playlists: Oynatma Listelerini Dışa Aktar\n    All playlists has been successfully imported: Tüm oynatma listeleri başarıyla içe aktarıldı\n    Playlist insufficient data: '\"{playlist}\" oynatma listesi için yetersiz veri, öge atlanıyor'\n    Import Playlists: Oynatma Listelerini İçe Aktar\n    All playlists has been successfully exported: Tüm oynatma listeleri başarıyla dışa aktarıldı\n    Playlist File: Oynatma Listesi Dosyası\n    Subscription File: Abonelik Dosyası\n    History File: Geçmiş Dosyası\n    Export Playlists For Older FreeTube Versions:\n      Label: Eski FreeTube Sürümleri İçin Oynatma Listelerini Dışa Aktar\n      Tooltip: \"Bu seçenek, tüm oynatma listelerindeki videoları 'Favoriler' adlı tek bir oynatma listesine aktarır.\\nFreeTube'un eski bir sürümü için oynatma listelerindeki videolar nasıl dışa ve içe aktarılır:\\n1. Oynatma listelerinizi bu seçenek etkinken dışa aktarın.\\n2. Gizlilik Ayarları altındaki Tüm Oynatma Listelerini Kaldır seçeneğini kullanarak var olan tüm oynatma listelerinizi silin.\\n3. FreeTube'un eski sürümünü başlatın ve dışa aktarılan oynatma listelerini içe aktarın.\\\"\"\n\n    Search history file: Arama geçmişi dosyası\n    Search history: Arama geçmişi\n    Import search history: Arama geçmişini içe aktar\n    Export search history: Arama geçmişini dışa aktar\n    All search history has been successfully imported: Tüm arama geçmişi başarıyla içe aktarıldı\n    All search history has been successfully exported: Tüm arama geçmişi başarıyla dışa aktarıldı\n  Distraction Free Settings:\n    Hide Live Chat: Canlı Sohbeti Gizle\n    Hide Popular Videos: Popüler Videoları Gizle\n    Hide Trending Videos: Öne Çıkan Videoları Gizle\n    Hide Recommended Videos: Tavsiye Edilen Videoları Gizle\n    Hide Comment Likes: Yorum Beğenmelerini Gizle\n    Hide Channel Subscribers: Kanal Abonelerini Gizle\n    Hide Video Likes And Dislikes: Video Beğenmeleri Ve Beğenmemelerini Gizle\n    Hide Video Views: Video İzlenme Sayılarını Gizle\n    Distraction Free Settings: Dikkat Dağıtmama\n    Hide Active Subscriptions: Etkin Abonelikleri Gizle\n    Hide Playlists: Oynatma Listelerini Gizle\n    Hide Live Streams: Canlı Yayınları Gizle\n    Hide Sharing Actions: Paylaşım Eylemlerini Gizle\n    Hide Videos on Watch: 'İzlenmiş Videoları Gizle'\n    Hide Video Description: Video Açıklamasını Gizle\n    Hide Comments: Yorumları Gizle\n    Hide Chapters: Bölümleri Gizle\n    Hide Upcoming Premieres: Yaklaşan İlk Gösterimleri Gizle\n    Hide Channels Placeholder: Kanal Kimliği\n    Hide Channels: Kanallardan Videoları Gizle\n    Display Titles Without Excessive Capitalisation: Başlıkları Aşırı Büyük Harf ve Noktalama İşaretleri Kullanmadan Görüntüle\n    Hide Featured Channels: Öne Çıkan Kanalları Gizle\n    Hide Channel Playlists: Kanal \"Oynatma Listelerini\" Sekmesini Gizle\n    Hide Channel Shorts: Kanal \"Kısa Videolar\" Sekmesini Gizle\n    Sections:\n      Side Bar: Kenar Çubuğu\n      Channel Page: Kanal Sayfası\n      Watch Page: İzleme Sayfası\n      General: Genel\n      Subscriptions Page: Abonelikler Sayfası\n    Hide Channel Releases: Kanal \"Yayınlar\" Sekmesini Gizle\n    Hide Channel Podcasts: Kanal \"Podcastler\" Sekmesini Gizle\n    Hide Subscriptions Videos: Abonelik Videolarını Gizle\n    Hide Subscriptions Shorts: Abonelik Kısa Videolarını Gizle\n    Hide Subscriptions Live: Abonelik Canlı Yayınlarını Gizle\n    Hide Profile Pictures in Comments: Yorumlardaki Profil Resimlerini Gizle\n    Hide Channels Invalid: Belirtilen kanal kimliği geçersiz\n    Hide Channels Disabled Message: Bazı kanallar kimliği kullanılarak engellendi ve işlenmedi. Bu kimlikler güncellenirken özellik engellenir\n    Hide Channels Already Exists: Kanal kimliği zaten var\n    Hide Channels API Error: Belirtilen kimliğe sahip kullanıcı alınırken hata oluştu. Lütfen kimliğin doğru olup olmadığını tekrar gözden geçirin.\n    Hide Videos, Playlists and Channels Containing Text: Metin İçeren Videoları ve Oynatma Listelerini Gizle\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Sözcük, Sözcük Parçası veya İfade\n    Hide Channel Home: Kanal \"Ana Sayfa\" Sekmesini Gizle\n    Show Added Items: Eklenen Öğeleri Göster\n    Hide Channel Courses: Kanal \"Kurslar\" Sekmesini Gizle\n    Hide Channel Posts: Kanalın \"Gönderiler\" sekmesini gizle\n    Hide Subscriptions Posts: Abonelik gönderilerini gizle\n  The app needs to restart for changes to take effect. Restart and apply change?: Değişikliklerin etkili olması için uygulamanın yeniden başlatılması gerekiyor. Yeniden başlatılsın ve değişiklikler uygulansın mı?\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Ağ bilgileri alınırken hata oluştu. Vekil sunucunuz doğru yapılandırıldı mı?\n    City: Şehir\n    Region: Bölge\n    Country: Ülke\n    Ip: IP\n    Your Info: Bilgileriniz\n    Test Proxy: Vekil Sunucuyu Test Et\n    Clicking on Test Proxy will send a request to: Vekil Sunucuyu Test Et düğmesine tıklamak, şu adrese bir istek gönderecek\n    Proxy Port Number: Vekil Sunucu Bağlantı Noktası Numarası\n    Proxy Host: Vekil Sunucu Ana Makinesi\n    Proxy Protocol: Vekil Sunucu Protokolü\n    Enable Tor / Proxy: Tor / Vekil Sunucu Etkinleştir\n    Proxy Settings: Vekil Sunucu\n    Proxy Warning: FreeTube yerleşik bir vekil sunucusu sağlamaz fakat cihazınızda çalışan Tor veya bazı VPN'ler tarafından sağlanan harici vekil sunucu SOCKS5 gibi harici bir vekil sunucuya bağlanabilir. İzin verildiği takdirde, vekil sunucu/Tor ağının düzgün ayarlandığından emin olun, aksi takdirde FreeTube herhangi bir veri sağlayamayacaktır.\n    Proxy Username: Vekil Kullanıcı Adı\n    Proxy Password: Vekil Parolası\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Sponsor bölümü atlandığında bildir\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API bağlantısı (Varsayılan https://sponsor.ajay.app)\n    Enable SponsorBlock: SponsorBlock'u Etkinleştir\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Atlama Seçeneği\n      Auto Skip: Otomatik Atla\n      Show In Seek Bar: Arama Çubuğunda Göster\n      Prompt To Skip: Atlamak İçin Sor\n      Do Nothing: Hiçbir Şey Yapma\n    Category Color: Kategori Rengi\n    UseDeArrowTitles: DeArrow Video Başlıklarını Kullan\n    UseDeArrowThumbnails: Önizleme görselleri için DeArrow kullan\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow Önizleme Görseli Oluşturucu API URL'si (Öntanımlı https://dearrow-thumb.ajay.app)\n  External Player Settings:\n    Custom External Player Arguments: Özel Harici Oynatıcı Argümanları\n    Custom External Player Executable: Özel Harici Oynatıcı Çalıştırılabilir Dosyası\n    Ignore Unsupported Action Warnings: Desteklenmeyen Eylem Uyarılarını Yok Say\n    External Player: Harici Oynatıcı\n    External Player Settings: Harici Oynatıcı\n    Players:\n      None:\n        Name: Yok\n    Ignore Default Arguments: Öntanımlı Argümanları Yoksay\n  Parental Control Settings:\n    Parental Control Settings: Ebeveyn Denetimi\n    Show Family Friendly Only: Yalnızca Aileye Uygun Olanları Göster\n    Hide Unsubscribe Button: Abonelikten Çık Düğmesini Gizle\n    Hide Search Bar: Arama Çubuğunu Gizle\n    Hide Uploader on Watch page: İzleme sayfasında yükleyiciyi gizle\n  Experimental Settings:\n    Replace HTTP Cache: HTTP Önbelleğini Değiştir\n    Warning: Bu ayarlar deneyseldir, etkin durumdayken çökmelere neden olabilirler. Yedekleme yapılması şiddetle tavsiye edilir. Kullanmanız durumunda risk size aittir!\n    Experimental Settings: Deneysel\n  Password Dialog:\n    Password: Parola\n    Enter Password To Unlock: Ayarların kilidini açmak için parolayı girin\n  Password Settings:\n    Password Settings: Parola\n    Set Password To Prevent Access: Ayarlara erişimi engellemek için bir parola belirleyin\n    Remove Password: Parolayı Kaldır\n    Set Password: Parola Ayarla\n  Sort Settings Sections (A-Z): Ayarlar Bölümlerini Sırala (A-Z)\n  Return to Settings Menu: Ayarlar Menüsüne Dön\n  SABR:\n    Label: DASH arka ucu olarak SABR etkinleştir\n    Tooltip: SABR, gelecek sürümlerde tek DASH arka ucu olacak ve devre dışı bırakılamayacaktır. Bu seçenek, erken uygulamada kurtarılamaz sorunlar olması ihtimaline karşı sunulmaktadır.\nAbout:\n  #On About page\n  About: 'Hakkında'\n  #& About\n  Website: Web sitesi\n  Blog: Blog\n  Credits: Katkıda Bulunanlar\n  FAQ: SSS\n  Email: E-posta\n  Beta: Beta\n  Donate: Bağış Yap\n  Help: Yardım\n  these people and projects: bu kişiler ve projeler\n  Translate: Çevir\n  room rules: oda kuralları\n  Chat on Matrix: Matrix'te sohbet et\n  Mastodon: Mastodon\n  Please check for duplicates before posting: Lütfen bildirmeden önce bildirilmiş olup olmadığına bakın\n  GitHub issues: GitHub sorunları\n  Report a problem: Sorun bildir\n  FreeTube Wiki: FreeTube Wiki\n  GitHub releases: GitHub Sürümleri\n  Downloads / Changelog: İndirmeler / Değişiklikler\n  Source code: Kaynak kodları\n  Discussions: Tartışmalar\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: '{licenseLink} altında lisanslanmıştır'\n  Please read the {roomRulesLink}: 'Lütfen okuyun: {roomRulesLink}'\n  FreeTube is made possible by {creditsPageLink}: 'FreeTube için emeği geçenler: {creditsPageLink}'\nProfile:\n  Profile Select: 'Profil Seçimi'\n  All Channels: 'Tüm Kanallar'\n  Profile Manager: 'Profil Yöneticisi'\n  Create New Profile: 'Yeni Profil Oluştur'\n  Edit Profile: 'Profili Düzenle'\n  Color Picker: 'Renk Seçimi'\n  Custom Color: 'Özel Renk'\n  Profile Preview: 'Profil Önizleme'\n  Create Profile: 'Profil Oluştur'\n  Update Profile: 'Profili Güncelle'\n  Make Default Profile: 'Öntanımlı Profil Yap'\n  Delete Profile: 'Profili Sil'\n  Are you sure you want to delete this profile?: 'Bu profili silmek istediğinizden emin misiniz?'\n  All subscriptions will also be deleted.: 'Tüm abonelikler de silinecek.'\n  Your profile name cannot be empty: 'Profil adı boş bırakılamaz'\n  Profile has been created: 'Profil oluşturuldu'\n  Profile has been updated: 'Profil güncellendi'\n  Your default profile has been set to {profile}: 'Öntanımlı profiliniz {profile} olarak ayarlandı'\n  Removed {profile} from your profiles: '{profile} Profillerinizden kaldırıldı'\n  Your default profile has been changed to your primary profile: 'Öntanımlı profiliniz birincil profiliniz olarak değiştirildi'\n  '{profile} is now the active profile': '{profile} artık etkin profil'\n  Subscription List: 'Abonelik Listesi'\n  Other Channels: 'Diğer Kanallar'\n  '{number} selected': '{number} seçildi'\n  Select All: 'Tümünü Seç'\n  Select None: 'Hiçbirini Seçme'\n  Delete Selected: 'Seçilenleri Sil'\n  Add Selected To Profile: 'Seçilenleri Profile Ekle'\n  No channel(s) have been selected: 'Hiçbir kanal seçilmedi'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Bu birincil profilinizdir. Seçili kanalları silmek istediğinizden emin misiniz? Aynı kanallar bulundukları tüm profillerden silinecek.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Seçili kanalları silmek istediğinizden emin misiniz?  Bu, kanalı başka bir profilden silmez.'\n#On Channel Page\n  Profile Filter: Profil Süzgeci\n  Profile Settings: Profil\n  Toggle Profile List: Profil Listesini Aç/Kapat\n  Profile Name: Profil Adı\n  Edit Profile Name: Profil Adını Düzenle\n  Create Profile Name: Profil Adı Oluştur\n  Open Profile Dropdown: Profil Açılır Menüsünü Aç\n  Close Profile Dropdown: Profil Açılır Menüsünü Kapat\nChannel:\n  Subscribe: 'Abone ol'\n  Unsubscribe: 'Abonelikten çık'\n  Channel has been removed from your subscriptions: 'Kanal aboneliklerinizden kaldırıldı'\n  Removed subscription from {count} other channel(s): 'Diğer {count} kanallarından abonelik kaldırıldı'\n  Added channel to your subscriptions: 'Kanal aboneliklerinize eklendi'\n  Search Channel: 'Kanalda ara'\n  Your search results have returned 0 results: 'Arama sonuçlarınız 0 sonuç verdi'\n  Videos:\n    Videos: 'Videolar'\n    This channel does not currently have any videos: 'Bu kanalda şu anda herhangi bir video yok'\n    Sort Types:\n      Newest: 'En yeni'\n      Oldest: 'En eski'\n      Most Popular: 'En Popüler'\n  Playlists:\n    Playlists: 'Oynatma Listeleri'\n    This channel does not currently have any playlists: 'Bu kanalda şu anda herhangi bir oynatma listesi yok'\n    Sort Types:\n      Last Video Added: 'Son Eklenen Video'\n      Newest: 'En yeni'\n      Oldest: 'En eski'\n  About:\n    About: 'Hakkında'\n    Channel Description: 'Kanal Açıklaması'\n    Featured Channels: 'Öne Çıkan Kanallar'\n    Tags:\n      Tags: Etiketler\n      Search for: '“{tag}” için ara'\n    Details: Ayrıntılar\n    Joined: Katıldı\n    Location: Konum\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Bu kanal yaş sınırlamasına tabidir ve şu anda FreeTube'da görüntülenememektedir.\n  Channel Tabs: Kanal Sekmeleri\n  This channel does not allow searching: Bu kanal aramaya izin vermiyor\n  This channel does not exist: Bu kanal mevcut değil\n  Posts:\n    This channel currently does not have any posts: Bu kanalda şu anda herhangi bir gönderi yok\n    votes: '{votes} oy'\n    Reveal Answers: Yanıtları Göster\n    Hide Answers: Yanıtları Gizle\n    Video hidden by FreeTube: FreeTube tarafından gizlenen video\n    View Full Post: Gönderinin Tamamını Görüntüle\n    Viewing Posts Only Supported By Invidious: Gönderileri görüntüleme yalnızca Invidious tarafından desteklenir. Invidious olmadan içeriği görüntülemek için bir kanalın topluluk sekmesine gidin.\n  Live:\n    Live: Canlı\n    This channel does not currently have any live streams: Bu kanalda şu anda herhangi bir canlı yayın yok\n  Shorts:\n    This channel does not currently have any shorts: Bu kanalda şu anda hiç kısa video yok\n  Podcasts:\n    Podcasts: Podcast'ler\n    This channel does not currently have any podcasts: Bu kanalda şu anda herhangi bir podcast yok\n  Releases:\n    This channel does not currently have any releases: Bu kanalda şu anda herhangi bir yayın yok\n    Releases: Yayınlar\n  Home:\n    Home: Ana Sayfa\n    View Playlist: Oynatma Listesini Gözat\n  Courses:\n    Courses: Kurslar\n    This channel does not currently have any courses: Bu kanalda şu anda herhangi bir kurs bulunmamaktadır\nVideo:\n  Mark As Watched: 'İzlendi Olarak İşaretle'\n  Remove From History: 'Geçmişten Kaldır'\n  Video has been marked as watched: 'Video izlendi olarak işaretlendi'\n  Video has been removed from your history: 'Video geçmişinizden kaldırıldı'\n  Open in YouTube: 'YouTube''da aç'\n  Copy YouTube Link: 'YouTube Bağlantısını Kopyala'\n  Open YouTube Embedded Player: 'Youtube Bütünleşik Oynatıcıda Aç'\n  Copy YouTube Embedded Player Link: 'Youtube Bütünleşik Oynatıcı Bağlantısını Kopyala'\n  Open in Invidious: 'Invidious''da aç'\n  Copy Invidious Link: 'Invidious Bağlantısını Kopyala'\n  Views: 'İzlenme'\n  Loop Playlist: 'Listeyi Döngüye Al'\n  Shuffle Playlist: 'Oynatma Listesini Karıştır'\n  Reverse Playlist: 'Oynatma Listesini Geriden Oynat'\n  Previous: 'Önceki'\n  Next: 'Sonraki'\n  Watched: 'İzlendi'\n  Autoplay: 'Otomatik Oynat'\n  Starting soon, please refresh the page to check again: 'Yakında başlayacak, lütfen tekrar denetlemek için sayfayı yenileyin'\n  # As in a Live Video\n  Live: 'Canlı'\n  Live Now: 'Şimdi Canlı'\n  Live Chat: 'Canlı Sohbet'\n  Enable Live Chat: 'Canlı Sohbeti Etkinleştir'\n  Live Chat is currently not supported in this build.: 'Canlı Sohbet bu sürümde desteklenmiyor.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Canlı Sohbet etkinleştirildi. Sohbet mesajları gönderildikten sonra burada görünecektir.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Canlı Sohbet şu anda Invidious API ile desteklenmemektedir. YouTube ile doğrudan bağlantı gerekli.'\n  Published:\n    In less than a minute: Bir dakikadan kısa sürede\n  Published on: 'Yayımlanma tarihi'\n#& Videos\n  Copy Invidious Channel Link: Invidious Kanalı Bağlantısını Kopyala\n  Open Channel in Invidious: İnvidious'da Kanal Aç\n  Copy YouTube Channel Link: Youtube Kanalı Bağlantısını Kopyala\n  Open Channel in YouTube: Youtube'da Kanal Açın\n  Started streaming on: Yayına başlama tarihi\n  Streamed on: Yayınlanma tarihi\n  Video has been removed from your saved list: Video, kaydedilen listenizden kaldırıldı\n  Video has been saved: Video kaydedildi\n  Save Video: Videoyu Kaydet\n  Sponsor Block category:\n    music offtopic: Müzik Konu Dışı\n    interaction: Etkileşim\n    self-promotion: Kendini Tanıtma\n    outro: Çıkış\n    intro: Giriş\n    sponsor: Sponsor\n    recap: Özet\n    filler: Dolgu\n  External Player:\n    Unsupported Actions:\n      looping playlists: döngüsel oynatma listeleri\n      shuffling playlists: oynatma listelerini karıştırma\n      reversing playlists: oynatma listelerini ters çevir\n      opening specific video in a playlist (falling back to opening the video): oynatma listesinde belirli bir videoyu açma (yedek olarak videoyu açma)\n      opening playlists: oynatma listelerini aç\n      setting a playback rate: oynatma hızını ayarla\n      starting video at offset: belirli bir konumda video başlatma\n    UnsupportedActionTemplate: '{externalPlayer} desteklemiyor: {action}'\n    OpeningTemplate: '{videoOrPlaylist}, {externalPlayer} içinde açılıyor...'\n    playlist: oynatma listesi\n    video: video\n    OpenInTemplate: '{externalPlayer} içinde aç'\n  Premieres: İlk gösterim\n  Scroll to Bottom: Aşağıya Kaydır\n  Show Super Chat Comment: Süper Sohbet Yorumunu Göster\n  Upcoming: Yakında\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Canlı sohbet bu yayın için kullanılamıyor. Yükleyen tarafından devre dışı bırakılmış olabilir.\n  Unhide Channel: Kanalı Göster\n  Hide Channel: Kanalı Gizle\n  More Options: Daha Fazla Seçenek\n  Player:\n    TranslatedCaptionTemplate: '{language} (\"{originalLanguage}\" dilinden çevrildi)'\n    Audio Tracks: Ses Parçaları\n    Stats:\n      Media Formats: 'Medya Biçimleri: {formats}'\n      Bitrate: 'Bit Hızı: {bitrate} kbps'\n      CodecsVideoAudioNoItags: 'Kod Çözücüler: {videoCodec} / {audioCodec}'\n      Stats: İstatistikler\n      Video ID: 'Video Kimliği: {videoId}'\n      Resolution: 'Çözünürlük: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Oynatıcı Boyutları: {width}x{height}'\n      Volume: 'Ses Düzeyi: {volumePercentage}%'\n      Bandwidth: 'Bant Genişliği: {bandwidth} kbps'\n      Buffered: 'Ara Belleğe Alınan: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Kaybedilen Çerçeve: {droppedFrames} / Toplam Çerçeve: {totalFrames}'\n      CodecAudio: 'Kod Çözücü: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'Kod Çözücüler: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n    Theatre Mode: Tiyatro Modu\n    Exit Theatre Mode: Tiyatro Modundan Çık\n    Full Window: Tam Pencere\n    Exit Full Window: Tam Pencereden Çık\n    Take Screenshot: Ekran Görüntüsü Al\n    Show Stats: İstatistikleri Göster\n    Hide Stats: İstatistikleri Gizle\n    You appear to be offline: Çevrim dışı görünüyorsunuz.\n    Playback will resume automatically when your connection comes back: Bağlantınız geri geldiğinde oynatma otomatik olarak devam edecektir.\n    Skipped segment: '{segmentCategory} bölümü atlandı'\n    Autoplay is off: Otomatik Oynat Kapalı\n    Autoplay is on: Otomatik Oynat Açık\n  IP block: YouTube, IP adresinizin video izlemesini engelledi. Lütfen farklı bir VPN veya vekil sunucuya geçmeyi deneyin.\n  Unlisted: Listelenmemiş\n  AgeRestricted: Yaş sınırlamalı videolar, Google hesabına giriş ve yaş doğrulaması yapılmış bir YouTube hesabının kullanımını gerektirdiği için FreeTube üzerinden izlenemez.\n  MembersOnly: Sadece üyelere özel videolar, Google hesabına giriş ve yükleyicinin kanalına ücretli abonelik gerektirdiği için FreeTube üzerinden izlenemez.\n  DeArrow:\n    Show Original Details: Düzenlenmemiş Detayları Göster\n    Show Modified Details: Düzenlenmiş Detayları Göster\n#& Playlists\n  DRMProtected: DRM korumalı videolar, özel kapalı kaynak bileşenleri gerektirdiğinden FreeTube ile oynatılamaz. Bu videoyu izlemek istiyorsanız lütfen resmi YouTube web sitesinde DRM etkinleştirilmiş bir web tarayıcısında izleyin.\n  Watched Progress Saved: İzlenen İlerleme Kaydedildi\n  Save Watched Progress: İzlenen İlerlemeyi Kaydet\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Kalan ön reklam süresi: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Kalan SABR bekleme süresi: {remindingTimeSeconds}s'\n  Popout Live Chat: Açılır Sohbet\nPlaylist:\n  #& About\n  View Full Playlist: 'Tüm oynatma listesini görüntüle'\n  Last Updated On: 'Son güncelleme tarihi'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Oynatma Listesi\n  Sort By:\n    DateAddedNewest: Eklenme Tarihi (En Yeni)\n    AuthorAscending: Yazar (A-Z)\n    AuthorDescending: Yazar (Z-A)\n    VideoTitleAscending: Başlık (A-Z)\n    VideoTitleDescending: Başlık (Z-A)\n    DateAddedOldest: Eklenme Tarihi (En Eski)\n    Custom: Özel\n    VideoDurationAscending: Süre (En Kısa)\n    VideoDurationDescending: Süre (En Uzun)\n    PublishedOldest: Yayınlanma Tarihi (En Eski)\n    PublishedNewest: Yayınlanma Tarihi (En Yeni)\nChange Format:\n  Change Media Formats: 'Medya Biçimlerini Değiştir'\n  Use Dash Formats: 'DASH Biçimlerini Kullan'\n  Use Legacy Formats: 'Eski Biçimleri Kullan'\n  Use Audio Formats: 'Ses Biçimlerini Kullan'\n  Dash formats are not available for this video: 'DASH biçimleri bu video için kullanılabilir değil'\n  Audio formats are not available for this video: 'Ses biçimleri bu video için kullanılabilir değil'\n  Legacy formats are not available for this video: Eski biçimler bu video için kullanılabilir değil\nShare:\n  Share Video: 'Videoyu Paylaş'\n  Share Playlist: 'Oynatma Listesini Paylaş'\n  Include Timestamp: 'Zaman Damgasını Dahil Et'\n  Copy Link: 'Bağlantıyı Kopyala'\n  Open Link: 'Bağlantıyı Aç'\n  Copy Embed: 'Bütünleşik Oynatıcı Kopyala'\n  Open Embed: 'Bütünleşik Oynatıcı Aç'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious bağlantısı panoya kopyalandı'\n  Invidious Embed URL copied to clipboard: 'Invidious bütünleşik oynatıcı bağlantısı panoya kopyalandı'\n  YouTube URL copied to clipboard: 'YouTube bağlantısı panoya kopyalandı'\n  YouTube Embed URL copied to clipboard: 'YouTube bütünleşik oynatıcı bağlantısı panoya kopyalandı'\n  YouTube Channel URL copied to clipboard: Youtube Kanalı Adresi panoya kopyalandı\n  Invidious Channel URL copied to clipboard: Invidious Kanalı Adresi panoya kopyalandı\n  Share Channel: Kanalı Paylaş\n  Share Post: Gönderiyi Paylaş\nMini Player: 'Mini Oynatıcı'\nComments:\n  Comments: 'Yorumlar'\n  Click to View Comments: 'Yorumları Görüntülemek İçin Tıklayın'\n  Getting comment replies, please wait: 'Yorum yanıtları yükleniyor, lütfen bekleyin'\n  There are no more comments for this video: 'Bu video için daha fazla yorum yok'\n  Hide Comments: 'Yorumları Gizle'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Bu videoya hiç yorum yapılmamış'\n  Load More Comments: 'Daha Fazla Yorum Yükle'\n  Newest first: En yeni ilk önce\n  Top comments: En iyi yorumlar\n  Show More Replies: Daha Fazla Yanıt Göster\n  Pinned by: Sabitleyen\n  Member: Üye\n  View {replyCount} replies: '1 yanıtı görüntüle | {replyCount} yanıtı görüntüle'\n  Hearted: Kalplendi\n  Subscribed: Abone olundu\n  There are no comments available for this post: Bu gönderi için hiç yorum yok\n  Hide {replyCount} replies: 1 yanıtı gizle | {replyCount} yanıtı gizle\n  View 1 reply from {channelName}: '{channelName} kanalından 1 yanıtı görüntüle'\n  View {replyCount} replies from {channelName} and others: '{channelName} kanalından ve diğerlerinden {replyCount} yanıtı görüntüle'\nUp Next: 'Sonraki'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Yerel API Hatası (Kopyalamak için tıklayın)'\nInvidious API Error (Click to copy): 'Invidious API Hatası (Kopyalamak için tıklayın)'\nFalling back to Invidious API: 'Invidious API''ye geri dönülüyor'\nFalling back to Local API: 'Yerel API''ye geri dönülüyor'\nLoop is now disabled: 'Döngü artık devre dışı'\nLoop is now enabled: 'Döngü artık etkin'\nShuffle is now disabled: 'Karıştır artık devre dışı'\nShuffle is now enabled: 'Karıştır artık etkin'\nThe playlist has been reversed: 'Oynatma listesi tersine çevrildi'\nPlaying Next Video: 'Sonraki Video Oynatılıyor'\nPlaying Previous Video: 'Önceki Video Oynatılıyor'\nCanceled next video autoplay: 'Sonraki video otomatik oynatımı iptal edildi'\n'The playlist has ended. Enable loop to continue playing': 'Oynatma listesi sona erdi.  Devam etmek için döngüyü etkinleştir'\n\nYes: 'Evet'\nNo: 'Hayır'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Eksik biçimler nedeniyle bu video kullanılamıyor. Bu durum, ülke kullanılamazlığı nedeniyle gerçekleşebilir.\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: Etkinleştirildiğinde, FreeTube abonelik akışınızı almak için varsayılan yöntemi yerine RSS kullanacaktır. RSS daha hızlıdır ve IP engellemesini önler, ancak video süresi, canlı durum veya gönderiler gibi belirli bilgileri sağlamaz\n    Fetch Automatically: Etkinleştirildiğinde, FreeTube başlangıçta ve yeni bir pencere açıldığında abonelik beslemenizi otomatik olarak getirecektir.\n  Player Settings:\n    Default Video Format: Bir video oynatılırken kullanılan biçimleri ayarlayın. DASH biçimleri daha yüksek kalitelerde oynatabilir. Eski biçimler en fazla 360p ile sınırlıdır ancak daha az bant genişliği kullanır. Ses biçimleri yalnızca ses akışlarıdır.\n    Proxy Videos Through Invidious: Videoları sunmak için YouTube ile doğrudan bağlantı kurmak yerine Invidious'a bağlanılacak.\n    Scroll Playback Rate Over Video Player: Oynatma hızını denetlemek için, imleç videonun üzerindeyken Ctrl tuşunu (Mac'te Komut tuşu) basılı tutun ve oynatma hızını denetlemek için fare tekerleğini ileri veya geri kaydırın. Öntanımlı oynatma hızına (ayarlarda değiştirilmediği sürece 1x) hızlı bir şekilde dönmek için Ctrl tuşunu (Mac'te Komut tuşu) basılı tutun ve fareye sol tıklayın.\n    Skip by Scrolling Over Video Player: MPV'deki gibi videoda atlamak için kaydırma tekerleğini kullanın.\n  General Settings:\n    Invidious Instance: FreeTube'un API çağrıları için bağlanacağı Invidious örneği.\n    Thumbnail Preference: FreeTube'daki tüm küçük resimler, varsayılan küçük resim yerine videonun bir karesiyle, bulanık veya gizli şekilde değiştirilecektir.\n    Fallback to Non-Preferred Backend on Failure: Etkinleştirildiğinde, tercih ettiğiniz API'de bir sorun olduğunda FreeTube otomatik olarak tercih edilmeyen API'nizi yedek yöntem olarak kullanmaya çalışır.\n    Preferred API Backend: FreeTube'un veri elde etmek için kullandığı arka ucu seçin. Yerel API yerleşik bir çıkarıcıdır. Invidious API'si, bağlanmak için bir Invidious sunucusu gerektirir.\n    Region for Trending: Öne çıkanların bölgesi, hangi ülkenin öne çıkan videolarını görüntülemek istediğinizi seçmenize olanak tanır.\n    External Link Handling: \"FreeTube'da açılamayan bir bağlantı tıklandığında öntanımlı davranışı seçin.\\nÖntanımlı olarak FreeTube, tıklanan bağlantıyı öntanımlı tarayıcınızda açacaktır.\\n\"\n    Open Deep Links In New Window: Yeniden yönlendirilmiş tarayıcı eklentileri veya komut satırı bağımsız değişkenleri gibi FreeTube'a yönlendirilen URL'ler, yeni pencerede açılırlar.\n  External Player Settings:\n    Custom External Player Arguments: Harici oynatıcıya iletmek isteyeceğiniz, herhangi özel komut satırı argümanları.\n    Ignore Warnings: Mevcut harici oynatıcının geçerli eylemi desteklemediği durumlar için uyarıları bastır (örn. oynatma listelerini ters çevirme vb.).\n    Custom External Player Executable: Öntanımlı olarak FreeTube, seçilen harici oynatıcının PATH ortam değişkeni aracılığıyla bulunabileceğini varsayacaktır. Gerekirse, burada özel bir yol ayarlanabilir.\n    External Player: 'Harici bir oynatıcı seçmek, videoyu (destekleniyorsa oynatma listesini) harici oynatıcıda açmak için önizleme görselinde bir simge görüntüleyecektir. Uyarı: Invidious ayarları harici oynatıcıları etkilemez.'\n    DefaultCustomArgumentsTemplate: \"(Öntanımlı: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Harici oynatıcıya video URL'si dışında herhangi bir öntanımlı argüman gönderme (örn. oynatma hızı, oynatma listesi URL'si vb.). Özel argümanlar yine de gönderilecektir.\n  Experimental Settings:\n    Replace HTTP Cache: Electron'un disk tabanlı HTTP önbelleğini devre dışı bırakır ve özel bir bellek içi resim önbelleğini etkinleştirir. RAM kullanımının artmasına neden olacaktır.\n  Distraction Free Settings:\n    Hide Channels: Tüm videoların, oynatma listelerinin ve kanalın kendisinin arama, öne çıkanlar, en popüler ve tavsiye edilenlerde görünmesini engellemek için bir kanal kimliği girin. Girilen kanal kimliği tam olarak eşleşmelidir ve büyük/küçük harfe duyarlıdır.\n    Hide Subscriptions Live: Bu ayar, \"{settingsSection}\" bölümünün \"{subsection}\" kısmında yer alan uygulama genelindeki \"{appWideSetting}\" ayarı tarafından geçersiz kılınıyor\n    Hide Videos, Playlists and Channels Containing Text: Yalnızca Geçmiş, Oynatma Listeleriniz ve oynatma listelerindeki videolar hariç olmak üzere, FreeTube'un tamamında orijinal başlıkları bu sözcüğü içeren tüm videoları ve oynatma listelerini gizlemek için bir sözcük, sözcük parçası veya ifade girin (büyük/küçük harfe duyarlı değildir).\n    Hide Videos on Watch: Abonelik ve kanal sayfalarındaki videolar, kısalar ve canlı sekmelerindeki izlenen videoları gizler. Bu, kanal sayfalarındaki ana sayfa sekmesini etkilemez\n  SponsorBlock Settings:\n    UseDeArrowTitles: Video başlıklarını DeArrow'dan kullanıcıların gönderdiği başlıklarla değiştir.\n    UseDeArrowThumbnails: Video önizleme görsellerini DeArrow'dan önizleme görselleriyle değiştirin.\nPlaying Next Video Interval: Sonraki video hemen oynatılıyor. İptal etmek için tıklayın. | Sonraki video {nextVideoInterval} saniye içinde oynatılıyor. İptal etmek için tıklayın. | Sonraki video {nextVideoInterval} saniye içinde oynatılıyor. İptal etmek için tıklayın.\nMore: Daha Fazla\nUnknown YouTube url type, cannot be opened in app: Bilinmeyen YouTube URL türü, uygulamada açılamıyor\nOpen New Window: Yeni Pencere Aç\nDefault Invidious instance has been cleared: Öntanımlı Invidious örneği temizlendi\nDefault Invidious instance has been set to {instance}: Öntanımlı Invidious örneği {instance} olarak ayarlandı\nSearch Bar:\n  Clear Input: Girişi Temizle\n  Remove: Kaldır\nExternal link opening has been disabled in the general settings: Harici bağlantı açma genel ayarlarda devre dışı bırakıldı\nAre you sure you want to open this link?: Bu bağlantıyı açmak istediğinizden emin misiniz?\nScreenshot Success: Ekran görüntüsü kaydedildi\nScreenshot Error: Ekran görüntüsü başarısız oldu. {error}\nNew Window: Yeni Pencere\nChannels:\n  Empty: Kanal listeniz şu anda boş.\n  Channels: Kanallar\n  Title: Kanal Listesi\n  Search bar placeholder: Kanalları Ara\n  Count: '{number} kanal bulundu.'\n  Unsubscribe Prompt: '\"{channelName}\" aboneliğinden çıkmak istediğinizden emin misiniz?'\nClipboard:\n  Copy failed: Panoya kopyalanamadı\n  Cannot access clipboard without a secure connection: Güvenli bağlantı olmadan panoya erişilemiyor\nChapters:\n  Chapters: Bölümler\n  Key Moments: Kilit Anlar\nPreferences: Tercihler\nOk: Tamam\nHashtag:\n  Hashtag: Hashtag\n  This hashtag does not currently have any videos: Bu hashtag'in şu anda herhangi bir videosu yok\nChannel Hidden: '{channel} kanal süzgecine eklendi'\nGo to page: '{page}. sayfaya git'\nChannel Unhidden: '{channel} kanal süzgecinden kaldırıldı'\nTrimmed input must be at least N characters long: Kırpılan girdi en az 1 karakter uzunluğunda olmalıdır | Kırpılan girdi en az {length} karakter uzunluğunda olmalıdır\nTag already exists: '\"{tagName}\" etiketi zaten var'\nClose Banner: Afişi Kapat\nAge Restricted:\n  This video is age restricted: Bu videoda yaş sınırlaması var\n  This channel is age restricted: Bu kanalda yaş sınırlaması var\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nFeed:\n  Refresh Feed: '{subscriptionName} yenile'\n  Feed Last Updated: '{feedName} akışı son güncelenme: {date}'\nMoments Ago: az önce\nYes, Restart: Evet, yeniden başlat\nYes, Open Link: Evet, bağlantıyı aç\nYes, Delete: Evet, sil\nCancel: İptal\nSearch character limit: Arama sorgusu karakter sınırının ({searchCharacterLimit}) üzerinde\nSearch Listing:\n  Label:\n    Closed Captions: Kapalı Alt Yazılar\n    4K: 4K\n    Subtitles: Alt Yazılar\n    VR180: VR180\n    360 Video: 360°\n    New: Yeni\n    3D: 3B\n    8K: 8K\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nKeys:\n  arrowdown: Aşağı Ok\n  arrowleft: Sol Ok\n  arrowup: Yukarı Ok\n  ctrl: Ctrl\n  arrowright: Sağ Ok\n  alt: Alt\n  enter: Enter\n  shift: Shift\n  plus: Plus\nshortcutJoinOperator: +\nRight-click or hold to see history: Geçmişi görmek için sağ tıklayın ya da basılı tutun\nDescription:\n  Expand Description: '...devamı'\n  Collapse Description: Daha az göster\nAutoplay Interruption Timer: Otomatik oynatma, {autoplayInterruptionIntervalHours} saattir aktif olmadığı için iptal edildi\nshortcutLabelSeparator: ｜\nKeyboardShortcutPrompt:\n  Full Window: Tam pencereyi değiştir\n  Theatre Mode: Sinema modunu değiştir\n  Close Window: Pencereyi kapat\n  Fullscreen: Tam Ekran\n  Increase Video Speed: Video Oynatma Hızı Aralığına göre video hızını artır\n  Large Rewind: 10 saniye geri sar / Mevcut Video Oynatma Hızına göre videoyu geri sar\n  Minimize Window: Pencereyi küçült\n  Take Screenshot: Ekran görüntüsü al\n  History Backward: Bir sayfa geriye git\n  Skip by Tenths: Videoyu yüzdeye göre atla (3 atlayışla sürenin %30'una ulaş)\n  Refresh: Beslemeyi en son içerikle yenileyin\n  Focus Secondary Search: İkincil arama çubuğuna odaklan (varsa)\n  New Window: Yeni bir pencere oluştur\n  Navigate to History: Geçmiş sayfasına git\n  Navigate to Settings: Ayarlar sayfasına git\n  Captions: Altyazıları AÇ/KAPAT\n  Stats: Video istatistiklerini göster\n  Play: Oynat/duraklat değiştir\n  Mute: Sesi kapat\n  Decrease Video Speed: Video Oynatma Hızı Aralığına göre video hızını azalt\n  Large Fast Forward: 10 saniye ileri / Mevcut Video Oynatma Hızına göre videoyu ileri sar\n  Keyboard Shortcuts: Klavye Kısayolları\n  History Forward: Bir sayfa ileri git\n  Picture in Picture: Resim içinde Resim modu değiştir\n  Volume Up: Ses seviyesini artır\n  Next Chapter: Sonraki Bölüm\n  Zoom Out: Uzaklaştır\n  Focus Search: Arama çubuğuna odaklan\n  Search in New Window: Yeni bir pencerede ara\n  Last Frame: Önceki kare (duraklatılmışken)\n  Reset Zoom: Yakınlaştırma seviyesini / UI ölçeğini sıfırla\n  Zoom In: Yakınlaştır\n  Next Frame: Sonraki kare (duraklatılmışken)\n  Small Fast Forward: Hızlı İleri Sarma Aralığı ve geçerli Video Oynatma Hızına göre X saniye ileri sar\n  Small Rewind: Geri Sarma Aralığı ve geçerli Video Oynatma Hızına göre X saniye geri sar\n  Toggle Developer Tools: Geliştirici araçlarını aç kapat\n  Volume Down: Ses seviyesini azalt\n  Sections:\n    App:\n      General: Uygulama: Genel\n      Situational: 'Uygulama: Durumsal'\n    Video:\n      General: Video: Genel\n      Playback: Video: Oynatım\n  Last Chapter: Son Bölüm\n  Show Keyboard Shortcuts: Klavye kısayollarını göster\n  End: Videonun sonuna git\n  Home: Videonun başına git\n  Skip to Next Video: Oynatma listesindeki sonraki videoya veya sonraki önerilen videoya atla\n  Skip to Previous Video: Oynatma listesindeki bir önceki videoya atla\nCompact side navigation: Yan gezinmeyi daralt\nExpand side navigation: Yan gezinmeyi genişlet\n"
  },
  {
    "path": "static/locales/uk.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'Українська'\n\n# Webkit Menu Bar\nFile: 'Файл'\nQuit: 'Вийти'\nEdit: 'Змінити'\nUndo: 'Повернути'\nRedo: 'Повторити'\nCut: 'Вирізати'\nCopy: 'Скопіювати'\nPaste: 'Вставити'\nDelete: 'Видалити'\nSelect all: 'Вибрати все'\nToggle Developer Tools: 'Перемкнути інструменти розробника'\nActual size: 'Дійсний розмір'\nZoom in: 'Збільшити'\nZoom out: 'Зменшити'\nToggle fullscreen: 'Перемкнути повноекранний режим'\nWindow: 'Вікно'\nMinimize: 'Згорнути'\nClose: 'Закрити'\nBack: 'Назад'\nForward: 'Вперед'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Відео'\n  Shorts: Shorts\n  Live: Наживо\n  Posts: Дописи\n  Sort By: Сортувати за\n\n  Counts:\n    Video Count: 1 відео | {count} відео\n    Channel Count: 1 канал | {count} канал\n    Subscriber Count: 1 підписник | {count} підписників\n    View Count: 1 перегляд | {count} переглядів\n    Watching Count: 1 глядач | {count} глядачів\n    Like Count: 1 вподобання | {count} вподобань\n    Comment Count: 1 коментар | {count} коментарів\nVersion {versionNumber} is now available!  Click for more details: 'Доступна нова версія {versionNumber}!  Натисніть, щоб переглянути подробиці'\nDownload From Site: 'Завантажити з сайту'\nA new blog is now available, {blogTitle}. Click to view more: 'Доступний новий блог, {blogTitle}. Натисніть, щоб переглянути більше'\n\n# Search Bar\nSearch / Go to URL: 'Пошук / Перейти по URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Фільтри пошуку'\n  Sort By:\n    Most Relevant: 'Найвідповідніші'\n    Rating: 'Рейтинг'\n    Upload Date: 'Час вивантаження'\n    View Count: 'Кількість переглядів'\n  Time:\n    Time: 'Час'\n    Any Time: 'Будь-який час'\n    Last Hour: 'Остання година'\n    Today: 'Сьогодні'\n    This Week: 'Цього тижня'\n    This Month: 'Цього місяця'\n    This Year: 'Цього року'\n  Type:\n    Type: 'Тип'\n    All Types: 'Усі типи'\n    Videos: 'Відео'\n    Channels: 'Канали'\n    #& Playlists\n    Movies: Фільми\n  Duration:\n    Duration: 'Тривалість'\n    All Durations: 'Будь-яка тривалість'\n    Short (< 4 minutes): 'Короткі (< 4 хвилини)'\n    Long (> 20 minutes): 'Довгі (> 20 хвилин)'\n  # On Search Page\n    Medium (4 - 20 minutes): Середні (4 - 20 хвилин)\n  Search Results: 'Результати пошуку'\n  Fetching results. Please wait: 'Завантажуються результати. Будь ласка, зачекайте'\n  Fetch more results: 'Завантажити більше результатів'\n# Sidebar\n  There are no more results for this search: Більше результатів для цього пошуку немає\n  Features:\n    Features: Функції\n    HD: HD\n    Subtitles: Субтитри\n    Live: Наживо\n    4K: 4K\n    360 Video: 360 Відео\n    Location: Розташування\n    HDR: HDR\n    VR180: VR180\n    3D: 3D\n    Creative Commons: Творчі Спільноти\n  Clear Filters: Очистити фільтри\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Підписки'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'Цей профіль має велику кількість підписок. Використайте RSS щоб уникнути обмеження швидкості'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Ваш список підписок наразі порожній. Якщо ви хочете імпортувати свої підписки, перейдіть до налаштувань даних і виберіть \"Імпортувати підписки\", або ви можете знайти канал і підписатися на нього.'\n  Load More Videos: 'Завантажити більше відео'\n  Error Channels: Канали з помилками\n  Disabled Automatic Fetching: Ви вимкнули автоматичне отримання підписок. Оновіть підписки, щоб вони з'явились тут.\n  Empty Channels: Канали, на які ви підписалися, наразі не містять відео.\n  Subscriptions Tabs: Вкладки підписок\n  All Subscription Tabs Hidden: Усі вкладки підписки сховані. Щоб побачити вміст, будь ласка, відкрийте деякі вкладки в розділі \"{subsection}\" в \"{settingsSection}\".\n  Load More Posts: Завантажити ще дописи\n  Empty Posts: На каналах, на які ви підписані, наразі немає дописів.\nTrending:\n  Trending: 'Популярне'\n  Trending Tabs: Популярні вкладки\n  Gaming: Ігри\n  Sports: Спорт\nMost Popular: 'Найпопулярніші'\nPlaylists: 'Добірки'\nUser Playlists:\n  Your Playlists: 'Ваші добірки'\n  Search bar placeholder: Шукати добірки\n  Empty Search Message: Немає відео в цій добірці, які відповідають вашому запиту\n  Create New Playlist: Створити новий список відтворення\n  Add to Playlist: Додати список відтворення\n  Remove from Favorites: Вилучити з {playlistName}\n  Move Video Up: Посунути відео вгору\n  Move Video Down: Посунути відео вниз\n  Remove from Playlist: Вилучити зі списку відтворення\n  Playlist Description: Опис списку відтворення\n  Save Changes: Зберегти зміни\n  Cancel: Скасувати\n  Copy Playlist: Скопіювати список відтворення\n  You have no playlists. Click on the create new playlist button to create a new one.: У вас немає списків відтворення. Натисніть на кнопку створити новий список відтворення, щоб створити його.\n  This playlist currently has no videos.: Наразі у цьому списку відтворення немає відео.\n  Add to Favorites: Додати до {playlistName}\n  Playlist Name: Назва списку відтворення\n  Edit Playlist Info: Змінити інформацію списку відтворення\n  Remove Watched Videos: Вилучити з переглянутих відео\n  Delete Playlist: Видалити добірку\n  Sort By:\n    LatestPlayedFirst: Нещодавно переглянуті\n    EarliestPlayedFirst: Найдавніше переглянуті\n    NameAscending: А-Я\n    LatestCreatedFirst: Нещодавно створено\n    EarliestCreatedFirst: Створено найраніше\n    NameDescending: Я-А\n    EarliestUpdatedFirst: Найстаріші оновлення\n    LatestUpdatedFirst: Останні оновлення\n  SinglePlaylistView:\n    Toast:\n      This playlist is now used for quick bookmark: Ця добірка тепер використовується для швидких закладок\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Ця добірка тепер використовується для швидких закладок замість {oldPlaylistName}. Натисніть тут, щоб скасувати\n      This video cannot be moved up.: Це відео не можна перемістити вгору.\n      This video cannot be moved down.: Це відео не можна перемістити вниз.\n      Video has been removed: Відео було видалено\n      This playlist is already being used for quick bookmark.: Ця добірка вже використовується для швидких закладок.\n      There was a problem with removing this video: Сталася помилка під час видалення цього відео\n      Reverted to use {oldPlaylistName} for quick bookmark: Повернуто до використання {oldPlaylistName} для швидких закладок\n      This playlist is protected and cannot be removed.: Цю добірку захищено, тому її не можна видалити.\n      \"{videoCount} video(s) have been removed\": 1 відео було видалено | {videoCount} відео було видалено\n      Playlist {playlistName} has been deleted.: Добірку {playlistName} було видалено.\n      This playlist does not exist: Ця добірка не існує\n      This playlist has a video with a duration error: Ця добірка містить принаймні одне відео, яке не має тривалості, тому воно буде відсортоване так, ніби його тривалість дорівнює нулю.\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Деякі відео в добірці ще не завантажено. Натисніть тут, щоб все одно скопіювати.\n      Playlist name cannot be empty. Please input a name.: Назва добірки не може бути порожньою. Будь ласка, введіть назву.\n      Playlist has been updated.: Добірка була оновлена.\n      There was an issue with updating this playlist.: Сталася помилка при оновленні цієї добірки.\n      There were no videos to remove.: Відео для видалення не знайдено.\n      Video has been removed. Click here to undo.: Відео видалено. Натисніть тут, щоб скасувати.\n    Search for Videos: Пошук відео\n  The playlist has been successfully exported: Добірку успішно експортовано\n  Export Playlist: Експортувати цю добірку\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Ви впевнені, що хочете видалити 1 переглянуте відео з цієї добірки? Цю дію не можна скасувати. | Ви впевнені, що хочете видалити {playlistItemCount} переглянутих відео з цієї добірки? Цю дію не можна скасувати.\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Ви впевнені, що хочете видалити 1 дубльоване відео з цієї добірки? Цю дію не можна скасувати. | Ви впевнені, що хочете видалити {playlistItemCount} дубльованих відео з цієї добірки? Цю дію не можна скасувати.\n  Are you sure you want to delete this playlist? This cannot be undone: Ви впевнені, що хочете видалити цю добірку? Це неможливо скасувати.\n  Enable Quick Bookmark With This Playlist: Увімкнути швидке додавання в закладки для цієї добірки\n  Quick Bookmark Enabled: Швидке додавання в закладки увімкнено\n  Cannot delete the quick bookmark target playlist.: Неможливо видалити добірку швидких закладок.\n  Playlists with Matching Videos: Добірки з відповідними відео\n  Remove Duplicate Videos: Видалити дублікати відео\n  AddVideoPrompt:\n    Save: Зберегти\n    Search in Playlists: Пошук в добірках\n    Allow Adding Duplicate Video(s): Дозволити додавати дублікатів відео\n    Added {count} Times: Вже додано | Додано {count} разів\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} Відео буде додано'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} Відео вже додано'\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n      You haven't selected any playlist yet.: Ви ще не вибрали жодної добірки.\n    N playlists selected: '{playlistCount} вибрано'\n    Select a playlist to add your N videos to: Виберіть добірку, до якої ви хочете додати своє відео | Виберіть добірку, до якої ви хочете додати свої {videoCount} відео\n  CreatePlaylistPrompt:\n    Create: Створити\n    Toast:\n      Playlist {playlistName} has been successfully created.: Добірку {playlistName} успішно створено.\n      There was an issue with creating the playlist.: Сталася помилка під час створення добірки.\n      There is already a playlist with this name. Please pick a different name.: Вже існує добірка з такою назвою. Будь ласка, виберіть іншу назву.\n    New Playlist Name: Нова назва добірки\n  TotalTimePlaylist: 'Загальний час: {duration}'\nHistory:\n  # On History Page\n  History: 'Історія'\n  Watch History: 'Історія переглядів'\n  Your history list is currently empty.: 'Ваша історія переглядів на разі порожня.'\n  Search bar placeholder: Шукати в історії\n  Empty Search Message: У вашій історії немає відео, що відповідають вашому пошуку\n  Case Sensitive Search: Пошук з урахуванням регістру\nSettings:\n  # On Settings Page\n  Settings: 'Налаштування'\n  The app needs to restart for changes to take effect. Restart and apply change?: 'Щоб зміни набули чинності, необхідно перезавантижити застосунок. Перезавантажити та застосувати зміни?'\n  General Settings:\n    General Settings: 'Загальні'\n    Check for Updates: 'Перевірити наявність оновлень'\n    Check for Latest Blog Posts: 'Перевірити останні повідомлення в блозі'\n    Fallback to Non-Preferred Backend on Failure: 'Коли у вашого головного API виникає проблема, FreeTube спробує автоматично використати допоміжний API у якості резервного, якщо він увімкнений'\n    Enable Search Suggestions: 'Увімкнути рекомендації пошуку'\n    Default Landing Page: 'Типова головна сторінка'\n    Locale Preference: 'Локальні налаштування'\n    Preferred API Backend:\n      Preferred API Backend: 'Головний API бекенд'\n      Local API: 'Локальний API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: 'Тип перегляду відео'\n      Grid: 'Сітка'\n      List: 'Список'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Налаштування мініатюр'\n      Default: 'Типово'\n      Beginning: 'На початку'\n      Middle: 'У середині'\n      End: 'У кінці'\n      Hidden: Сховано\n      Blur: Розмиття\n    Region for Trending: 'Регіон для Популярних'\n        #! List countries\n    View all Invidious instance information: Перегляд усіх відомостей про екземпляр Invidious\n    System Default: За системними налаштуваннями\n    Clear Default Instance: Очистити типовий екземпляр\n    Set Current Instance as Default: Установити поточний екземпляр типовим\n    Current instance will be randomized on startup: Поточний випадковий екземпляр буде обрано під час запуску\n    No default instance has been set: Типовий екземпляр не встановлено\n    The currently set default instance is {instance}: Поточний встановлений типовим екземпляр — {instance}\n    Current Invidious Instance: Поточний екземпляр Invidious\n    External Link Handling:\n      No Action: Без дій\n      Ask Before Opening Link: Запитувати, перш ніж відкрити посилання\n      Open Link: Відкрити посилання\n      External Link Handling: Обробка зовнішніх посилань\n    Auto Load Next Page:\n      Label: Автозавантаження наступної сторінки\n      Tooltip: Автоматично завантажувати додаткові сторінки та коментарі.\n    Open Deep Links In New Window: Відкривати URL-адреси, передані в FreeTube, в новому вікні\n  Theme Settings:\n    Theme Settings: 'Теми'\n    Match Top Bar with Main Color: 'Верхня панель основного кольору'\n    Expand Side Bar by Default: 'Усталено розгортати бічну панель'\n    Disable Smooth Scrolling: 'Відключити плавну прокрутку'\n    UI Scale: 'Масштаб інтерфейсу'\n    Base Theme:\n      Base Theme: 'Базова тема'\n      Black: 'Чорна'\n      Dark: 'Темна'\n      Light: 'Світла'\n      Dracula: 'Дракула'\n      System Default: Тема системи\n      Catppuccin Mocha: Капучино мокко\n      Hot Pink: Гарячий рожевий\n      Pastel Pink: Пастельний рожевий\n      Gruvbox Dark: Gruvbox Темний\n      Solarized Light: Solarized Світлий\n      Nordic: Нордичний\n      Gruvbox Light: Gruvbox Світлий\n      Solarized Dark: Solarized Темна\n      Catppuccin Frappe: Капучино фрапе\n      Everforest Dark Hard: Everforest Dark Hard (Темний ліс)\n      Everforest Dark Medium: Everforest Dark Medium (Темний середній)\n      Everforest Dark Low: Вічнозелений ліс Темний низький\n      Everforest Light Hard: Everforest Light Твердий\n      Everforest Light Medium: Everforest Light Середній\n      Everforest Light Low: вічнозелене світло низьке\n    Main Color Theme:\n      Main Color Theme: 'Основна кольорова тема'\n      Red: 'Червона'\n      Pink: 'Рожева'\n      Purple: 'Фіолетова'\n      Deep Purple: 'Темно-фіолетова'\n      Indigo: 'Індіго'\n      Blue: 'Синя'\n      Light Blue: 'Світло-синя'\n      Cyan: 'Блакитна'\n      Teal: 'Бірюзова'\n      Green: 'Зелена'\n      Light Green: 'Світло-зелена'\n      Lime: 'Лаймова'\n      Yellow: 'Жовта'\n      Amber: 'Бурштинова'\n      Orange: 'Жовтогаряча'\n      Deep Orange: 'Насичена жовтогаряча'\n      Dracula Cyan: 'Дракула Блакитна'\n      Dracula Green: 'Дракула Зелена'\n      Dracula Orange: 'Дракула Жовтогаряча'\n      Dracula Pink: 'Дракула Рожева'\n      Dracula Purple: 'Дракула Фіолетова'\n      Dracula Red: 'Дракула Червона'\n      Dracula Yellow: 'Дракула Жовта'\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Red: Catppuccin Mocha Red\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach\n      Catppuccin Mocha Green: Catppuccin Mocha Green\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Gruvbox Dark Purple: Gruvbox Темно Фіолетовий\n      Gruvbox Light Blue: Gruvbox Світло Голубий\n      Solarized Cyan: Solarized Голубий\n      Solarized Green: Solarized Зелений\n      Gruvbox Light Orange: Gruvbox Світло Оранжевий\n      Solarized Yellow: Solarized Жовтий\n      Gruvbox Dark Green: Gruvbox Темно Зелений\n      Gruvbox Dark Blue: Gruvbox Темно Синій\n      Gruvbox Dark Aqua: Gruvbox Темна Аква\n      Gruvbox Dark Orange: Gruvbox Темно Оранжевий\n      Gruvbox Light Red: Gruvbox Світло Червоний\n      Gruvbox Light Purple: Gruvbox Світло Фіолетовий\n      Solarized Magenta: Solarized Пурпурний\n      Solarized Violet: Solarized Фіолетовий\n      Solarized Orange: Solarized Оранжевий\n      Solarized Red: Solarized Червоний\n      Gruvbox Dark Yellow: Gruvbox Темно Жовтий\n      Solarized Blue: Solarized Голубий\n      Catppuccin Frappe Rosewater: Капучино фрапе з рожевою водою\n      Catppuccin Frappe Sapphire: Капучино фрапе сапфіровий\n      Catppuccin Frappe Blue: Капучино фрапе синій\n      Catppuccin Frappe Lavender: Капучино фрапе лавандовий\n      Catppuccin Frappe Teal: Капучино фрапе бірюзовий\n      Catppuccin Frappe Flamingo: Капучино фрапе Фламінго\n      Catppuccin Frappe Green: Капучино фрапе зелений\n      Catppuccin Frappe Red: Капучино фрапе червоний\n      Catppuccin Frappe Peach: Капучино фрапе персиковий\n      Catppuccin Frappe Pink: Капучино фрапе рожевий\n      Catppuccin Frappe Sky: Капучино фрапе небесний\n      Catppuccin Frappe Mauve: Капучино фрапе фіолетовий\n      Catppuccin Frappe Maroon: Капучино фрапе бордовий\n      Catppuccin Frappe Yellow: Капучино фрапе жовтий\n      Everforest Light Red: Everforest Light Червоний\n      Everforest Dark Yellow: Темно-жовтий вічнозелений ліс\n      Everforest Dark Red: Вічнозелений темно-червоний\n      Everforest Dark Orange: Еверфорест Темно-помаранчевий\n      Everforest Dark Green: Темно-зелений вічнозелений ліс\n      Everforest Dark Aqua: Еверфорест Темна Аква\n      Everforest Dark Blue: Темно-синій Everforest\n      Everforest Dark Purple: Еверфорест Темно-фіолетовий\n      Everforest Light Yellow: Еверфорест світло-жовтий\n      Everforest Light Green: Еверфорест Світло-зелений\n      Everforest Light Orange: Everforest Світло-помаранчевий\n      Everforest Light Aqua: Еверфорест Лайт Аква\n      Everforest Light Blue: Еверфорест Світло-блакитний\n      Everforest Light Purple: Світло-фіолетовий Everforest\n    Secondary Color Theme: 'Другорядна кольорова тема'\n        #* Main Color Theme\n    Hide Side Bar Labels: Сховати мітки бічної панелі\n    Hide FreeTube Header Logo: Сховати логотип FreeTube із заголовка\n  Player Settings:\n    Player Settings: 'Плеєр'\n    Play Next Video: 'Автовідтворення рекомендованих відео'\n    Turn on Subtitles by Default: 'Увімкнути субтитри за замовчуванням'\n    Autoplay Videos: 'Автоматично запускати відео'\n    Proxy Videos Through Invidious: 'Проксі-відео через Invidious'\n    Autoplay Playlists: 'Автовідтворення відео з добірки'\n    Enable Theatre Mode by Default: 'Типово увімкнути режим театру'\n    Default Volume: 'Типова гучність'\n    Default Playback Rate: 'Типова швидкість відтворення'\n    Default Video Format:\n      Default Video Format: 'Типовий формат відео'\n      Dash Formats: 'Формати DASH'\n      Legacy Formats: 'Застарілі формати'\n      Audio Formats: 'Аудіо формати'\n    Default Quality:\n      Default Quality: 'Типова якість'\n      Auto: 'Автоматично'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: Таймер автозапуску\n    Scroll Volume Over Video Player: Прокручування гучності на відеопрогравачі\n    Display Play Button In Video Player: Показувати кнопку відтворення у відеопрогравачі\n    Fast-Forward / Rewind Interval: Інтервал перемотування вперед/назад\n    Scroll Playback Rate Over Video Player: Контроль швидкості відтворення коліщам миші у відеопрогравачі\n    Video Playback Rate Interval: Інтервал швидкості відтворення відео\n    Max Video Playback Rate: Максимальна швидкість відтворення відео\n    Screenshot:\n      Folder Label: Тека зі знімками екрана\n      File Name Label: Шаблон назви файлу\n      Error:\n        Forbidden Characters: Заборонені символи\n        Empty File Name: Порожня назва файлу\n      Enable: Увімкнути знімок екрана\n      Format Label: Формат знімка екрана\n      Folder Button: Вибрати теку\n      Quality Label: Якість знімка екрана\n      Ask Path: Запитувати у якій теці зберігати\n      File Name Tooltip: Нижче ви можете використовувати змінні. %Y Рік 4 цифри. %M Місяць 2 цифри. %D день 2 цифри. %H Година 2 цифри. %N Хвилина 2 цифри. %S Секунда 2 цифри. %T Мілісекунда 3 цифри. %s Секунда відео. %t Мілісекунда відео 3 цифри. %i ID відео.\n    Enter Fullscreen on Display Rotate: Переходити в повноекранний режим за обертання екрана\n    Skip by Scrolling Over Video Player: Пропустити гортанням відеопрогравача\n    Autoplay Interruption Timer: Таймер переривання автозапуску\n    Default Viewing Mode:\n      Picture in Picture: Картинка в картинці\n      Theater: Театр\n      External Player: Зовнішній плеєр ({externalPlayerName})\n      Default Viewing Mode: Режим перегляду за замовчуванням\n      Full Screen: Повноекранний режим\n  Privacy Settings:\n    Privacy Settings: 'Конфіденційність'\n    Remember History: 'Зберігати історію переглядів'\n    Save Watched Progress: 'Зберігати прогрес перегляду'\n    Clear Search Cache: 'Очистити пошуковий кеш'\n    Are you sure you want to clear out your search cache?: 'Дійсно бажаєте очистити кеш пошуку?'\n    Search cache has been cleared: 'Кеш пошуку очищено'\n    Remove Watch History: 'Видалити історію переглядів'\n    Are you sure you want to remove your entire watch history?: 'Дійсно бажаєте вилучити всю історію переглядів?'\n    Watch history has been cleared: 'Історію переглядів було очищено'\n    Remove All Subscriptions / Profiles: 'Видалити всі підписки / профілі'\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 'Справді хочете вилучити всі підписки та профілі? Цю дію не можна скасувати.'\n    Save Watched Videos With Last Viewed Playlist: Зберегти переглянуті відео у список відтворення, який ви переглядали останнім часом\n    All playlists have been removed: Усі добірки були видалені\n    Remove All Playlists: Видалити всі добірки\n    Are you sure you want to remove all your playlists?: Ви впевнені, що хочете видалити всі свої добірки?\n    Remember Search History: Зберігати історію пошуку\n    Search history and cache have been cleared: Історію пошуку та кеш очищено\n    Clear Search History and Cache: Очистити історію пошуку та кеш\n    Are you sure you want to clear out your search history and cache?: Ви впевнені, що хочете очистити історію пошуку та кеш?\n    Watched Progress Saving Mode:\n      Tooltip: Авто = Зберігати при кожному виході зі сторінки відео, коли відео завершене або виникла помилка (наприклад, обмеження швидкості або завершення сеансу перегляду). Напівавтомат = Як і Авто, але без збереження при виході зі сторінки відео; можна зберегти прогрес вручну через кнопку \"Зберегти переглянутий прогрес\", що розташована під відеоплеєром.\n      Modes:\n        Auto: Авто\n        Semi-auto: Напівавтомат\n        Never: Ніколи\n  Subscription Settings:\n    Subscription Settings: 'Підписка'\n    Fetch Feeds from RSS: 'Отримати канали з RSS'\n    Fetch Automatically: Автоматично отримувати стрічку\n    Confirm Before Unsubscribing: Підтвердити перед скасуванням підписки\n    'Limit the number of videos displayed for each channel': Обмежити кількість відео, що відображаються для кожного каналу\n    To: До\n  Distraction Free Settings:\n    Distraction Free Settings: 'Без відволікань'\n    Hide Video Views: 'Сховати перегляди відео'\n    Hide Video Likes And Dislikes: 'Приховати вподобайки до відео'\n    Hide Channel Subscribers: 'Не показувати підписників каналу'\n    Hide Comment Likes: 'Не показувати уподобання коментарів'\n    Hide Recommended Videos: 'Не показувати рекомендовані відео'\n    Hide Trending Videos: 'Не показувати тренди відео'\n    Hide Popular Videos: 'Не показувати популярні відео'\n    Hide Live Chat: 'Не показувати живий чат'\n    Hide Active Subscriptions: Сховати активні підписки\n    Hide Playlists: Сховати добірки\n    Hide Video Description: Сховати опис відео\n    Hide Comments: Сховати коментарі\n    Hide Sharing Actions: Сховати дії поширення\n    Hide Videos on Watch: 'Ховати відео при перегляді'\n    Hide Live Streams: Сховати прямі трансляції\n    Hide Chapters: Сховати розділи\n    Hide Upcoming Premieres: Сховати майбутні прем'єри\n    Hide Channels: Сховати відео з каналів\n    Hide Channels Placeholder: ID каналу\n    Display Titles Without Excessive Capitalisation: Відображати заголовки без зайвої капіталізації та пунктуації\n    Hide Featured Channels: Сховати пропоновані канали\n    Hide Channel Playlists: Сховати добірки каналу\n    Hide Channel Shorts: Сховати вкладку \"Shorts\" каналу\n    Sections:\n      Side Bar: Бічна панель\n      Channel Page: Сторінка каналу\n      Watch Page: Сторінка перегляду\n      General: Загальні\n      Subscriptions Page: Сторінка підписок\n    Hide Subscriptions Videos: Сховати відео з підписок\n    Hide Channel Podcasts: Сховати вкладку \"Подкасти\" каналу\n    Hide Channel Releases: Сховати вкладку \"Випуски\" каналу\n    Hide Subscriptions Shorts: Сховати Shorts із підписок\n    Hide Subscriptions Live: Сховати трансляції з підписок\n    Hide Profile Pictures in Comments: Сховати зображення профілю в коментарях\n    Hide Channels Invalid: Вказаний ID каналу недійсний\n    Hide Channels Disabled Message: Деякі канали були заблоковані за допомогою ID і не були оброблені. Функція заблокована в той час, як ці ID оновлювалися\n    Hide Channels Already Exists: ID каналу вже існує\n    Hide Channels API Error: Помилка під час пошуку користувача з наданим ID. Перевірте ще раз, чи правильний ID.\n    Hide Channel Home: Сховати вкладку \"Головна\" каналу\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Слово, фрагмент слова або фраза\n    Hide Videos, Playlists and Channels Containing Text: Сховати відео та добірки, що містять текст\n    Show Added Items: Показати додані елементи\n    Hide Channel Courses: Приховати вкладку «Курси» каналу\n    Hide Channel Posts: Сховати вкладку \"Пости\" каналу\n    Hide Subscriptions Posts: Сховати пости підписок\n  Data Settings:\n    Data Settings: 'Дані'\n    Select Export Type: 'Оберіть тип експорту'\n    Import Subscriptions: 'Імпортувати підписки'\n    Export Subscriptions: 'Експортувати підписки'\n    Export FreeTube: 'Експортувати FreeTube'\n    Export YouTube: 'Експортувати YouTube'\n    Export NewPipe: 'Експортувати NewPipe'\n    Import History: 'Імпортувати історію'\n    Export History: 'Експортувати історію'\n    Profile object has insufficient data, skipping item: 'Об’єкт профілю має недостатньо даних, пропуск елемента'\n    All subscriptions and profiles have been successfully imported: 'Усі підписки та профілі успішно імпортовано'\n    All subscriptions have been successfully imported: 'Усі підписки успішно імпортовано'\n    Invalid subscriptions file: 'Недійсний файл підписок'\n    Invalid history file: 'Недійсний файл історії'\n    Subscriptions have been successfully exported: 'Підписки успішно експортовано'\n    History object has insufficient data, skipping item: 'У об’єкта історії недостатньо даних, пропуск елемента'\n    All watched history has been successfully imported: 'Всю історію переглядів успішно імпортовано'\n    All watched history has been successfully exported: 'Всю історію переглядів успішно експортовано'\n    Unable to read file: 'Не вдалося прочитати файл'\n    Unable to write file: 'Не вдалося записати файл'\n    Unknown data key: 'Невідомий ключ даних'\n    How do I import my subscriptions?: 'Як імпортувати свої підписки?'\n    Manage Subscriptions: Керування підписками\n    Playlist insufficient data: Недостатньо даних для списку відтворення \"{playlist}\", пропуск елемента\n    All playlists has been successfully exported: Усі добірки успішно експортовано\n    Import Playlists: Імпорт добірок\n    Export Playlists: Експорт добірок\n    All playlists has been successfully imported: Усі добірки успішно імпортовано\n    Playlist File: Файл списку відтворення\n    Subscription File: Файл підписки\n    History File: Файл історії\n    Export Playlists For Older FreeTube Versions:\n      Label: Експортувати добірки для старих версій FreeTube\n      Tooltip: \"Ця опція експортує відео з усіх добірок в одну добірку під назвою \\\"Улюблені\\\".\\nЯк експортувати та імпортувати відео з добірок для старої версії FreeTube:\\n1. Експортуйте свої добірки увімкнувши цю опцію.\\n2. Видаліть усі свої наявні добірки за допомогою опції \\\"Вилучити всі добірки\\\" в налаштуваннях приватності..\\n3. Запустіть стару версію FreeTube та імпортуйте експортовані добірки.\"\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: Помилка отримання відомостей про мережу. Чи правильно налаштовано ваш проксі?\n    City: Місто\n    Region: Регіон\n    Country: Країна\n    Ip: IP\n    Your Info: Ваші дані\n    Test Proxy: Перевірка проксі\n    Clicking on Test Proxy will send a request to: Натискання кнопки Перевірити проксі надішле запит\n    Proxy Port Number: Номер порту проксі\n    Proxy Host: Проксі-вузол\n    Proxy Protocol: Проксі-протокол\n    Enable Tor / Proxy: Увімкнути Tor / Проксі\n    Proxy Settings: Проксі\n    Proxy Warning: FreeTube не має вбудованого проксі, але може підключатися до зовнішнього проксі, такого як Tor, що працює на вашому комп'ютері, або зовнішній проксі, наприклад, SOCKS5 проксі, який надають деякі VPN-сервіси. Якщо ця опція увімкнена, переконайтеся, що ваш проксі/Tor налаштовані правильно, інакше FreeTube не зможе завантажувати дані.\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: Сповіщати про пропуск спонсорованого відтинка\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL-адреса API SponsorBlock (типово https://sponsor.ajay.app)\n    Enable SponsorBlock: Увімкнути SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: Опція пропуску\n      Auto Skip: Автопропуск\n      Show In Seek Bar: Показати на панелі прокрутки\n      Prompt To Skip: Запит на пропуск\n      Do Nothing: Нічого не робити\n    Category Color: Колір категорії\n    UseDeArrowTitles: Використовувати назви для відео DeArrow\n    UseDeArrowThumbnails: Використовувати DeArrow для ескізів\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL API генератора ескізів DeArrow (за замовчуванням: https://dearrow-thumb.ajay.app)'\n  External Player Settings:\n    Custom External Player Arguments: Власні аргументи зовнішнього програвача\n    Custom External Player Executable: Власний виконуваний зовнішній програвач\n    Ignore Unsupported Action Warnings: Нехтувати попередженнями про непідтримувані дії\n    External Player: Зовнішній програвач\n    External Player Settings: Зовнішній плеєр\n    Players:\n      None:\n        Name: Немає\n    Ignore Default Arguments: Ігнорувати стандартні аргументи\n  Parental Control Settings:\n    Parental Control Settings: Батьківський контроль\n    Hide Unsubscribe Button: Сховати кнопку скасування підписки\n    Show Family Friendly Only: Показати лише для сімейного перегляду\n    Hide Search Bar: Сховати панель пошуку\n    Hide Uploader on Watch page: Приховати Канал на Сторінці перегляду\n  Experimental Settings:\n    Replace HTTP Cache: Заміна кешу HTTP\n    Experimental Settings: Експериментальні\n    Warning: Ці налаштування експериментальні, їхнє ввімкнення може призводити до збоїв. Радимо робити резервні копії. Використовуйте на свій страх і ризик!\n  Password Dialog:\n    Enter Password To Unlock: Введіть пароль, щоб розблокувати налаштування\n    Password: Пароль\n  Password Settings:\n    Password Settings: Пароль\n    Set Password: Установити пароль\n    Remove Password: Вилучити пароль\n    Set Password To Prevent Access: Встановіть пароль, щоб запобігти доступу до налаштувань\n  Return to Settings Menu: Повернутися до налаштувань\n  Sort Settings Sections (A-Z): Сортувати розділи налаштувань (А-Я)\nAbout:\n  #On About page\n  About: 'Про додаток'\n  #& About\n  Donate: Підтримати\n  these people and projects: цим людям та проєктам\n  Credits: Про авторів\n  Translate: Перекласти\n  room rules: правила кімнати\n  Chat on Matrix: Чат у Matrix\n  Mastodon: Mastodon\n  Email: Електронна пошта\n  Blog: Блог\n  Website: Вебсайт\n  Please check for duplicates before posting: Будь ласка, перевірте наявність повторів перед публікацією\n  GitHub issues: Проблеми на GitHub\n  Report a problem: Повідомити про проблему\n  FAQ: ЧаПи\n  FreeTube Wiki: Вікі FreeTube\n  Help: Довідка\n  GitHub releases: Випуски GitHub\n  Downloads / Changelog: Завантаження / Журнал змін\n  Source code: Джерельний код\n  Beta: Бета\n  Discussions: Обговорення\n  AGPLv3: AGPLv3\nProfile:\n  Profile Select: 'Вибір профілю'\n  All Channels: 'Усі канали'\n  Profile Manager: 'Керування профілями'\n  Create New Profile: 'Створити новий профіль'\n  Edit Profile: 'Редагувати профіль'\n  Color Picker: 'Вибір кольору'\n  Custom Color: 'Власний колір'\n  Profile Preview: 'Попередній перегляд профілю'\n  Create Profile: 'Створити профіль'\n  Update Profile: 'Оновити профіль'\n  Make Default Profile: 'Зробити профіль типовим'\n  Delete Profile: 'Видалити профіль'\n  Are you sure you want to delete this profile?: 'Справді видалити цей профіль?'\n  All subscriptions will also be deleted.: 'Усі підписки також буде видалено.'\n  Your profile name cannot be empty: 'Ім''я профілю не може бути порожнім'\n  Profile has been created: 'Профіль створено'\n  Profile has been updated: 'Профіль оновлено'\n  Your default profile has been set to {profile}: 'Типовим профілем встановлено {profile}'\n  Removed {profile} from your profiles: '{profile} вилучено з профілів'\n  Your default profile has been changed to your primary profile: 'Ваш типовий профіль змінено на основний'\n  '{profile} is now the active profile': '{profile} активний профіль зараз'\n  Subscription List: 'Перелік підписок'\n  Other Channels: 'Інші канали'\n  '{number} selected': '{number} вибрано'\n  Select All: 'Вибрати все'\n  Select None: 'Нічого не вибрано'\n  Delete Selected: 'Видалити вибране'\n  Add Selected To Profile: 'Додати вибране до профілю'\n  No channel(s) have been selected: 'Не вибрано жодного каналу'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'Це ваш основний профіль. Ви впевнені, що хочете видалити вибрані канали? Ті ж канали буде видалені в будь-якому профілі, в якому вони перебувають.'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'Дійсно бажаєте видалити вибрані канали?  Канал не буде видалено з будь-якого іншого профілю.'\n#On Channel Page\n  Profile Filter: Фільтр профілю\n  Profile Settings: Профіль\n  Toggle Profile List: Перемкнути список профілів\n  Profile Name: Назва профілю\n  Edit Profile Name: Змінити назву профілю\n  Create Profile Name: Створити назву профілю\n  Open Profile Dropdown: Відкрити спадне меню профілю\n  Close Profile Dropdown: Закрити спадне меню профілю\nChannel:\n  Subscribe: 'Підписатися'\n  Unsubscribe: 'Відписатися'\n  Channel has been removed from your subscriptions: 'Канал прибрано з ваших підписок'\n  Removed subscription from {count} other channel(s): 'Вилучено підписку з {count} інших каналів'\n  Added channel to your subscriptions: 'Додано канал до підписок'\n  Search Channel: 'Шукати на каналі'\n  Your search results have returned 0 results: 'Пошук дав 0 результатів'\n  Videos:\n    Videos: 'Відео'\n    This channel does not currently have any videos: 'Наразі на цьому каналі немає жодного відео'\n    Sort Types:\n      Newest: 'Найновіші'\n      Oldest: 'Найдавніші'\n      Most Popular: 'Найпопулярніші'\n  Playlists:\n    Playlists: 'Добірки'\n    This channel does not currently have any playlists: 'Цей канал наразі не має добірок'\n    Sort Types:\n      Last Video Added: 'Останнє додане відео'\n      Newest: 'Найновіші'\n      Oldest: 'Найдавніші'\n  About:\n    About: 'Про канал'\n    Channel Description: 'Опис каналу'\n    Featured Channels: 'Рекомендовані канали'\n    Tags:\n      Tags: Мітки\n      Search for: Шукати «{tag}»\n    Details: Подробиці\n    Joined: Дата приєднання\n    Location: Розташування\n  This channel does not exist: Цей канал не існує\n  This channel does not allow searching: Цей канал не дозволяє здійснювати пошук\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Цей канал має вікові обмеження і наразі не може бути переглянутий на FreeTube.\n  Channel Tabs: Вкладки каналів\n  Posts:\n    This channel currently does not have any posts: Зараз на цьому каналі немає публікацій\n    votes: 'Голосів: {votes}'\n    Reveal Answers: Розгорнути відповіді\n    Hide Answers: Сховати відповіді\n    Video hidden by FreeTube: Відео приховане FreeTube\n    View Full Post: Переглянути повний пост\n    Viewing Posts Only Supported By Invidious: Перегляд постів підтримується лише через Invidious. Перейдіть до вкладки спільноти каналу, щоб переглядати контент без Invidious.\n  Live:\n    This channel does not currently have any live streams: Наразі на цьому каналі немає прямих трансляцій\n    Live: Наживо\n  Shorts:\n    This channel does not currently have any shorts: На цьому каналі немає Shorts\n  Podcasts:\n    Podcasts: Подкасти\n    This channel does not currently have any podcasts: На цьому каналі наразі немає подкастів\n  Releases:\n    This channel does not currently have any releases: Наразі на цьому каналі немає випусків\n    Releases: Випуски\n  Home:\n    Home: Головна\n    View Playlist: Переглянути добірку\n  Courses:\n    Courses: курси\n    This channel does not currently have any courses: На цьому каналі наразі немає курсів\nVideo:\n  Mark As Watched: 'Позначити переглянутим'\n  Remove From History: 'Прибрати з історії'\n  Video has been marked as watched: 'Відео позначено переглянутим'\n  Video has been removed from your history: 'Відео вилучено з історії'\n  Open in YouTube: 'Відкрити в YouTube'\n  Copy YouTube Link: 'Копіювати посилання youTube'\n  Open YouTube Embedded Player: 'Відкрити вбудований програвач YouTube'\n  Copy YouTube Embedded Player Link: 'Копіювати посилання вбудованого програвача YouTube'\n  Open in Invidious: 'Відкрито в Invidious'\n  Copy Invidious Link: 'Копіювати посилання Invidious'\n  Open Channel in YouTube: 'Відкрити канал на YouTube'\n  Copy YouTube Channel Link: 'Копіювати посилання на канал YouTube'\n  Open Channel in Invidious: 'Відкрити канал у Invidious'\n  Copy Invidious Channel Link: 'Копіювати посилання на канал Invidious'\n  Views: 'Перегляди'\n  Loop Playlist: 'Повторювати список відтворення'\n  Shuffle Playlist: 'Перемішати список відтворення'\n  Reverse Playlist: 'Зворотний напрямок списку відтворення'\n  Previous: 'Назад'\n  Next: 'Далі'\n  Watched: 'Переглянуто'\n  Autoplay: 'Автовідтворення'\n  Starting soon, please refresh the page to check again: 'Початок незабаром, оновіть сторінку, щоб перевірити ще раз'\n  # As in a Live Video\n  Live: 'Наживо'\n  Live Now: 'Зараз в етері'\n  Live Chat: 'Чат в режимі реального часу'\n  Enable Live Chat: 'Увімкнути чат у реальному часі'\n  Live Chat is currently not supported in this build.: 'Чат в режимі реального часу наразі не підтримується в цій збірці.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Чат увімкнено.  Повідомлення чату з''являться тут після надсилання.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Чат в режимі реального часу наразі не підтримується API Invidious.  Потрібне пряме з''єднання з YouTube.'\n  Published:\n    In less than a minute: Менше ніж за хвилину\n  Published on: 'Опубліковано'\n#& Videos\n  Started streaming on: Почато трансляцію\n  Streamed on: Потокове передавання\n  Video has been removed from your saved list: Відео вилучено зі списку збережених\n  Video has been saved: Відео збережено\n  Save Video: Зберегти відео\n  Sponsor Block category:\n    music offtopic: Музика поза темою\n    interaction: Взаємодія\n    self-promotion: Самореклама\n    outro: Кінцівка\n    intro: Вступ\n    sponsor: Спонсор\n    recap: Підсумок\n    filler: Заповнювач\n  External Player:\n    Unsupported Actions:\n      looping playlists: зациклювання добірок\n      shuffling playlists: перемішування добірок\n      reversing playlists: зміна добірок\n      opening specific video in a playlist (falling back to opening the video): відкриття певного відео у добірці (повернення до відкриття відео)\n      opening playlists: відкриття добірок\n      setting a playback rate: встановлення швидкості відтворення\n      starting video at offset: запуск відео зі зміщенням\n    UnsupportedActionTemplate: '{externalPlayer} не підтримує: {action}'\n    OpeningTemplate: Відкриття {videoOrPlaylist} у {externalPlayer}...\n    playlist: список відтворення\n    video: відео\n    OpenInTemplate: Відкрити у {externalPlayer}\n  Premieres: Прем'єри\n  Scroll to Bottom: Прокрутити до кінця\n  Show Super Chat Comment: Показати коментар із суперчату\n  Upcoming: Незабаром\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Спілкування наживо недоступне для цієї трансляції. Можливо, вивантажувач вимкнув його.\n  Unhide Channel: Показати канал\n  Hide Channel: Сховати канал\n  Player:\n    TranslatedCaptionTemplate: '{language} (перекладено з \"{originalLanguage}\")'\n    Stats:\n      Bandwidth: 'Пропускна здатність: {bandwidth} кбіт/с'\n      CodecsVideoAudio: 'Кодеки: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      Bitrate: 'Бітрейт: {bitrate} кбіт/с'\n      Volume: 'Гучність: {volumePercentage}%'\n      Buffered: 'Буферизація: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'Втрачені кадри: {droppedFrames} / Загальні кадри: {totalFrames}'\n      Player Dimensions: 'Розміри плеєра: {width}x{height}'\n      CodecAudio: 'Кодек: {audioCodec} ({audioItag})'\n      Stats: Статистика\n      Video ID: 'ID відео: {videoId}'\n      Media Formats: 'Медійні формати: {formats}'\n      Resolution: 'Роздільна здатність: {width}x{height}{''@''}{frameRate}'\n      CodecsVideoAudioNoItags: 'Кодеки: {videoCodec} / {audioCodec}'\n    Show Stats: Показати статистику\n    Full Window: Повний екран\n    Take Screenshot: Зробити скріншот\n    You appear to be offline: Виглядає, що ви не в мережі.\n    Playback will resume automatically when your connection comes back: Відтворення відновиться автоматично, коли ваше підключення відновиться.\n    Exit Theatre Mode: Вийти з режиму кінотеатру\n    Exit Full Window: Вийти з повного екрану\n    Audio Tracks: Аудіотреки\n    Theatre Mode: Режим кінотеатру\n    Hide Stats: Сховати статистику\n    Skipped segment: Пропущено сегмент {segmentCategory}\n    Autoplay is off: Автовідтворення вимкнено\n    Autoplay is on: Автовідтворення увімкнено\n  IP block: YouTube заблокував вашу IP-адресу для перегляду відео. Будь ласка, спробуйте змінити VPN або проксі.\n  Unlisted: Не в списку\n  AgeRestricted: Відео з віковими обмеженнями не можна переглядати за допомогою FreeTube, оскільки вони вимагають входу через Google та використання відео-аккаунту YouTube з підтвердженням віку.\n  More Options: Більше опцій\n  DeArrow:\n    Show Original Details: Показати оригінальні деталі\n    Show Modified Details: Показати змінені деталі\n  MembersOnly: Відео, доступні лише для учасників, не можна переглядати за допомогою FreeTube, оскільки вони вимагають входу через Google та платної підписки на канал завантажувача.\n  DRMProtected: Відео, захищені DRM, неможливо відтворити у FreeTube, оскільки для цього потрібні пропрієтарні компоненти з закритим вихідним кодом. Щоб переглянути це відео, скористайтеся офіційним сайтом YouTube у веб-браузері з підтримкою DRM.\n#& Playlists\n  Save Watched Progress: Зберегти переглянутий прогрес\n  Watched Progress Saved: Переглянутий прогрес збережено\nPlaylist:\n  #& About\n  View Full Playlist: 'Переглянути весь список відтворення'\n  Last Updated On: 'Востаннє оновлено'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Список відтворення\n  Sort By:\n    VideoDurationDescending: Тривалість (спочатку найдовші)\n    Custom: Користувацький\n    VideoTitleDescending: Заголовок (Я-А)\n    VideoTitleAscending: Заголовок (А-Я)\n    DateAddedOldest: Спочатку найстаріші добавлені\n    AuthorAscending: Автор (А-Я)\n    AuthorDescending: Автор (Я-А)\n    VideoDurationAscending: Тривалість (спочатку найкоротші)\n    DateAddedNewest: Спочатку новіші добавлені\n    PublishedNewest: Останні опубліковані першими\n    PublishedOldest: Найдавніші опубліковані першими\nChange Format:\n  Change Media Formats: 'Зміна форматів відео'\n  Use Dash Formats: 'Використовувати формати DASH'\n  Use Legacy Formats: 'Використовувати застарілі формати'\n  Use Audio Formats: 'Використовувати аудіоформати'\n  Dash formats are not available for this video: 'Формати DASH недоступні для цього відео'\n  Audio formats are not available for this video: 'Аудіоформати недоступні для цього відео'\n  Legacy formats are not available for this video: Застарілі формати недоступні для цього відео\nShare:\n  Share Video: 'Поділитися відео'\n  Share Playlist: 'Поділитися списком відтворення'\n  Include Timestamp: 'Включити позначку часу'\n  Copy Link: 'Копіювати посилання'\n  Open Link: 'Відкрити посилання'\n  Copy Embed: 'Копіювати вбудоване'\n  Open Embed: 'Відкрити вбудовуване'\n  # On Click\n  Invidious URL copied to clipboard: 'URL-адресу Invidious скопійовано в буфер обміну'\n  Invidious Embed URL copied to clipboard: 'URL-адресу вбудовування Invidious скопійовано до буфера обміну'\n  Invidious Channel URL copied to clipboard: 'URL-адресу каналу Invidious скопійовано в буфер обміну'\n  YouTube URL copied to clipboard: 'URL-адресу YouTube скопійовано до буфера обміну'\n  YouTube Embed URL copied to clipboard: 'URL-адресу вбудовування YouTube скопійовано до буфера обміну'\n  YouTube Channel URL copied to clipboard: 'URL-адресу каналу YouTube скопійовано до буфера обміну'\n\n  Share Channel: Поділитися каналом\nMini Player: 'Мініпрогравач'\nComments:\n  Comments: 'Коментарі'\n  Click to View Comments: 'Клацніть, щоб переглянути коментарі'\n  Getting comment replies, please wait: 'Отримання відповідей на коментарі, зачекайте'\n  There are no more comments for this video: 'Більше немає коментарів до цього відео'\n  Hide Comments: 'Сховати коментарі'\n  Top comments: 'Найпопулярніші коментарі'\n  Newest first: 'Спочатку новіші'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Немає коментарів до цього відео'\n  Load More Comments: 'Завантажити більше коментарів'\n  Show More Replies: Показати інші відповіді\n  Pinned by: Закріплено\n  Member: Учасник\n  Hearted: З сердечком\n  View {replyCount} replies: Переглянути {replyCount} відповідей\n  Subscribed: Слідкують\n  There are no comments available for this post: Коментарі для цього поста відсутні\nUp Next: 'Далі'\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: 'Виберіть сервер, який FreeTube використовує для отримання даних. Локальний API є вбудованим видобувачем. Для API Invidious потрібен сервер Invidious для з'' єднання.'\n    Fallback to Non-Preferred Backend on Failure: 'Коли бажаний API має проблеми, FreeTube автоматично спробує використовувати ваш не вибраний API як запасний метод, коли його увімкнено.'\n    Thumbnail Preference: 'Усі ескізи у FreeTube будуть замінені на кадр з відео, розмитий або схований замість стандартного ескізу.'\n    Invidious Instance: 'Сервер Invidious, до якого FreeTube під''єднуватиметься для викликів API.'\n    Region for Trending: 'Регіон популярного дозволяє вам вибрати популярні відео країни, які ви хочете бачити.'\n    External Link Handling: \"Визначте типову поведінку, коли натиснено на посилання, яке не можна відкрити у FreeTube.\\nТипово FreeTube відкриває натиснуте посилання у вашому типовому переглядачі.\\n\"\n    Open Deep Links In New Window: URL-адреси, передані в FreeTube, наприклад через розширення для браузера або аргументи командного рядка, відкриваються в новому вікні.\n  Player Settings:\n    Proxy Videos Through Invidious: 'Під’єднається до Invidious, щоб дивитися відео, а не встановлювати пряме з’єднання з YouTube.'\n    Default Video Format: 'Встановіть формати, що використовуються при відтворенні відео. Формати DASH підтримують вищі якості. Старі формати обмежені максимальним роздільною здатністю 360p, але використовують менше пропускної здатності. Аудіоформати — це потоки тільки з аудіо.'\n    Scroll Playback Rate Over Video Player: Поки курсор знаходиться над відео, натисніть і утримуйте клавішу Control (клавіша Command на Mac) і прокрутіть коліщатко миші вперед або назад, щоб контролювати швидкість відтворення. Натисніть і утримуйте клавішу Control (клавіша Command на Mac) і клацніть лівою кнопкою миші, щоб швидко повернутися до типової швидкості відтворення (1x, якщо вона не була змінена в налаштуваннях).\n    Skip by Scrolling Over Video Player: Використовувати колесо прокрутки для прокручування відео в стилі MPV.\n  Subscription Settings:\n    Fetch Feeds from RSS: 'При увімкненні, FreeTube використовуватиме RSS замість стандартного методу для отримання вашого фіду підписок. RSS є швидшим і запобігає блокуванню IP-адрес, але не надає певну інформацію, таку як тривалість відео, статус в прямому ефірі або пости'\n\n# Toast Messages\n    Fetch Automatically: При увімкненні, FreeTube автоматично завантажуватиме фід ваших підписок під час запуску та коли відкривається нове вікно.\n  External Player Settings:\n    Custom External Player Arguments: Будь-які користувацькі аргументи командного рядка, які ви хочете передати зовнішньому плеєру.\n    Ignore Warnings: Заборонити попередження, якщо поточний зовнішній програвач не підтримує поточну дію (наприклад, зворотна почерговість відтворення добірок тощо).\n    Custom External Player Executable: Усталено FreeTube вважатиме, що вибраний зовнішній програвач можна знайти за допомогою змінної середовища PATH. Якщо потрібно, тут можна призначити нетиповий шлях.\n    External Player: Якщо обрано зовнішній програвач, з'явиться піктограма для відкриття відео (список відтворення, якщо підтримується) у зовнішньому програвачі, на мініатюрі. Увага, налаштування Invidious не застосовуються до сторонніх програвачів.\n    DefaultCustomArgumentsTemplate: \"(Типово: '{defaultCustomArguments}')\"\n    Ignore Default Arguments: Не надсилати жодних стандартних аргументів зовнішньому плеєру, окрім URL-адреси відео (наприклад, швидкість відтворення, URL-адреса добірки тощо). Користувацькі аргументи все одно будуть передаватися.\n  Experimental Settings:\n    Replace HTTP Cache: Вимикає дисковий HTTP-кеш Electron і вмикає власний кеш зображень у пам'яті. Призведе до збільшення використання оперативної пам'яті.\n  Distraction Free Settings:\n    Hide Channels: Введіть ID, щоб сховати всі відео, добірки та сам канал від появи в пошуку, тренді, найпопулярніших і рекомендованих. Введений ID каналу повинен повністю збігатися і чутливий до регістру.\n    Hide Subscriptions Live: Цей параметр перевизначається загальнодоступним налаштуванням \"{appWideSetting}\" у розділі \"{subsection}\" \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Введіть слово, фрагмент слова або фразу (незалежно від регістру), щоб приховати всі відео та добірки, у заголовках яких вона міститься, по всьому FreeTube, за винятком Історії, Ваших Добірок і відео в межах добірок.\n    Hide Videos on Watch: Приховує переглянуті відео з вкладок Відео,Shorts, та Наживо на сторінках підписок та каналу. Це не впливає на Домашню вкладку сторінок каналів\n  SponsorBlock Settings:\n    UseDeArrowTitles: Замінити назви відео на надіслані користувачем назви з DeArrow.\n    UseDeArrowThumbnails: Замінити ескізи відео на ескізи з DeArrow.\nLocal API Error (Click to copy): 'Помилка локального API (натисніть, щоб скопіювати)'\nInvidious API Error (Click to copy): 'Помилка Invidious API (натисніть, щоб скопіювати)'\nFalling back to Invidious API: 'Повернення до API Invidious'\nFalling back to Local API: 'Повернення до локального API'\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'Це відео недоступне через відсутність форматів. Це може статися через недоступність країни.'\nLoop is now disabled: 'Цикл вимкнено'\nLoop is now enabled: 'Цикл увімкнено'\nShuffle is now disabled: 'Випадковий порядок вимкнено'\nShuffle is now enabled: 'Випадковий порядок увімкнено'\nThe playlist has been reversed: 'Список відтворення обернено'\nPlaying Next Video: 'Відтворення наступного відео'\nPlaying Previous Video: 'Відтворення попереднього відео'\nCanceled next video autoplay: 'Скасовано автовідтворення наступного відео'\n'The playlist has ended. Enable loop to continue playing': 'Список відтворення завершився. Увімкніть повторення, щоб продовжити відтворення'\n\nYes: 'Так'\nNo: 'Ні'\nPlaying Next Video Interval: Відтворення наступного відео в будь-який час. Клацніть, щоб скасувати. | Відтворення наступного відео через {nextVideoInterval} секунду. Клацніть, щоб скасувати. | Відтворення наступного відео через {nextVideoInterval} секунд. Клацніть, щоб скасувати.\nMore: Докладніше\nUnknown YouTube url type, cannot be opened in app: Невідомий тип URL-адреси YouTube, його не можна відкрити в застосункові\nOpen New Window: Відкрити нове вікно\nDefault Invidious instance has been cleared: Типовий екземпляр Invidious очищено\nDefault Invidious instance has been set to {instance}: 'Типовим екземпляром Invidious встановлено {instance}'\nSearch Bar:\n  Clear Input: Очистити поле\n  Remove: Видалити\nExternal link opening has been disabled in the general settings: Відкриття зовнішнього посилання вимкнено в загальних налаштуваннях\nAre you sure you want to open this link?: Ви впевнені, що хочете відкрити це посилання?\nScreenshot Success: Збережений знімок екрана\nScreenshot Error: Не вдалося зробити знімок екрана. {error}\nNew Window: Нове вікно\nChannels:\n  Count: 'Знайдено каналів: {number}.'\n  Empty: Ваш список каналів наразі порожній.\n  Unsubscribe Prompt: Ви впевнені, що хочете відписатися від «{channelName}»?\n  Channels: Канали\n  Title: Список каналів\n  Search bar placeholder: Пошук каналів\nClipboard:\n  Copy failed: Не вдалося скопіювати до буфера обміну\n  Cannot access clipboard without a secure connection: Неможливо отримати доступ до буфера обміну без захищеного з'єднання\nChapters:\n  Chapters: Розділи\n  Key Moments: Ключові моменти\nPreferences: Налаштування\nOk: Гаразд\nHashtag:\n  Hashtag: Хештег\n  This hashtag does not currently have any videos: За цим хештегом наразі немає відео\nChannel Hidden: '{channel} додано до фільтра каналу'\nGo to page: Перейти до {page}\nChannel Unhidden: '{channel} вилучено з фільтра каналу'\nClose Banner: Закрити банер\nSearch character limit: Запит перевищує ліміт у {searchCharacterLimit} символів\nFeed:\n  Refresh Feed: Оновити {subscriptionName}\n  Feed Last Updated: 'Останнє оновлення фіда {feedName}: {date}'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Субтитри\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Новинка\n    3D: 3D\n    Closed Captions: Закриті субтитри\nRight-click or hold to see history: ПКМ або утримуйте для перегляду історії\nDisplay Label: '{label}: {value}'\nTag already exists: Тег \"{tagName}\" вже існує\nshortcutJoinOperator: +\nKeys:\n  arrowright: Стрілка вправо\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Стрілка вниз\n  arrowleft: Стрілка вліво\n  arrowup: Стрілка вгору\n  shift: Shift\n  enter: Enter\n  plus: Плюс\ncheckmark: ✓\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nAge Restricted:\n  This channel is age restricted: Цей канал має вікові обмеження\n  This video is age restricted: Це відео має вікові обмеження\nTrimmed input must be at least N characters long: Обрізаний ввід повинен бути хоча б 1 символ довжиною | Обрізаний ввід повинен бути хоча б {length} символів довжиною\nMoments Ago: щойно\nYes, Restart: Так, перезапустити\nYes, Open Link: Так, відкрити посилання\nYes, Delete: Так, видалити\nCancel: Скасувати\nAutoplay Interruption Timer: Автозапуск скасовано через {autoplayInterruptionIntervalHours} годин бездіяльності\nDescription:\n  Expand Description: '...докладніше'\n  Collapse Description: Показати менше\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: Гарячі клавіші\n  Sections:\n    Video:\n      Playback: 'Відео: Відтворення'\n      General: 'Відео: Загальні'\n    App:\n      Situational: 'Додаток: Ситуаційне'\n      General: 'Додаток: Загальне'\n  Show Keyboard Shortcuts: Показати клавіатурні скорочення\n  History Backward: Повернутися на одну сторінку назад\n  History Forward: Перейти на одну сторінку вперед\n  Navigate to Settings: Перейти до сторінки налаштувань\n  Navigate to History: Перейти на сторінку Історії\n  Focus Secondary Search: Зосередитись на вторинній панелі пошуку (якщо вона є)\n  Captions: Перемикати субтитри УВІМК/ВИМК\n  Stats: Показати статистику відео\n  Fullscreen: Перемкнути на повний екран\n  Picture in Picture: Перемкнути режим \"Картинка в картинці\"\n  Large Rewind: Перемотати на 10 секунд / Перемотати відео в залежності від поточної швидкості відтворення\n  Play: Перемикання відтворення/паузи\n  Mute: Перемкнути беззвучний режим\n  Increase Video Speed: Збільшити швидкість відео відповідно до інтервалу швидкості відтворення відео\n  Full Window: Переключити на повний екран\n  Take Screenshot: Зробити скріншот\n  Minimize Window: Згорнути вікно\n  Close Window: Закрити вікно\n  Refresh: Оновити стрічку з останнім вмістом\n  Large Fast Forward: Перемотати вперед на 10 секунд / Швидка перемотка відео відповідно до поточної швидкості відтворення\n  Decrease Video Speed: Зменшити швидкість відео відповідно до інтервалу швидкості відтворення відео\n  New Window: Створити нове вікно\n  Theatre Mode: Переключити на театральний режим\n  Toggle Developer Tools: Перемикнути інструменти розробника\n  Reset Zoom: Скинути рівень масштабування / шкалу інтерфейсу\n  Zoom In: Масштабувати вперед\n  Zoom Out: Масштабувати назад\n  Focus Search: Зосередитися на рядку пошуку\n  Search in New Window: Пошук у новому вікні\n  Last Frame: Попередній кадр (під час паузи)\n  Next Frame: Наступний кадр (під час паузи)\n  Volume Up: Збільшити гучність\n  Volume Down: Зменшити гучність\n  Small Rewind: Перемотати на X секунд згідно з інтервалом перемотування та поточним коефіцієнтом відтворення відео\n  Small Fast Forward: Перемотати вперед на X секунд згідно з інтервалом перемотування вперед та поточним коефіцієнтом відтворення відео\n  Last Chapter: Останній розділ\n  Skip by Tenths: Пропустити відео на певний відсоток (3 пропуски до 30% тривалості)\n  Next Chapter: Наступний розділ\n  End: Перемотати вкінець відео\n  Skip to Next Video: Перейти до наступного відео у списку відтворення або до наступного рекомендованого відео\n  Skip to Previous Video: Пеерейти до минулого відео у списку відтворенн\nshortcutLabelSeparator: ｜\n"
  },
  {
    "path": "static/locales/ur.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'اردو'\n\n# Webkit Menu Bar\nFile: 'فائل'\nNew Window: 'نئی ونڈو'\nQuit: 'چھوڑیں'\nEdit: 'ترمیم'\nUndo: 'پہلے جیسا کریں'\nRedo: 'دوبارہ کریں'\nCut: 'کاٹنا'\nCopy: 'کاپی'\nPaste: 'چسپاں کریں'\nDelete: 'ڈیلیٹ کریں'\nSelect all: 'تمام منتخب کریں'\nToggle Developer Tools: 'ڈویلپر ٹولز کو ٹوگل کریں'\nActual size: 'اصل سائز'\nZoom in: 'زوم ان'\nZoom out: 'زوم آؤٹ'\nToggle fullscreen: 'فُل اسکرین کو ٹوگل کریں'\nWindow: 'ونڈو'\nMinimize: 'چھوٹا کریں'\nClose: 'بند کریں'\nBack: 'پیچھے'\nForward: 'آگے'\nOpen New Window: 'نئی ونڈو کھولیں'\n\nDownload From Site: 'سائٹ سے ڈاؤن لوڈ کریں'\nA new blog is now available, {blogTitle}. Click to view more: 'ایک نیا بلاگ اب دستیاب ہے، {blogTitle}. مزید دیکھنے کے لیے کلک کریں'\nAre you sure you want to open this link?: 'کیا واقعی آپ اس لنک کو کھولنا چاہتے ہیں؟'\n\n# Search Bar\nSearch / Go to URL: 'تلاش کریں / یو آر ایل پر جائیں'\nSearch Bar:\n  Clear Input: 'ان پٹ صاف کریں'\n  # In Filter Button\n  Remove: ہٹائیں\nSearch Filters:\n  Search Filters: 'تلاش کے فلٹرز'\n  There are no more results for this search: 'اس تلاش کے مزید نتائج نہیں ہیں'\n# Sidebar\n  Type:\n    Videos: ویڈیوز\n    Type: قسم\n    All Types: تمام اقسام\n    Channels: چینلز\n    Movies: فلمیں\n  Sort By:\n    Most Relevant: موزوں ترین\n    Rating: ریٹنگ\n    Upload Date: اپ لوڈ کی تاریخ\n    View Count: ویوز کی تعداد\n  Time:\n    Time: وقت\n    Any Time: کسی بھی وقت\n    Last Hour: پچھلا گھنٹہ\n    Today: آج\n    This Week: اس ہفتے\n    This Month: اس مہینے\n    This Year: اس سال\n  Duration:\n    Duration: دورانیہ\n    All Durations: تمام دورانیے\n    Short (< 4 minutes): مختصر (< 4 منٹ)\n    Medium (4 - 20 minutes): درمیانہ (4 - 20 منٹ)\n    Long (> 20 minutes): طویل (> 20 منٹ)\n  Features:\n    Features: فیچرز\n    HD: HD\n    Subtitles: سب ٹائٹلز\n    Creative Commons: کریئیٹیو کامنز\n    3D: 3D\n    Live: لائیو\n    4K: 4K\n    360 Video: 360 ویڈیو\n    Location: مقام\n    HDR: HDR\n    VR180: VR180\n  Search Results: سرچ کے نتائج\n  Fetching results. Please wait: نتائج حاصل کیے جا رہے ہیں۔ براہ کرم انتظار کریں\n  Fetch more results: مزید نتائج حاصل کریں\n  Clear Filters: فلٹرز ختم کریں\nSubscriptions:\n    # On Subscriptions Page\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 'یہ پروفائل میں سبسکرپشنز کی ایک بڑی تعداد ہے۔ . .شرح کو محدود کرنے سے بچنے کے لیے RSS کو مجبور کر رہے ہیں'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'آپ کی سبسکرپشن کی فہرست فی الحال خالی ہے۔ اگر آپ اپنی سبسکرپشنز امپورٹ کرنا چاہتے ہیں تو آپ ڈیٹا سیٹنگز میں جا کر امپورٹ سبسکرپشنز کو منتخب کر سکتے ہیں یا آپ کوئی چینل تلاش کر کے سبسکرائب کر سکتے ہیں۔'\n  Load More Videos: 'مزید ویڈیوز لوڈ کریں'\n  Subscriptions: سبسکرپشنز\n  Error Channels: ایرر والے چینلز\n  Disabled Automatic Fetching: آپ نے خودکار سبسکرپشن حاصل کرنا غیر فعال کر دیا ہے۔ انہیں یہاں دیکھنے کے لیے سبسکرپشنز ریفریش کریں۔\n  Empty Channels: آپ کے سبسکرائب کردہ چینلز پر فی الحال کوئی ویڈیو نہیں ہے۔\n  Empty Posts: آپ کے سبسکرائب کردہ چینلز پر فی الحال کوئی پوسٹ نہیں ہے۔\n  Load More Posts: مزید پوسٹس لوڈ کریں\n  Subscriptions Tabs: سبسکرپشن ٹیبز\n  All Subscription Tabs Hidden: سبسکرپشن کے تمام ٹیبز پوشیدہ ہیں۔ یہاں مواد دیکھنے کے لیے، براہ کرم \"{settingsSection}\" میں \"{subsection}\" سیکشن کے کچھ ٹیبز کو ظاہر کریں۔\nMore: 'مزید'\nChannels:\n  Channels: 'چینلز'\n  Title: 'چینل کی فہرست'\n  Search bar placeholder: 'چینلز تلاش کریں'\n  Count: '{number} چینل(ز) ملا/ملے۔'\n  Empty: 'آپ کے چینل کی فہرست فی الحال خالی ہے۔'\n  Unsubscribe Prompt: کیا آپ واقعی \"{channelName}\" سے ان سبسکرائب کرنا چاہتے ہیں؟\nUser Playlists:\n  Empty Search Message: 'اس پلے لسٹ میں کوئی ایسی ویڈیوز نہیں ہیں جو آپ کی تلاش سے مماثل ہوں'\n  Search bar placeholder: 'پلے لسٹ کی تلاش'\n  Your Playlists: آپ کی پلے لسٹس\n  You have no playlists. Click on the create new playlist button to create a new one.: آپ کی کوئی پلے لسٹ نہیں ہے۔ نئی پلے لسٹ بنانے کے لیے بٹن پر کلک کریں۔\n  Playlists with Matching Videos: ملتی جلتی ویڈیوز والی پلے لسٹس\n  This playlist currently has no videos.: اس پلے لسٹ میں فی الحال کوئی ویڈیو نہیں ہے۔\n  Create New Playlist: نئی پلے لسٹ بنائیں\n  Add to Playlist: پلے لسٹ میں شامل کریں\n  Add to Favorites: '{playlistName} میں شامل کریں'\n  Remove from Favorites: '{playlistName} سے ہٹائیں'\n  Move Video Up: ویڈیو اوپر لے جائیں\n  Move Video Down: ویڈیو نیچے لے جائیں\n  Remove from Playlist: پلے لسٹ سے ہٹائیں\n  Playlist Name: پلے لسٹ کا نام\n  Playlist Description: پلے لسٹ کی تفصیل\n  Save Changes: تبدیلیاں محفوظ کریں\n  Cancel: منسوخ کریں\n  Edit Playlist Info: پلے لسٹ کی معلومات ایڈٹ کریں\n  Copy Playlist: پلے لسٹ کاپی کریں\n  Remove Duplicate Videos: ڈوپلیکیٹ ویڈیوز ہٹائیں\n  Remove Watched Videos: دیکھی گئی ویڈیوز ہٹائیں\n  Enable Quick Bookmark With This Playlist: اس پلے لسٹ کے ساتھ فوری بک مارک فعال کریں\n  Quick Bookmark Enabled: فوری بک مارک فعال ہے\n  Export Playlist: یہ پلے لسٹ ایکسپورٹ کریں\n  Export list of URLs: URLs کی فہرست ایکسپورٹ کریں\n  The playlist has been successfully exported: پلے لسٹ کامیابی کے ساتھ ایکسپورٹ کر دی گئی ہے\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: کیا آپ واقعی اس پلے لسٹ سے 1 ڈوپلیکیٹ ویڈیو ہٹانا چاہتے ہیں؟ اسے واپس نہیں لیا جا سکے گا۔ | کیا آپ واقعی اس پلے لسٹ سے {playlistItemCount} ڈوپلیکیٹ ویڈیوز ہٹانا چاہتے ہیں؟ اسے واپس نہیں لیا جا سکے گا۔\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: کیا آپ واقعی اس پلے لسٹ سے 1 دیکھی گئی ویڈیو ہٹانا چاہتے ہیں؟ اسے واپس نہیں لیا جا سکے گا۔ | کیا آپ واقعی اس پلے لسٹ سے {playlistItemCount} دیکھی گئی ویڈیوز ہٹانا چاہتے ہیں؟ اسے واپس نہیں لیا جا سکے گا۔\n  Delete Playlist: پلے لسٹ حذف کریں\n  Cannot delete the quick bookmark target playlist.: فوری بک مارک والی پلے لسٹ کو حذف نہیں کیا جا سکتا۔\n  Are you sure you want to delete this playlist? This cannot be undone: کیا آپ واقعی یہ پلے لسٹ حذف کرنا چاہتے ہیں؟ یہ عمل واپس نہیں لیا جا سکے گا۔\n  TotalTimePlaylist: 'کل وقت: {duration}'\n  Sort By:\n    NameAscending: A سے Z\n    NameDescending: Z سے A\n    LatestCreatedFirst: تخلیق کی تاریخ (جدید ترین)\n    EarliestCreatedFirst: تخلیق کی تاریخ (قدیم ترین)\n    LatestUpdatedFirst: اپ ڈیٹ کی تاریخ (جدید ترین)\n    EarliestUpdatedFirst: اپ ڈیٹ کی تاریخ (قدیم ترین)\n    LatestPlayedFirst: چلانے کی تاریخ (جدید ترین)\n    EarliestPlayedFirst: چلانے کی تاریخ (قدیم ترین)\n  SinglePlaylistView:\n    Search for Videos: ویڈیوز تلاش کریں\n    Toast:\n      This video cannot be moved up.: اس ویڈیو کو اوپر نہیں لایا جا سکتا۔\n      This video cannot be moved down.: اس ویڈیو کو نیچے نہیں لے جایا جا سکتا۔\n      Video has been removed: ویڈیو ہٹا دی گئی ہے\n      Video has been removed. Click here to undo.: ویڈیو ہٹا دی گئی ہے۔ واپس لانے کے لیے یہاں کلک کریں۔\n      There was a problem with removing this video: اس ویڈیو کو ہٹانے میں مسئلہ پیش آیا\n      This playlist is already being used for quick bookmark.: یہ پلے لسٹ پہلے ہی فوری بک مارک کے لیے استعمال ہو رہی ہے۔\n      This playlist is now used for quick bookmark: یہ پلے لسٹ اب فوری بک مارک کے لیے استعمال ہوگی\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: یہ پلے لسٹ اب {oldPlaylistName} کے بجائے فوری بک مارک کے لیے استعمال ہوگی۔ واپس لانے کے لیے یہاں کلک کریں\n      Reverted to use {oldPlaylistName} for quick bookmark: دوبارہ {oldPlaylistName} کو فوری بک مارک کے لیے سیٹ کر دیا گیا ہے\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: پلے لسٹ کی کچھ ویڈیوز ابھی لوڈ نہیں ہوئی ہیں۔ بہر حال کاپی کرنے کے لیے یہاں کلک کریں۔\n      Playlist name cannot be empty. Please input a name.: پلے لسٹ کا نام خالی نہیں ہو سکتا۔ براہ کرم ایک نام درج کریں۔\n      Playlist has been updated.: پلے لسٹ اپ ڈیٹ ہو گئی ہے۔\n      There was an issue with updating this playlist.: اس پلے لسٹ کو اپ ڈیٹ کرنے میں مسئلہ پیش آیا۔\n      \"{videoCount} video(s) have been removed\": 1 ویڈیو ہٹا دی گئی ہے | {videoCount} ویڈیوز ہٹا دی گئی ہیں\n      There were no videos to remove.: ہٹانے کے لیے کوئی ویڈیو نہیں تھی۔\n      This playlist is protected and cannot be removed.: یہ پلے لسٹ محفوظ ہے اور اسے ہٹایا نہیں جا سکتا۔\n      Playlist {playlistName} has been deleted.: پلے لسٹ {playlistName} حذف کر دی گئی ہے۔\n      This playlist does not exist: یہ پلے لسٹ موجود نہیں ہے\n      This playlist has a video with a duration error: اس پلے لسٹ میں کم از کم ایک ایسی ویڈیو ہے جس کا دورانیہ معلوم نہیں ہے، اسے اس طرح ترتیب دیا جائے گا جیسے اس کا دورانیہ صفر ہو۔\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: اپنی ویڈیو شامل کرنے کے لیے پلے لسٹ منتخب کریں | اپنی {videoCount} ویڈیوز شامل کرنے کے لیے پلے لسٹ منتخب کریں\n    N playlists selected: '{playlistCount} منتخب شدہ'\n    Search in Playlists: پلے لسٹس میں تلاش کریں\n    Allow Adding Duplicate Video(s): ڈوپلیکیٹ ویڈیوز شامل کرنے کی اجازت دیں\n    Save: محفوظ کریں\n    Added {count} Times: پہلے ہی شامل ہے | {count} بار شامل کی گئی\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} ویڈیوز شامل کی جائیں گی'\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} ویڈیوز پہلے ہی شامل ہیں'\n    Toast:\n      You haven't selected any playlist yet.: آپ نے ابھی تک کوئی پلے لسٹ منتخب نہیں کی ہے۔\n      \"Video(s) added to {playlistCount} playlists\": ویڈیو(ز) 1 پلے لسٹ میں شامل کر دی گئیں | ویڈیو(ز) {playlistCount} پلے لسٹس میں شامل کر دی گئیں\n  CreatePlaylistPrompt:\n    New Playlist Name: نئی پلے لسٹ کا نام\n    Create: بنائیں\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: اس نام سے پہلے ہی ایک پلے لسٹ موجود ہے۔ براہ کرم کوئی دوسرا نام منتخب کریں۔\n      Playlist {playlistName} has been successfully created.: پلے لسٹ {playlistName} کامیابی کے ساتھ بنا لی گئی ہے۔\n      There was an issue with creating the playlist.: پلے لسٹ بنانے میں مسئلہ پیش آیا۔\nHistory:\n  # On History Page\n  History: 'تاریخ'\n  Watch History: 'تاریخ دیکھیں'\n  Your history list is currently empty.: 'آپ کی تاریخ کی فہرست فی الحال خالی ہے۔'\n  Empty Search Message: 'آپ کی سرگزشت میں کوئی ایسی ویڈیوز نہیں ہیں جو آپ کی تلاش سے مماثل ہوں'\n  Search bar placeholder: \"سرگزشت میں تلاش کریں\"\n  Case Sensitive Search: حروف کی حساسیت کے ساتھ تلاش\n  DateOldestHistory: دیکھنے کی تاریخ (قدیم ترین)\n  DateNewestHistory: دیکھنے کی تاریخ (جدید ترین)\nSettings:\n  # On Settings Page\n  The app needs to restart for changes to take effect. Restart and apply change?: 'دی تبدیلیاں اثر انداز ہونے کے لیے ایپ کو دوبارہ شروع کرنے کی ضرورت ہے۔ دوبارہ شروع کریں اور تبدیلی کا اطلاق کریں؟'\n  General Settings:\n    General Settings: 'عام'\n    Check for Updates: 'اپ ڈیٹ کے لیے چیک کریں'\n    Check for Latest Blog Posts: 'تازہ ترین بلاگ پوسٹس چیک کریں'\n    Fallback to Non-Preferred Backend on Failure: 'غیر ترجیحی بیک اینڈ پر فال بیک ناکامی پر'\n    Enable Search Suggestions: 'تلاش کی تجاویز کو فعال کریں'\n    Default Landing Page: 'ڈیفالٹ لینڈنگ پیج'\n    Open Deep Links In New Window: فری ٹیوب کو دیے گئے یو آر ایل کو نئی ونڈو میں کھولیں\n    Minimize to system tray: سسٹم ٹرے میں چھوٹا کریں\n    Auto Load Next Page:\n      Label: اگلا صفحہ خود بخود لوڈ کریں\n      Tooltip: اضافی صفحات اور کمنٹس خود بخود لوڈ کریں۔\n    Locale Preference: علاقائی ترجیح (Locale)\n    System Default: سسٹم ڈیفالٹ\n    Preferred API Backend:\n      Preferred API Backend: ترجیحی API بیک اینڈ\n      Local API: لوکل API\n      Invidious API: انویڈیئس API\n    Video View Type:\n      Video View Type: ویڈیو دیکھنے کی قسم\n      Grid: گرڈ\n      List: فہرست\n    Thumbnail Preference:\n      Thumbnail Preference: تھمب نیل کی ترجیح\n      Default: ڈیفالٹ\n      Beginning: آغاز\n      Middle: درمیان\n      End: آخر\n      Hidden: پوشیدہ\n      Blur: دھندلا\n    Current Invidious Instance: موجودہ انویڈیئس انسٹنس\n    The currently set default instance is {instance}: فی الحال سیٹ کردہ ڈیفالٹ انسٹنس {instance} ہے\n    No default instance has been set: کوئی ڈیفالٹ انسٹنس سیٹ نہیں کیا گیا\n    Current instance will be randomized on startup: شروعات پر موجودہ انسٹنس بے ترتیب طور پر منتخب کیا جائے گا\n    Set Current Instance as Default: موجودہ انسٹنس کو ڈیفالٹ کے طور پر سیٹ کریں\n    Clear Default Instance: ڈیفالٹ انسٹنس ختم کریں\n    View all Invidious instance information: تمام انویڈیئس انسٹنس کی معلومات دیکھیں\n    Region for Trending: ٹرینڈنگ کے لیے خطہ\n    External Link Handling:\n      External Link Handling: بیرونی لنکس کا طریقہ کار\n      Open Link: لنک کھولیں\n      Ask Before Opening Link: لنک کھولنے سے پہلے پوچھیں\n      No Action: کوئی کارروائی نہیں\n  Theme Settings:\n    Theme Settings: تھیم\n    Match Top Bar with Main Color: اوپری بار کو مین کلر سے ملائیں\n    Expand Side Bar by Default: سائیڈ بار کو ڈیفالٹ کے طور پر پھیلائیں\n    Disable Smooth Scrolling: اسموتھ اسکرولنگ غیر فعال کریں\n    UI Scale: انٹرفیس (UI) کا اسکیل\n    Hide Side Bar Labels: سائیڈ بار کے لیبلز چھپائیں\n    Hide FreeTube Header Logo: فری ٹیوب ہیڈر لوگو چھپائیں\n    Base Theme:\n      Base Theme: بنیادی تھیم\n      Black: کالا\n      Dark: ڈارک\n      System Default: سسٹم ڈیفالٹ\n      Light: لائٹ\n      Dracula: Dracula\n      Catppuccin Frappe: Catppuccin Frappe\n      Catppuccin Latte: Catppuccin Latte\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: پیسٹل پنک\n      Hot Pink: ہاٹ پنک\n      Nordic: Nordic\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Light\n      Solarized Dark: Solarized Dark\n      Solarized Light: Solarized Light\n      Everforest Dark Hard: Everforest Dark Hard\n      Everforest Dark Medium: Everforest Dark Medium\n      Everforest Dark Low: Everforest Dark Low\n      Everforest Light Hard: Everforest Light Hard\n      Everforest Light Medium: Everforest Light Medium\n      Everforest Light Low: Everforest Light Low\n    Main Color Theme:\n      Main Color Theme: مین کلر تھیم\n      Red: سرخ\n      Pink: گلابی\n      Purple: ارغوانی\n      Deep Purple: گہرا ارغوانی\n      Indigo: انڈیگو\n      Blue: نیلا\n      Light Blue: ہلکا نیلا\n      Cyan: سیان\n      Teal: ٹیل\n      Green: سبز\n      Light Green: ہلکا سبز\n      Lime: لائم\n      Yellow: پیلا\n      Amber: ایمبر\n      Orange: نارنجی\n      Deep Orange: گہرا نارنجی\n      Dracula Cyan: Dracula Cyan\n      Dracula Green: Dracula Green\n      Dracula Orange: Dracula Orange\n      Dracula Pink: Dracula Pink\n      Dracula Purple: Dracula Purple\n      Dracula Red: Dracula Red\n      Dracula Yellow: Dracula Yellow\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Red\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maroon\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow\n      Catppuccin Frappe Green: Catppuccin Frappe Green\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Sky: Catppuccin Frappe Sky\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Sapphire\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve\n      Catppuccin Mocha Red: Catppuccin Mocha Red\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow\n      Catppuccin Mocha Green: Catppuccin Mocha Green\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender\n      Gruvbox Dark Green: Gruvbox Dark Green\n      Gruvbox Dark Yellow: Gruvbox Dark Yellow\n      Gruvbox Dark Blue: Gruvbox Dark Blue\n      Gruvbox Dark Purple: Gruvbox Dark Purple\n      Gruvbox Dark Aqua: Gruvbox Dark Aqua\n      Gruvbox Dark Orange: Gruvbox Dark Orange\n      Gruvbox Light Red: Gruvbox Light Red\n      Gruvbox Light Blue: Gruvbox Light Blue\n      Gruvbox Light Purple: Gruvbox Light Purple\n      Gruvbox Light Orange: Gruvbox Light Orange\n      Solarized Yellow: Solarized Yellow\n      Solarized Orange: Solarized Orange\n      Solarized Red: Solarized Red\n      Solarized Magenta: Solarized Magenta\n      Solarized Violet: Solarized Violet\n      Solarized Blue: Solarized Blue\n      Solarized Cyan: Solarized Cyan\n      Solarized Green: Solarized Green\n      Everforest Dark Red: Everforest Dark Red\n      Everforest Dark Orange: Everforest Dark Orange\n      Everforest Dark Yellow: Everforest Dark Yellow\n      Everforest Dark Green: Everforest Dark Green\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Dark Blue\n      Everforest Dark Purple: Everforest Dark Purple\n      Everforest Light Red: Everforest Light Red\n      Everforest Light Orange: Everforest Light Orange\n      Everforest Light Yellow: Everforest Light Yellow\n      Everforest Light Green: Everforest Light Green\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Light Blue: Everforest Light Blue\n      Everforest Light Purple: Everforest Light Purple\n    Secondary Color Theme: ثانوی کلر تھیم\n  Player Settings:\n    Screenshot:\n      File Name Tooltip: 'آپ ذیل میں متغیرات استعمال کر سکتے ہیں۔ %Y سال کے 4 ہندسے۔ %M مہینہ 2 ہندسے۔ %D دن کے 2 ہندسے۔ %H گھنٹے 2 ہندسے۔ %N منٹ 2 ہندسے۔ %S دوسرے 2 ہندسے۔ %T ملی سیکنڈ 3 ہندسے۔ %s ویڈیو سیکنڈ۔ %t ویڈیو ملی سیکنڈ 3 ہندسے۔ %i ویڈیو ID۔ آپ ذیلی فولڈر بنانے کے لیے \"\\\" یا \"/\" بھی استعمال کر سکتے ہیں۔'\n      Enable: اسکرین شاٹ فعال کریں\n      Format Label: اسکرین شاٹ فارمیٹ\n      Quality Label: اسکرین شاٹ کوالٹی\n      Ask Path: محفوظ کرنے کے لیے فولڈر کا پوچھیں\n      Folder Label: اسکرین شاٹ فولڈر\n      Folder Button: فولڈر منتخب کریں\n      File Name Label: فائل کا نام رکھنے کا انداز\n      Error:\n        Forbidden Characters: ممنوعہ حروف\n        Empty File Name: خالی فائل کا نام\n    Player Settings: پلیئر\n    Play Next Video: تجویز کردہ ویڈیوز خود بخود چلائیں\n    Autoplay Playlists: پلے لسٹ ویڈیوز خود بخود چلائیں\n    Autoplay Videos: ویڈیوز خود بخود شروع کریں\n    Turn on Subtitles by Default: ڈیفالٹ کے طور پر سب ٹائٹلز فعال کریں\n    Proxy Videos Through Invidious: ۔Invidious کے ذریعے ویڈیوز پراکسی کریں\n    Default Viewing Mode:\n      Theater: تھیٹر\n      Default Viewing Mode: ڈیفالٹ ویونگ موڈ\n      Full Screen: فل سکرین\n      Picture in Picture: پکچر ان پکچر\n      External Player: بیرونی پلیئر ({externalPlayerName})\n    Scroll Volume Over Video Player: ویڈیو پلیئر پر اسکرول کر کے والیوم تبدیل کریں\n    Scroll Playback Rate Over Video Player: ویڈیو پلیئر پر اسکرول کر کے پلے بیک ریٹ تبدیل کریں\n    Skip by Scrolling Over Video Player: ویڈیو پلیئر پر اسکرول کر کے اسکیپ کریں\n    Display Play Button In Video Player: ویڈیو پلیئر میں پلے بٹن دکھائیں\n    Enter Fullscreen on Display Rotate: ڈسپلے گھومنے پر فل اسکرین کریں\n    Next Video Interval: آٹو پلے کاؤنٹ ڈاؤن ٹائمر\n    Autoplay Interruption Timer: آٹو پلے میں رکاوٹ کا ٹائمر\n    Fast-Forward / Rewind Interval: فاسٹ فارورڈ / ریوائنڈ کا وقفہ\n    Default Volume: ڈیفالٹ والیوم\n    Default Playback Rate: ڈیفالٹ پلے بیک ریٹ\n    Max Video Playback Rate: زیادہ سے زیادہ ویڈیو پلے بیک ریٹ\n    Video Playback Rate Interval: ویڈیو پلے بیک ریٹ کا وقفہ\n    Default Video Format:\n      Default Video Format: ڈیفالٹ ویڈیو فارمیٹ\n      Dash Formats: DASH فارمیٹس\n      Legacy Formats: پرانے (Legacy) فارمیٹس\n      Audio Formats: آڈیو فارمیٹس\n    Default Quality:\n      Default Quality: ڈیفالٹ کوالٹی\n      Auto: خودکار\n      144p: 144p\n      240p: 240p\n      360p: 360p\n      480p: 480p\n      720p: 720p\n      1080p: 1080p\n      1440p: 1440p\n      4k: 4k\n      8k: 8k\n  External Player Settings:\n    Players:\n      None:\n        Name: کوئی نہیں\n    External Player Settings: بیرونی پلیئر\n    External Player: بیرونی پلیئر\n    Ignore Unsupported Action Warnings: غیر تعاون یافتہ ایکشن وارننگز کو نظر انداز کریں\n    Ignore Default Arguments: ڈیفالٹ آرگیومینٹس کو نظر انداز کریں\n    Custom External Player Executable: کسٹم بیرونی پلیئر فائل (Executable)\n    Custom External Player Arguments: کسٹم بیرونی پلیئر آرگیومینٹس\n  Data Settings:\n    Profile object has insufficient data, skipping item: 'پروفائل آبجیکٹ ناکافی ہے۔ ڈیٹا، آئٹم کو چھوڑنا'\n    All subscriptions and profiles have been successfully imported: 'تمام سبسکرپشنز اور پروفائلز کو کامیابی کے ساتھ درآمد کیا گیا ہے'\n    All subscriptions have been successfully imported: 'تمام سبسکرپشنز کو کامیابی کے ساتھ درآمد کر لیا گیا'\n    Subscriptions have been successfully exported: 'سبسکرپشنز کامیابی سے ہو گئی ہیں۔ برآمد'\n    History object has insufficient data, skipping item: 'تاریخ کا اعتراض ناکافی ہے۔ ڈیٹا، آئٹم کو چھوڑنا'\n    All watched history has been successfully imported: 'تمام دیکھی گئی سرگزشت کامیابی سے درآمد کیا گیا'\n    All watched history has been successfully exported: 'تمام دیکھی گئی تاریخ رہی ہے۔ کامیابی سے برآمد'\n    Playlist insufficient data: '\"{playlist}\" پلے لسٹ کے لیے ناکافی ڈیٹا، آئٹم کو چھوڑنا'\n    All playlists has been successfully imported: 'تمام پلے لسٹ کامیابی سے درآمد کی گئی'\n    All playlists has been successfully exported: 'تمام پلے لسٹ ہو چکی ہیں۔ کامیابی سے برآمد'\n    Data Settings: ڈیٹا\n    Select Export Type: ایکسپورٹ کی قسم منتخب کریں\n    Import Subscriptions: سبسکرپشنز امپورٹ کریں\n    Subscription File: سبسکرپشن فائل\n    History File: ہسٹری فائل\n    Playlist File: پلے لسٹ فائل\n    Search history file: سرچ ہسٹری فائل\n    Export Subscriptions: سبسکرپشنز ایکسپورٹ کریں\n    Export FreeTube: فری ٹیوب ایکسپورٹ کریں\n    Export YouTube: یوٹیوب ایکسپورٹ کریں\n    Export NewPipe: نیو پائپ ایکسپورٹ کریں\n    Import History: ہسٹری امپورٹ کریں\n    Export History: ہسٹری ایکسپورٹ کریں\n    Import Playlists: پلے لسٹس امپورٹ کریں\n    Export Playlists: پلے لسٹس ایکسپورٹ کریں\n    Search history: سرچ ہسٹری\n    Import search history: سرچ ہسٹری امپورٹ کریں\n    Export search history: سرچ ہسٹری ایکسپورٹ کریں\n    Invalid subscriptions file: غیر درست سبسکرپشن فائل\n    Invalid history file: غیر درست ہسٹری فائل\n    All search history has been successfully imported: تمام سرچ ہسٹری کامیابی کے ساتھ امپورٹ ہو گئی ہے\n    All search history has been successfully exported: تمام سرچ ہسٹری کامیابی کے ساتھ ایکسپورٹ ہو گئی ہے\n    Unable to read file: فائل پڑھنے میں ناکامی\n    Unable to write file: فائل لکھنے میں ناکامی\n    Unknown data key: نامعلوم ڈیٹا کی (Key)\n    How do I import my subscriptions?: میں اپنی سبسکرپشنز کیسے امپورٹ کروں؟\n    Manage Subscriptions: سبسکرپشنز کا انتظام کریں\n  SponsorBlock Settings:\n    SponsorBlock Settings: اسپانسر بلاک (SponsorBlock)\n    Enable SponsorBlock: اسپانسر بلاک فعال کریں\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': اسپانسر بلاک API Url (ڈیفالٹ https://sponsor.ajay.app ہے)\n    Notify when sponsor segment is skipped: اسپانسر حصہ اسکیپ ہونے پر مطلع کریں\n    UseDeArrowTitles: ۔DeArrow ویڈیو عنوانات استعمال کریں\n    UseDeArrowThumbnails: تھمب نیلز کے لیے DeArrow استعمال کریں\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ۔DeArrow تھمبنیل جنریٹر API Url (ڈیفالٹ https://dearrow-thumb.ajay.app ہے)\n    Skip Options:\n      Skip Option: اسکیپ آپشن\n      Auto Skip: آٹو اسکیپ\n      Show In Seek Bar: سیک بار (Seek Bar) میں دکھائیں\n      Prompt To Skip: اسکیپ کرنے کے لیے پوچھیں\n      Do Nothing: کچھ نہ کریں\n    Category Color: زمرہ کا رنگ\n  Settings: سیٹنگز\n  Sort Settings Sections (A-Z): Sort Settings Sections (A سے Z)\n  Return to Settings Menu: سیٹنگز مینو میں واپس جائیں\n  Privacy Settings:\n    Privacy Settings: رازداری\n    Remember History: واچ ہسٹری یاد رکھیں\n    Remember Search History: سرچ ہسٹری یاد رکھیں\n    Save Watched Progress: دیکھی گئی پیشرفت محفوظ کریں\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: خودکار\n        Semi-auto: نیم خودکار\n        Never: کبھی نہیں\n      Tooltip: Auto = ہر ویڈیو پیج سے نکلنے، ویڈیو ختم ہونے اور ایرر آنے پر محفوظ کریں۔ Semi-auto = یہ آٹو کی طرح ہے سوائے ویڈیو پیج سے نکلنے کے، اور اس میں آپ ویڈیو پلیئر کے نیچے موجود بٹن ”Save Watched Progress“ کے ذریعے دستی طور پر پیشرفت محفوظ کر سکتے ہیں۔\n    Save Watched Videos With Last Viewed Playlist: آخری بار دیکھی گئی پلے لسٹ کے ساتھ ویڈیوز محفوظ کریں\n    Clear Search History and Cache: سرچ ہسٹری اور کیشے صاف کریں\n    Are you sure you want to clear out your search history and cache?: کیا آپ واقعی اپنی سرچ ہسٹری اور کیشے صاف کرنا چاہتے ہیں؟\n    Search history and cache have been cleared: سرچ ہسٹری اور کیشے صاف کر دیے گئے ہیں\n    Remove Watch History: واچ ہسٹری ہٹائیں\n    Are you sure you want to remove your entire watch history?: کیا آپ واقعی اپنی تمام واچ ہسٹری ہٹانا چاہتے ہیں؟\n    Watch history has been cleared: واچ ہسٹری صاف کر دی گئی ہے\n    Remove All Subscriptions / Profiles: تمام سبسکرپشنز / پروفائلز ہٹائیں\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: کیا آپ واقعی تمام سبسکرپشنز اور پروفائلز ہٹانا چاہتے ہیں؟ یہ عمل واپس نہیں لیا جا سکے گا۔\n    Remove All Playlists: تمام پلے لسٹس ہٹائیں\n    All playlists have been removed: تمام پلے لسٹس ہٹا دی گئی ہیں\n    Are you sure you want to remove all your playlists?: کیا آپ واقعی اپنی تمام پلے لسٹس ہٹانا چاہتے ہیں؟\n  Subscription Settings:\n    Subscription Settings: سبسکرپشن\n    Fetch Feeds from RSS: RSS سے فیڈز حاصل کریں\n    Fetch Automatically: فیڈز خود بخود حاصل کریں\n    'Limit the number of videos displayed for each channel': ہر چینل کے لیے ویڈیوز کی تعداد محدود کریں\n    To: تک\n    Confirm Before Unsubscribing: ان سبسکرائب کرنے سے پہلے تصدیق کریں\n  Distraction Free Settings:\n    Distraction Free Settings: ڈسٹریکشن فری (Distraction Free)\n    Sections:\n      Side Bar: سائیڈ بار\n      Subscriptions Page: سبسکرپشنز کا صفحہ\n      Channel Page: چینل کا صفحہ\n      Watch Page: واچ پیج\n      General: عمومی\n    Hide Video Views: ویڈیو ویوز چھپائیں\n    Hide Video Likes And Dislikes: ویڈیو لائکس اور ڈسلائکس چھپائیں\n    Hide Channel Subscribers: چینل سبسکرائبرز چھپائیں\n    Hide Comment Likes: کمنٹس کے لائکس چھپائیں\n    Hide Recommended Videos: تجویز کردہ ویڈیوز چھپائیں\n    Hide Trending Videos: ٹرینڈنگ ویڈیوز چھپائیں\n    Hide Popular Videos: مقبول ویڈیوز چھپائیں\n    Hide Playlists: پلے لسٹس چھپائیں\n    Hide Live Chat: لائیو چیٹ چھپائیں\n    Hide Active Subscriptions: فعال سبسکرپشنز چھپائیں\n    Hide Video Description: ویڈیو کی تفصیل چھپائیں\n    Hide Comments: کمنٹس چھپائیں\n    Hide Profile Pictures in Comments: کمنٹس میں پروفائل تصویریں چھپائیں\n    Display Titles Without Excessive Capitalisation: عنوانات کو زیادہ بڑے حروف اور رموزِ اوقاف کے بغیر دکھائیں\n    Hide Live Streams: لائیو اسٹریمز چھپائیں\n    Hide Upcoming Premieres: آنے والے پریمیئرز چھپائیں\n    Hide Sharing Actions: شیئرنگ ایکشنز چھپائیں\n    Hide Videos on Watch: واچ پیج پر ویڈیوز چھپائیں\n    Hide Chapters: چیپٹرز چھپائیں\n    Hide Channels: چینلز سے ویڈیوز چھپائیں\n    Hide Channels Disabled Message: کچھ چینلز کو آئی ڈی کے ذریعے بلاک کیا گیا تھا اور ان پر کارروائی نہیں ہوئی۔ جب تک وہ آئی ڈیز اپ ڈیٹ ہو رہی ہیں، یہ فیچر بلاک رہے گا\n    Hide Channels Placeholder: چینل آئی ڈی\n    Hide Channels Invalid: فراہم کردہ چینل آئی ڈی غیر درست ہے\n    Hide Channels API Error: فراہم کردہ آئی ڈی کے ساتھ صارف کی معلومات حاصل کرنے میں غلطی ہوئی۔ براہ کرم دوبارہ چیک کریں کہ آیا آئی ڈی درست ہے۔\n    Hide Channels Already Exists: چینل آئی ڈی پہلے ہی موجود ہے\n    Hide Featured Channels: فیچرڈ چینلز چھپائیں\n    Hide Channel Playlists: چینل کا ”پلے لسٹس“ ٹیب چھپائیں\n    Hide Channel Posts: چینل کا ”پوسٹس“ ٹیب چھپائیں\n    Hide Channel Home: چینل کا ”ہوم“ ٹیب چھپائیں\n    Hide Channel Shorts: چینل کا ”شارٹس“ ٹیب چھپائیں\n    Hide Channel Podcasts: چینل کا ”پوڈ کاسٹس“ ٹیب چھپائیں\n    Hide Channel Releases: چینل کا ”ریلیز“ ٹیب چھپائیں\n    Hide Channel Courses: چینل کا ”کورسز“ ٹیب چھپائیں\n    Hide Videos, Playlists and Channels Containing Text: تحریر پر مشتمل ویڈیوز، پلے لسٹس اور چینلز چھپائیں\n    Hide Videos, Playlists and Channels Containing Text Placeholder: لفظ، لفظ کا حصہ، یا جملہ\n    Hide Subscriptions Videos: سبسکرپشن ویڈیوز چھپائیں\n    Hide Subscriptions Shorts: سبسکرپشن شارٹس چھپائیں\n    Hide Subscriptions Live: سبسکرپشن لائیو چھپائیں\n    Hide Subscriptions Posts: سبسکرپشن پوسٹس چھپائیں\n    Show Added Items: شامل کردہ آئٹمز دکھائیں\n  Proxy Settings:\n    Proxy Settings: پراکسی\n    Proxy Warning: FreeTube میں پہلے سے موجود پراکسی نہیں ہے لیکن یہ کسی بیرونی پراکسی سے منسلک ہو سکتا ہے، جیسے کہ آپ کی مشین پر چلنے والا Tor یا SOCKS5 پراکسی جو کچھ VPNs فراہم کرتے ہیں۔ اگر فعال ہو، تو یقینی بنائیں کہ آپ کی پراکسی/Tor درست طریقے سے کنفیگر ہے، ورنہ FreeTube کوئی ڈیٹا حاصل نہیں کر سکے گا۔\n    Enable Tor / Proxy: ٹور / پراکسی فعال کریں\n    Proxy Protocol: پراکسی پروٹوکول\n    Proxy Host: پراکسی ہوسٹ\n    Proxy Port Number: پراکسی پورٹ نمبر\n    Proxy Username: پراکسی یوزر نیم\n    Proxy Password: پراکسی پاس ورڈ\n    Clicking on Test Proxy will send a request to: 'ٹیسٹ پراکسی پر کلک کرنے سے ایک درخواست اس پر بھیجی جائے گی'\n    Test Proxy: پراکسی ٹیسٹ کریں\n    Your Info: آپ کی معلومات\n    Ip: آئی پی (Ip)\n    Country: ملک\n    Region: خطہ\n    City: شہر\n    Error getting network information. Is your proxy configured properly?: نیٹ ورک کی معلومات حاصل کرنے میں غلطی۔ کیا آپ کی پراکسی درست طریقے سے کنفیگر ہے؟\n  Parental Control Settings:\n    Parental Control Settings: پیرنٹل کنٹرول\n    Hide Unsubscribe Button: ان سبسکرائب بٹن چھپائیں\n    Hide Uploader on Watch page: واچ پیج پر اپ لوڈر کو چھپائیں\n    Show Family Friendly Only: صرف فیملی فرینڈلی دکھائیں\n    Hide Search Bar: سرچ بار چھپائیں\n  Experimental Settings:\n    Experimental Settings: تجرباتی\n    Warning: یہ سیٹنگز تجرباتی ہیں، ان کے فعال ہونے پر ایپ کریش ہو سکتی ہے۔ بیک اپ بنانے کی سختی سے سفارش کی جاتی ہے۔ اپنے خطرے پر استعمال کریں!\n    Replace HTTP Cache: ۔HTTP کیشے کو تبدیل کریں\n  Password Dialog:\n    Password: پاس ورڈ\n    Enter Password To Unlock: سیٹنگز ان لاک کرنے کے لیے پاس ورڈ درج کریں\n  Password Settings:\n    Password Settings: پاس ورڈ\n    Set Password To Prevent Access: سیٹنگز تک رسائی روکنے کے لیے پاس ورڈ سیٹ کریں\n    Set Password: پاس ورڈ سیٹ کریں\n    Remove Password: پاس ورڈ ہٹائیں\nAbout:\n  #On About page\n  Please check for duplicates before posting: 'براہ کرم پوسٹ کرنے سے پہلے ڈپلیکیٹس کی جانچ کریں'\n  About: بارے میں\n  Beta: بیٹا (Beta)\n  Source code: سورس کوڈ\n  Licensed under the: کے تحت لائسنس یافتہ\n  AGPLv3: AGPLv3\n  Downloads / Changelog: ڈاؤن لوڈز / تبدیلیوں کا ریکارڈ\n  GitHub releases: گِٹ ہب ریلیز\n  Help: مدد\n  FreeTube Wiki: فری ٹیوب وکی\n  FAQ: اکثر پوچھے گئے سوالات\n  Discussions: بات چیت\n  Report a problem: مسئلہ رپورٹ کریں\n  GitHub issues: گِٹ ہب مسائل\n  Website: ویب سائٹ\n  Blog: بلاگ\n  Email: ای میل\n  Mastodon: Mastodon\n  Chat on Matrix: ۔Matrix پر چیٹ کریں\n  Please read the: 'براہ کرم پڑھیں'\n  room rules: کمرے کے اصول\n  Translate: ترجمہ کریں\n  Credits: کریڈٹس\n  FreeTube is made possible by: 'فری ٹیوب ان لوگوں کی بدولت ممکن ہوا ہے'\n  these people and projects: یہ لوگ اور پروجیکٹس\n  Donate: عطیہ دیں\nProfile:\n  Are you sure you want to delete this profile?: 'کیا آپ واقعی اسے حذف کرنا چاہتے ہیں۔ پروفائل؟'\n  All subscriptions will also be deleted.: 'تمام سبسکرپشنز بھی حذف کر دی جائیں گی۔'\n  Your profile name cannot be empty: 'آپ کا پروفائل نام خالی نہیں ہو سکتا'\n  Profile has been created: 'پروفائل بن گیا ہے'\n  Profile has been updated: 'پروفائل اپ ڈیٹ کر دیا گیا'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 'یہ آپ کا بنیادی پروفائل ہے۔ کیا آپ واقعی منتخب چینلز کو حذف کرنا چاہتے ہیں؟ دی ایک جیسے چینلز کو کسی بھی پروفائل میں حذف کر دیا جائے گا جس میں وہ پائے جائیں گے۔'\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 'ہیں کیا آپ واقعی منتخب چینلز کو حذف کرنا چاہتے ہیں؟ اس سے چینل حذف نہیں ہوگا۔ کسی دوسرے پروفائل سے۔'\n#On Channel Page\n  Select All: تمام منتخب کریں\n  Profile Settings: پروفائل\n  Toggle Profile List: پروفائل لسٹ تبدیل کریں\n  Profile Select: پروفائل کا انتخاب\n  Profile Filter: پروفائل فلٹر\n  All Channels: تمام چینلز\n  Profile Manager: پروفائل مینیجر\n  Create New Profile: نیا پروفائل بنائیں\n  Edit Profile: پروفائل ایڈٹ کریں\n  Edit Profile Name: پروفائل کا نام ایڈٹ کریں\n  Create Profile Name: پروفائل کا نام بنائیں\n  Profile Name: پروفائل کا نام\n  Color Picker: کلر پکر\n  Custom Color: کسٹم کلر\n  Profile Preview: پروفائل کا پیش نظارہ\n  Create Profile: پروفائل بنائیں\n  Update Profile: پروفائل اپ ڈیٹ کریں\n  Make Default Profile: ڈیفالٹ پروفائل بنائیں\n  Delete Profile: پروفائل حذف کریں\n  Your default profile has been set to {profile}: آپ کا ڈیفالٹ پروفائل {profile} پر سیٹ کر دیا گیا ہے\n  Removed {profile} from your profiles: آپ کے پروفائلز سے {profile} کو ہٹا دیا گیا ہے\n  Your default profile has been changed to your primary profile: آپ کا ڈیفالٹ پروفائل آپ کے پرائمری پروفائل میں تبدیل کر دیا گیا ہے\n  '{profile} is now the active profile': اب {profile} فعال پروفائل ہے\n  Subscription List: سبسکرپشن لسٹ\n  Other Channels: دیگر چینلز\n  '{number} selected': '{number} منتخب شدہ'\n  Select None: کوئی منتخب نہ کریں\n  Delete Selected: منتخب شدہ حذف کریں\n  Add Selected To Profile: منتخب شدہ کو پروفائل میں شامل کریں\n  No channel(s) have been selected: کوئی چینل منتخب نہیں کیا گیا\n  Close Profile Dropdown: پروفائل ڈراپ ڈاؤن بند کریں\n  Open Profile Dropdown: پروفائل ڈراپ ڈاؤن کھولیں\nChannel:\n  Videos:\n    Videos: ویڈیوز\n    This channel does not currently have any videos: اس چینل پر فی الحال کوئی ویڈیوز نہیں ہیں\n    Sort Types:\n      Newest: جدید ترین\n      Oldest: قدیم ترین\n      Most Popular: سب سے زیادہ مقبول\n  Subscribe: سبسکرائب\n  Unsubscribe: ان سبسکرائب\n  Channel has been removed from your subscriptions: چینل کو آپ کی سبسکرپشنز سے ہٹا دیا گیا ہے\n  Removed subscription from {count} other channel(s): '{count} دیگر چینلز سے سبسکرپشن ہٹا دی گئی ہے'\n  Added channel to your subscriptions: چینل کو آپ کی سبسکرپشنز میں شامل کر دیا گیا ہے\n  Search Channel: چینل تلاش کریں\n  Your search results have returned 0 results: آپ کی تلاش کے کوئی نتائج نہیں ملے\n  This channel does not exist: یہ چینل موجود نہیں ہے\n  This channel does not allow searching: یہ چینل تلاش کی اجازت نہیں دیتا\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: یہ چینل عمر کی حد کی وجہ سے محدود ہے اور فی الحال FreeTube میں نہیں دیکھا جا سکتا۔\n  Channel Tabs: چینل ٹیبز\n  Shorts:\n    This channel does not currently have any shorts: اس چینل پر فی الحال کوئی شارٹس نہیں ہیں\n  Live:\n    Live: لائیو\n    This channel does not currently have any live streams: اس چینل پر فی الحال کوئی لائیو اسٹریمز نہیں ہیں\n  Playlists:\n    Playlists: پلے لسٹس\n    This channel does not currently have any playlists: اس چینل پر فی الحال کوئی پلے لسٹس نہیں ہیں\n    Sort Types:\n      Last Video Added: آخری شامل کردہ ویڈیو\n      Newest: جدید ترین\n      Oldest: قدیم ترین\n  Home:\n    Home: ہوم\n    View Playlist: پلے لسٹ دیکھیں\n  Podcasts:\n    Podcasts: پوڈ کاسٹس\n    This channel does not currently have any podcasts: اس چینل پر فی الحال کوئی پوڈ کاسٹس نہیں ہیں\n  Releases:\n    Releases: ریلیز\n    This channel does not currently have any releases: اس چینل پر فی الحال کوئی ریلیز نہیں ہیں\n  Courses:\n    Courses: کورسز\n    This channel does not currently have any courses: اس چینل پر فی الحال کوئی کورسز نہیں ہیں\n  About:\n    About: بارے میں\n    Channel Description: چینل کی تفصیل\n    Tags:\n      Tags: ٹیگز\n      Search for: ”{tag}“ کے لیے تلاش کریں\n    Details: تفصیلات\n    Joined: شمولیت کی تاریخ\n    Location: مقام\n    Featured Channels: فیچرڈ چینلز\n  Posts:\n    This channel currently does not have any posts: اس چینل پر فی الحال کوئی پوسٹس نہیں ہیں\n    votes: '{votes} ووٹ'\n    View Full Post: مکمل پوسٹ دیکھیں\n    Reveal Answers: جوابات ظاہر کریں\n    Hide Answers: جوابات چھپائیں\n    Video hidden by FreeTube: ویڈیو کو FreeTube نے چھپا دیا ہے\nVideo:\n  IP block: یو ٹیوب نے آپ کے آئی پی ایڈریس کو ویڈیوز دیکھنے سے بلاک کر دیا ہے۔ براہ کرم کوئی دوسرا VPN یا پراکسی استعمال کریں۔\n  MembersOnly: صرف ممبرز کے لیے مخصوص ویڈیوز FreeTube پر نہیں دیکھی جا سکتیں کیونکہ ان کے لیے گوگل لاگ ان اور اپ لوڈر کے چینل کی پیڈ ممبرشپ درکار ہے۔\n  AgeRestricted: عمر کی حد والی ویڈیوز FreeTube پر نہیں دیکھی جا سکتیں کیونکہ ان کے لیے گوگل لاگ ان اور عمر کی تصدیق شدہ اکاؤنٹ درکار ہے۔\n  DRMProtected: DRM سے محفوظ ویڈیوز FreeTube پر نہیں چلائی جا سکتیں کیونکہ ان کے لیے کلوزڈ سورس اجزاء درکار ہیں۔ اگر آپ یہ ویڈیو دیکھنا چاہتے ہیں تو براہ کرم اسے آفیشل یوٹیوب ویب سائٹ پر دیکھیں۔\n  More Options: مزید آپشنز\n  Mark As Watched: دیکھا ہوا قرار دیں\n  Remove From History: ہسٹری سے ہٹائیں\n  Video has been marked as watched: ویڈیو کو دیکھا ہوا قرار دے دیا گیا ہے\n  Video has been removed from your history: ویڈیو کو آپ کی ہسٹری سے ہٹا دیا گیا ہے\n  Save Watched Progress: دیکھی گئی پیشرفت محفوظ کریں\n  Watched Progress Saved: دیکھی گئی پیشرفت محفوظ کر لی گئی ہے\n  Save Video: ویڈیو محفوظ کریں\n  Video has been saved: ویڈیو محفوظ کر لی گئی ہے\n  Video has been removed from your saved list: ویڈیو کو آپ کی محفوظ فہرست سے ہٹا دیا گیا ہے\n  Open in YouTube: یو ٹیوب میں کھولیں\n  Copy YouTube Link: یو ٹیوب لنک کاپی کریں\n  Open YouTube Embedded Player: یو ٹیوب ایمبیڈڈ پلیئر کھولیں\n  Copy YouTube Embedded Player Link: یو ٹیوب ایمبیڈڈ پلیئر لنک کاپی کریں\n  Open in Invidious: ۔Invidious میں کھولیں\n  Copy Invidious Link: ۔Invidious لنک کاپی کریں\n  Open Channel in YouTube: یو ٹیوب میں چینل کھولیں\n  Copy YouTube Channel Link: یو ٹیوب چینل لنک کاپی کریں\n  Open Channel in Invidious: ۔Invidious میں چینل کھولیں\n  Copy Invidious Channel Link: ۔Invidious چینل لنک کاپی کریں\n  Hide Channel: چینل چھپائیں\n  Unhide Channel: چینل دکھائیں\n  Views: ویوز\n  Loop Playlist: پلے لسٹ لوپ کریں\n  Shuffle Playlist: پلے لسٹ شفل کریں\n  Reverse Playlist: پلے لسٹ الٹ دیں\n  Previous: پچھلا\n  Next: اگلا\n  Watched: دیکھا ہوا\n  Autoplay: آٹو پلے\n  Starting soon, please refresh the page to check again: جلد شروع ہو رہا ہے، براہ کرم چیک کرنے کے لیے پیج ری فریش کریں\n  Premieres: پریمیئرز\n  Upcoming: آنے والا\n  Unlisted: ان لسٹڈ\n  Live: لائیو\n  Live Now: ابھی لائیو\n  Live Chat: لائیو چیٹ\n  Enable Live Chat: لائیو چیٹ فعال کریں\n  Popout Live Chat: پاپ آؤٹ چیٹ\n  Live Chat is currently not supported in this build.: لائیو چیٹ فی الحال اس ورژن میں دستیاب نہیں ہے۔\n  Live chat is enabled. Chat messages will appear here once sent.: لائیو چیٹ فعال ہے۔ پیغامات بھیجے جانے کے بعد یہاں نظر آئیں گے۔\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ۔Invidious API کے ساتھ لائیو چیٹ دستیاب نہیں ہے۔ یوٹیوب سے براہ راست کنکشن درکار ہے۔\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': اس اسٹریم کے لیے لائیو چیٹ دستیاب نہیں ہے۔ ہو سکتا ہے اپ لوڈر نے اسے غیر فعال کر دیا ہو۔\n  Show Super Chat Comment: سپر چیٹ کمنٹ دکھائیں\n  Scroll to Bottom: آخر تک اسکرول کریں\n  Published:\n    In less than a minute: ایک منٹ سے بھی کم وقت میں\n  Published on: شائع ہوا\n  Streamed on: اسٹریم ہوا\n  Started streaming on: اسٹریم شروع ہوا\n  DeArrow:\n    Show Original Details: اصل تفصیلات دکھائیں\n    Show Modified Details: تبدیل شدہ تفصیلات دکھائیں\n  Sponsor Block category:\n    sponsor: اسپانسر\n    intro: انٹرو (Intro)\n    outro: آؤٹرو (Outro)\n    self-promotion: اپنی تشہیر\n    interaction: تعامل (Interaction)\n    music offtopic: غیر متعلقہ موسیقی\n    recap: خلاصہ (Recap)\n    filler: فلر (Filler)\n  External Player:\n    OpenInTemplate: '{externalPlayer} میں کھولیں'\n    video: ویڈیو\n    playlist: پلے لسٹ\n    OpeningTemplate: '{videoOrPlaylist} کو {externalPlayer} میں کھولا جا رہا ہے...'\n    UnsupportedActionTemplate: '{externalPlayer} اس کی اجازت نہیں دیتا: {action}'\n    Unsupported Actions:\n      starting video at offset: ویڈیو کو مخصوص وقت سے شروع کرنا\n      setting a playback rate: پلے بیک کی رفتار سیٹ کرنا\n      opening playlists: پلے لسٹس کھولنا\n      opening specific video in a playlist (falling back to opening the video): پلے لسٹ میں مخصوص ویڈیو کھولنا (صرف ویڈیو کھولنے کی طرف واپس جا رہا ہے)\n      reversing playlists: پلے لسٹس کو الٹنا\n      shuffling playlists: پلے لسٹس کو شفل کرنا\n      looping playlists: پلے لسٹس کو لوپ کرنا\n  Player:\n    TranslatedCaptionTemplate: '{language} (”{originalLanguage}“ سے ترجمہ شدہ)'\n    Audio Tracks: آڈیو ٹریکس\n    Autoplay is off: آٹو پلے آف ہے\n    Autoplay is on: آٹو پلے آن ہے\n    Theatre Mode: تھیٹر موڈ\n    Exit Theatre Mode: تھیٹر موڈ سے باہر نکلیں\n    Full Window: مکمل ونڈو\n    Exit Full Window: مکمل ونڈو سے باہر نکلیں\n    Take Screenshot: اسکرین شاٹ لیں\n    Show Stats: اعداد و شمار دکھائیں\n    Hide Stats: اعداد و شمار چھپائیں\n    Stats:\n      Stats: اعداد و شمار\n      Video ID: 'ویڈیو آئی ڈی: {videoId}'\n      Media Formats: 'میڈیا فارمیٹس: {formats}'\n      Resolution: \"ریزولوشن: {width}x{height}{'@'}{frameRate}\"\n      Player Dimensions: 'پلیئر کے ابعاد: {width}x{height}'\n      Bitrate: 'بٹ ریٹ: {bitrate} kbps'\n      Volume: 'والیوم: {volumePercentage}%'\n      Bandwidth: 'بینڈوڈتھ: {bandwidth} kbps'\n      Buffered: 'بفر شدہ: {bufferedPercentage}%'\n      Dropped Frames / Total Frames: 'ضائع شدہ فریمز: {droppedFrames} / کل فریمز: {totalFrames}'\n      CodecAudio: 'کوڈیک: {audioCodec} ({audioItag})'\n      CodecsVideoAudio: 'کوڈیکس: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'کوڈیکس: {videoCodec} / {audioCodec}'\n    You appear to be offline: ایسا لگتا ہے کہ آپ آف لائن ہیں۔\n    Playback will resume automatically when your connection comes back: کنکشن بحال ہونے پر پلے بیک خود بخود شروع ہو جائے گا۔\n    Skipped segment: '{segmentCategory} والا حصہ اسکیپ کر دیا گیا'\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'بقیہ پری رول اشتہار کا وقت: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'بقیہ SABR بیک آف وقت: {remindingTimeSeconds}s'\nTooltips:\n  General Settings:\n    Preferred API Backend: 'اس بیک اینڈ کا انتخاب کریں جسے FreeTube ڈیٹا حاصل کرنے کے لیے استعمال کرتا ہے۔ دی لوکل API ایک بلٹ ان ایکسٹریکٹر ہے۔ ۔Invidious API کو ۔Invidious سرور کی ضرورت ہے۔ سے منسلک کرنے کے لئے.'\n    Fallback to Non-Preferred Backend on Failure: 'جب آپ کے پسندیدہ API میں کوئی مسئلہ ہو، FreeTube خود بخود آپ کے غیر ترجیحی API کو فال بیک کے طور پر استعمال کرنے کی کوشش کرے گا۔ فعال ہونے پر طریقہ۔'\n    Thumbnail Preference: 'FreeTube کے تمام تھمب نیلز کو اس سے بدل دیا جائے گا۔ پہلے سے طے شدہ تھمب نیل کے بجائے ویڈیو کا ایک فریم۔'\n    Invidious Instance: '۔Invidious Instance جس سے فری ٹیوب API کالز کے لیے جڑے گا۔'\n    External Link Handling: |\n      'جب کوئی لنک، جسے FreeTube میں نہیں کھولا جا سکتا، پر کلک کیا جاتا ہے تو پہلے سے طے شدہ طرز عمل کا انتخاب کریں۔\n       بطور ڈیفالٹ FreeTube آپ کے ڈیفالٹ براؤزر میں کلک کردہ لنک کو کھول دے گا۔'\n    Region for Trending: ٹرینڈز کا خطہ آپ کو یہ انتخاب کرنے دیتا ہے کہ آپ کس ملک کی ٹرینڈنگ ویڈیوز دیکھنا چاہتے ہیں۔\n    Open Deep Links In New Window: FreeTube کو بھیجے گئے لنکس (URLs)، جیسے کہ براؤزر ایکسٹینشنز یا کمانڈ لائن کے ذریعے، نئی ونڈو میں کھولے جاتے ہیں۔\n  Player Settings:\n    Proxy Videos Through Invidious: 'یوٹیوب سے براہ راست کنکشن بنانے کے بجائے ویڈیوز پیش کرنے کے لیے ۔Invidious سے جڑے گا۔'\n    Default Video Format: 'ویڈیو چلتے وقت استعمال ہونے والے فارمیٹس کو سیٹ کریں۔ DASH فارمیٹس کر سکتے ہیں۔ اعلی خصوصیات کو کھیلیں. لیگیسی فارمیٹس زیادہ سے زیادہ 720p تک محدود ہیں لیکن کم استعمال کرتے ہیں۔ بینڈوڈتھ. آڈیو فارمیٹس صرف آڈیو سلسلے ہیں۔'\n    Scroll Playback Rate Over Video Player: 'جب کرسر ویڈیو پر ہے، دبائیں اور کنٹرول کلید (میک پر کمانڈ کی) کو تھامیں اور کنٹرول کرنے کے لیے ماؤس وہیل کو آگے یا پیچھے کی طرف اسکرول کریں۔ پلے بیک کی شرح. کنٹرول کی (میک پر کمانڈ کی) کو دبائیں اور تھامیں اور ماؤس پر بائیں کلک کریں۔ ڈیفالٹ پلے بیک ریٹ پر تیزی سے واپس آنے کے لیے (1x جب تک اسے سیٹنگز میں تبدیل نہ کیا گیا ہو)۔'\n    Skip by Scrolling Over Video Player: ویڈیو کو اسکیپ کرنے کے لیے اسکرول وہیل کا استعمال کریں، MPV اسٹائل میں۔\n  External Player Settings:\n    External Player: 'ایک بیرونی کھلاڑی کا انتخاب ایک آئیکن ظاہر کرے گا، کھولنے کے لیے تھمب نیل پر، بیرونی پلیئر میں ویڈیو (اگر سپورٹ ہو تو پلے لسٹ)۔ انتباہ، ناگوار ترتیبات بیرونی کھلاڑیوں کو متاثر نہیں کرتی ہیں۔'\n    Custom External Player Executable: 'پہلے سے طے شدہ طور پر، FreeTube یہ فرض کرے گا کہ منتخب کردہ بیرونی پلیئر کو PATH ماحولیاتی متغیر کے ذریعے پایا جا سکتا ہے۔ اگر ضرورت ہو تو، ایک اپنی مرضی کے مطابق راستہ کر سکتے ہیں یہاں مقرر کیا جائے.'\n    Ignore Warnings: 'انتباہات کو دبائیں جب موجودہ بیرونی کھلاڑی تعاون نہیں کرتا ہے۔ موجودہ کارروائی (مثلاً پلے لسٹ کو تبدیل کرنا، وغیرہ)۔'\n    Custom External Player Arguments: کوئی بھی حسب ضرورت کمانڈ لائن آرگومنٹس، جو سیمیکولنز (';') سے الگ کیے گئے ہیں، آپ بیرونی کھلاڑی کو منتقل کرنا چاہتے ہیں۔\n    DefaultCustomArgumentsTemplate: '(پہلے سے طے شدہ: ''{defaultCustomArguments}'')'\n    Ignore Default Arguments: ویڈیو لنک کے علاوہ بیرونی پلیئر کو کوئی ڈیفالٹ آرگیومینٹس نہ بھیجیں (جیسے پلے بیک رفتار، پلے لسٹ لنک وغیرہ)۔ کسٹم آرگیومینٹس اب بھی بھیجے جائیں گے۔\n  Subscription Settings:\n    Fetch Feeds from RSS: 'فعال ہونے پر، FreeTube آپ کے سبسکرپشن فیڈ کو حاصل کرنے کے لیے اپنے پہلے سے طے شدہ طریقہ کے بجائے RSS کا استعمال کرے گا۔ RSS تیز ہے اور آئی پی کو بلاک کرنے سے روکتا ہے، لیکن کچھ معلومات فراہم نہیں کرتا ہے جیسے ویڈیو کا دورانیہ، لائیو اسٹیٹس یا کمیونٹی پوسٹس'\n\n# Toast Messages\n    Fetch Automatically: فعال ہونے پر، FreeTube ایپ شروع ہوتے ہی اور نئی ونڈو کھلنے پر آپ کی سبسکرپشن فیڈ خود بخود حاصل کر لے گا۔\n  Distraction Free Settings:\n    Hide Channels: تلاش، ٹرینڈنگ، مقبول اور تجویز کردہ فہرستوں سے ویڈیوز، پلے لسٹس اور چینل کو چھپانے کے لیے چینل آئی ڈی درج کریں۔ آئی ڈی کا مکمل طور پر درست ہونا ضروری ہے۔\n    Hide Subscriptions Live: یہ سیٹنگ ایپ بھر کی ”{appWideSetting}“ سیٹنگ کے ذریعے تبدیل کر دی گئی ہے، جو کہ ”{settingsSection}“ کے ”{subsection}“ سیکشن میں ہے\n    Hide Videos, Playlists and Channels Containing Text: کسی لفظ، جملے یا لفظ کے حصے کے ذریعے ان تمام ویڈیوز، پلے لسٹس اور چینلز کو چھپائیں جن کے عنوان میں وہ موجود ہو (سوائے ہسٹری، آپ کی پلے لسٹس اور پلے لسٹس کے اندر موجود ویڈیوز کے)۔\n    Hide Videos on Watch: سبسکرپشن اور چینل کے صفحات پر ویڈیوز، شارٹس اور لائیو ٹیبز سے دیکھی گئی ویڈیوز کو چھپاتا ہے۔ یہ چینل صفحات کے ہوم ٹیب پر اثر انداز نہیں ہوتا\n  Experimental Settings:\n    Replace HTTP Cache: Electron کے ڈسک پر مبنی HTTP کیشے کو غیر فعال کرتا ہے اور کسٹم میموری امیج کیشے کو فعال کرتا ہے۔ اس سے ریم (RAM) کا استعمال بڑھ سکتا ہے۔\n  SponsorBlock Settings:\n    UseDeArrowTitles: ویڈیو کے عنوانات کو DeArrow کے صارفین کے فراہم کردہ عنوانات سے تبدیل کریں۔\n    UseDeArrowThumbnails: ویڈیو تھمب نیلز کو DeArrow کے تھمب نیلز سے تبدیل کریں۔\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 'یہ ویڈیو غائب فارمیٹس کی وجہ سے دستیاب نہیں ہے۔ یہ ملک کی عدم دستیابی کی وجہ سے ہوسکتا ہے۔'\nUnknown YouTube url type, cannot be opened in app: 'نامعلوم یو ٹیوب url قسم، ایپ میں نہیں کھولی جا سکتی'\nLoop is now disabled: 'بار بار چلانا اب غیر فعال ہے'\nLoop is now enabled: 'مکرر چلانا اب فعال ہے'\nShuffle is now disabled: 'شفل اب غیر فعال ہے'\nShuffle is now enabled: 'شفل اب فعال ہے'\nThe playlist has been reversed: 'پلے لسٹ کو الٹ دیا گیا ہے'\nPlaying Next Video: 'اگلا ویڈیو چل رہا ہے'\nPlaying Previous Video: 'پچھلا ویڈیو چل رہا ہے'\nPlaying Next Video Interval: 'اگلی ویڈیو بغیر کسی وقت چلائی جا رہی ہے۔ منسوخ کرنے کے لیے کلک کریں۔ | اگلی ویڈیو {nextVideoInterval} سیکنڈ میں چلائی جا رہی ہے۔ منسوخ کرنے کے لیے کلک کریں۔ | اگلی ویڈیو {nextVideoInterval} سیکنڈ میں چلائی جا رہی ہے۔ منسوخ کرنے کے لیے کلک کریں۔'\nCanceled next video autoplay: 'اگلا ویڈیو آٹو پلے منسوخ کر دی گئی'\nDefault Invidious instance has been cleared: 'طے شدہ ۔Invidious instance کو صاف کر دیا گیا ہے'\n'The playlist has ended. Enable loop to continue playing': 'پلے لسٹ ختم ہو گئی ہے۔ فعال کھیل جاری رکھنے کے لیے لوپ'\nExternal link opening has been disabled in the general settings: 'عام ترتیبات میں بیرونی لنک کھولنے کو غیر فعال کر دیا گیا ہے'\nScreenshot Error: 'اسکرین شاٹ ناکام ہو گیا۔ {error}'\nVersion {versionNumber} is now available!  Click for more details: ورژن {versionNumber} اب دستیاب ہے! . . مزید تفصیلات کے لیے کلک کریں\nGlobal:\n  Counts:\n    Video Count: ۱ ویڈیو | {count} ویڈیوز\n    Channel Count: ۱ چینل | {count} چینلز\n    Subscriber Count: ۱ سبسکرائبر | {count} سبسکرائبرس\n    Watching Count: ۱ دیکھ رہا ہے | {count} دیکھ رہے ہیں\n    View Count: 1 مشاہدہ | {count} مشاہدات\n    Like Count: ۱ لائک | {count} لائکس\n    Comment Count: ۱ تبصرہ | {count} تبصرے\n  Videos: ویڈیوز\n  Shorts: شورٹس\n  Live: لائیو\n  Posts: پوسٹس\n  Sort By: ترتیب بہ لحاظ\nClose Banner: بینر بندکریں\nPreferences: ترجیحات\nGo to page: '{page} میں جائیں'\nSearch Listing:\n  Label:\n    4K: 4K\n    VR180: VR180\n    8K: 8K\n    360 Video: 360°\n    Subtitles: سب ٹائٹلز\n    New: نیا\n    3D: 3D\n    Closed Captions: کلوزڈ کیپشنز\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: ڈویلپر ٹولز کو ٹوگل کریں\n  Zoom Out: زوم آؤٹ\n  Zoom In: زوم ان\n  Fullscreen: پوری اسکرین کو ٹوگل کریں\n  Keyboard Shortcuts: کی بورڈ شارٹ کٹس\n  Sections:\n    Video:\n      Playback: ویڈیو: پلے بیک\n      General: ویڈیو: عمومی\n    App:\n      Situational: 'ایپ: حالات کے مطابق'\n      General: ایپ: عمومی\n  Show Keyboard Shortcuts: کی بورڈ شارٹ کٹس دکھائیں\n  History Backward: ایک صفحہ پیچھے جائیں\n  History Forward: ایک صفحہ آگے جائیں\n  New Window: نئی ونڈو بنائیں\n  Navigate to Settings: سیٹنگز پیج پر جائیں\n  Navigate to History: ہسٹری پیج پر جائیں\n  Refresh: تازہ ترین مواد کے ساتھ فیڈ ری فریش کریں\n  Focus Secondary Search: سیکنڈری سرچ بار پر توجہ دیں (اگر موجود ہو)\n  Captions: کیپشنز آن/آف کریں\n  Stats: ویڈیو کے اعداد و شمار دکھائیں\n  Picture in Picture: پکچر ان پکچر موڈ تبدیل کریں\n  Large Rewind: 10 سیکنڈ پیچھے کریں / پلے بیک کی رفتار کے مطابق ویڈیو پیچھے کریں\n  Play: پلے/پاز تبدیل کریں\n  Large Fast Forward: 10 سیکنڈ آگے کریں / پلے بیک کی رفتار کے مطابق ویڈیو آگے کریں\n  Mute: میوٹ تبدیل کریں\n  Decrease Video Speed: پلے بیک رفتار کے وقفے کے مطابق ویڈیو کی رفتار کم کریں\n  Increase Video Speed: پلے بیک رفتار کے وقفے کے مطابق ویڈیو کی رفتار زیادہ کریں\n  Full Window: فل ونڈو تبدیل کریں\n  Theatre Mode: تھیٹر موڈ تبدیل کریں\n  Take Screenshot: اسکرین شاٹ لیں\n  Minimize Window: ونڈو چھوٹی کریں\n  Close Window: ونڈو بند کریں\n  Reset Zoom: زوم لیول / UI اسکیل ری سیٹ کریں\n  Focus Search: سرچ بار پر توجہ دیں\n  Search in New Window: نئی ونڈو میں تلاش کریں\n  Last Frame: پچھلا فریم (رکی ہوئی حالت میں)\n  Next Frame: اگلا فریم (رکی ہوئی حالت میں)\n  Volume Up: والیوم زیادہ کریں\n  Volume Down: والیوم کم کریں\n  Small Rewind: ریوائنڈ کے وقفے اور پلے بیک کی رفتار کے مطابق X سیکنڈ پیچھے کریں\n  Small Fast Forward: فاسٹ فارورڈ کے وقفے اور پلے بیک کی رفتار کے مطابق X سیکنڈ آگے کریں\n  Last Chapter: آخری چیپٹر\n  Next Chapter: اگلا چیپٹر\n  Skip by Tenths: فیصد کے لحاظ سے ویڈیو اسکیپ کریں (مثلاً 3 دبانے سے 30% دورانیے پر جائیں)\n  Home: ویڈیو کے آغاز پر جائیں\n  End: ویڈیو کے آخر پر جائیں\n  Skip to Next Video: پلے لسٹ میں اگلی ویڈیو یا اگلی تجویز کردہ ویڈیو پر جائیں\n  Skip to Previous Video: پلے لسٹ میں پچھلی ویڈیو پر جائیں\nCompact side navigation: سائیڈ نیویگیشن چھوٹا کریں\nExpand side navigation: سائیڈ نیویگیشن پھیلائیں\nRight-click or hold to see history: ہسٹری دیکھنے کے لیے رائٹ کلک کریں یا دبائے رکھیں\nSearch character limit: تلاش کے الفاظ {searchCharacterLimit} حروف کی حد سے زیادہ ہے\nTrending:\n  Trending: ٹرینڈنگ\n  Gaming: گیمنگ\n  Sports: کھیل\n  Trending Tabs: ٹرینڈنگ ٹیبز\nMost Popular: سب سے زیادہ مقبول\nFeed:\n  Feed Last Updated: '{feedName} فیڈ آخری بار اپ ڈیٹ ہوئی: {date}'\n  Refresh Feed: '{subscriptionName} ریفریش کریں'\nPlaylists: پلے لسٹس\nPlaylist:\n  Playlist: پلے لسٹ\n  View Full Playlist: مکمل پلے لسٹ دیکھیں\n  Last Updated On: آخری بار اپ ڈیٹ ہوا\n  Sort By:\n    DateAddedNewest: شامل کرنے کی تاریخ (جدید ترین)\n    DateAddedOldest: شامل کرنے کی تاریخ (قدیم ترین)\n    PublishedNewest: اشاعت کی تاریخ (جدید ترین)\n    PublishedOldest: اشاعت کی تاریخ (قدیم ترین)\n    AuthorAscending: تخلیق کا (A سے Z)\n    AuthorDescending: تخلیق کار (Z سے A)\n    VideoTitleAscending: عنوان (A سے Z)\n    VideoTitleDescending: عنوان (Z سے A)\n    VideoDurationAscending: دورانیہ (مختصر ترین)\n    VideoDurationDescending: دورانیہ (طویل ترین)\n    Custom: کسٹم\nChange Format:\n  Change Media Formats: میڈیا فارمیٹس تبدیل کریں\n  Use Dash Formats: ۔DASH فارمیٹس استعمال کریں\n  Use Legacy Formats: پرانے (Legacy) فارمیٹس استعمال کریں\n  Use Audio Formats: آڈیو فارمیٹس استعمال کریں\n  Dash formats are not available for this video: اس ویڈیو کے لیے DASH فارمیٹس دستیاب نہیں ہیں\n  Audio formats are not available for this video: اس ویڈیو کے لیے آڈیو فارمیٹس دستیاب نہیں ہیں\n  Legacy formats are not available for this video: اس ویڈیو کے لیے پرانے فارمیٹس دستیاب نہیں ہیں\nShare:\n  Share Video: ویڈیو شیئر کریں\n  Share Post: پوسٹ شیئر کریں\n  Share Channel: چینل شیئر کریں\n  Share Playlist: پلے لسٹ شیئر کریں\n  Include Timestamp: ٹائم اسٹیمپ شامل کریں\n  Copy Link: لنک کاپی کریں\n  Open Link: لنک کھولیں\n  Copy Embed: ایمبیڈ کاپی کریں\n  Open Embed: ایمبیڈ کھولیں\n  Invidious URL copied to clipboard: ۔Invidious URL کلپ بورڈ پر کاپی کر لیا گیا ہے\n  Invidious Embed URL copied to clipboard: ۔Invidious Embed URL کلپ بورڈ پر کاپی کر لیا گیا ہے\n  Invidious Channel URL copied to clipboard: ۔Invidious Channel URL کلپ بورڈ پر کاپی کر لیا گیا ہے\n  YouTube URL copied to clipboard: یو ٹیوب URL کلپ بورڈ پر کاپی کر لیا گیا ہے\n  YouTube Embed URL copied to clipboard: یو ٹیوب Embed URL کلپ بورڈ پر کاپی کر لیا گیا ہے\n  YouTube Channel URL copied to clipboard: یو ٹیوب Channel URL کلپ بورڈ پر کاپی کر لیا گیا ہے\nClipboard:\n  Copy failed: کلپ بورڈ پر کاپی کرنا ناکام رہا\n  Cannot access clipboard without a secure connection: محفوظ کنکشن کے بغیر کلپ بورڈ تک رسائی ممکن نہیں ہے\nChapters:\n  Chapters: چیپٹرز (Chapters)\n  Key Moments: اہم لمحات\nMini Player: منی پلیئر\nComments:\n  Comments: کمنٹس\n  Click to View Comments: کمنٹس دیکھنے کے لیے کلک کریں\n  Getting comment replies, please wait: کمنٹس کے جوابات حاصل کیے جا رہے ہیں، براہ کرم انتظار کریں\n  There are no more comments for this video: اس ویڈیو کے لیے مزید کوئی کمنٹس نہیں ہیں\n  Hide Comments: کمنٹس چھپائیں\n  Top comments: بہترین کمنٹس\n  Newest first: جدید ترین پہلے\n  View {replyCount} replies: 1 جواب دیکھیں | {replyCount} جوابات دیکھیں\n  Hide {replyCount} replies: 1 جواب چھپائیں | {replyCount} جوابات چھپائیں\n  View 1 reply from {channelName}: '{channelName} کا 1 جواب دیکھیں'\n  View {replyCount} replies from {channelName} and others: '{channelName} اور دیگر کے {replyCount} جوابات دیکھیں'\n  Show More Replies: مزید جوابات دکھائیں\n  There are no comments available for this video: اس ویڈیو کے لیے کوئی کمنٹس دستیاب نہیں ہیں\n  There are no comments available for this post: اس پوسٹ کے لیے کوئی کمنٹس دستیاب نہیں ہیں\n  Load More Comments: مزید کمنٹس لوڈ کریں\n  Pinned by: پن کیا گیا از\n  Member: ممبر\n  Subscribed: سبسکرائب شدہ\n  Hearted: ہارٹ دیا گیا\nUp Next: اگلا\nDescription:\n  Expand Description: مزید…\n  Collapse Description: کم دکھائیں\nLocal API Error (Click to copy): مقامی (Local) API میں غلطی (کاپی کرنے کے لیے کلک کریں)\nInvidious API Error (Click to copy): ۔Invidious API میں غلطی (کاپی کرنے کے لیے کلک کریں)\nFalling back to Invidious API: ۔Invidious API کی طرف واپس جا رہا ہے\nFalling back to Local API: مقامی (Local) API کی طرف واپس جا رہا ہے\nAutoplay Interruption Timer: آٹو پلے {autoplayInterruptionIntervalHours} گھنٹے تک غیر فعال رہنے کی وجہ سے منسوخ کر دیا گیا\nDefault Invidious instance has been set to {instance}: ڈیفالٹ ۔Invidious انسٹنس {instance} پر سیٹ کر دیا گیا ہے\nAge Restricted:\n  This channel is age restricted: یہ چینل عمر کی حد کی وجہ سے محدود ہے\n  This video is age restricted: یہ ویڈیو عمر کی حد کی وجہ سے محدود ہے\nScreenshot Success: اسکرین شاٹ محفوظ کر لیا گیا\nChannel Hidden: '{channel} کو چینل فلٹر میں شامل کر دیا گیا'\nChannel Unhidden: '{channel} کو چینل فلٹر سے ہٹا دیا گیا'\nTrimmed input must be at least N characters long: ان پٹ کم از کم 1 حرف پر مشتمل ہونا چاہیے | ان پٹ کم از کم {length} حروف پر مشتمل ہونا چاہیے\nTag already exists: ”{tagName}“ ٹیگ پہلے سے موجود ہے\nHashtag:\n  Hashtag: ہیش ٹیگ\n  This hashtag does not currently have any videos: اس ہیش ٹیگ پر فی الحال کوئی ویڈیوز نہیں ہیں\nMoments Ago: تھوڑی دیر پہلے\nYes: جی ہاں\nNo: نہیں\nOk: ٹھیک ہے\nYes, Delete: جی ہاں، حذف کریں\nYes, Restart: جی ہاں، دوبارہ شروع کریں\nYes, Open Link: جی ہاں، لنک کھولیں\nCancel: منسوخ کریں\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nshortcutLabelSeparator: ｜\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  shift: Shift\n  enter: Enter\n  plus: Plus\n  arrowdown: نچلی تیر\n  arrowleft: بایاں تیر\n  arrowright: دایاں تیر\n  arrowup: اوپری تیر\n"
  },
  {
    "path": "static/locales/uz.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: ''\n\n# Webkit Menu Bar\nFile: ''\nNew Window: ''\nPreferences: ''\nQuit: ''\nEdit: ''\nUndo: ''\nRedo: ''\nCut: ''\nCopy: ''\nPaste: ''\nDelete: ''\nSelect all: ''\nToggle Developer Tools: ''\nActual size: ''\nZoom in: ''\nZoom out: ''\nToggle fullscreen: ''\nWindow: ''\nMinimize: ''\nClose: ''\nCompact side navigation: ''\nExpand side navigation: ''\nBack: ''\nForward: ''\nRight-click or hold to see history: ''\nOpen New Window: ''\nGo to page: ''\nClose Banner: ''\n\nVersion {versionNumber} is now available!  Click for more details: ''\nDownload From Site: ''\nA new blog is now available, {blogTitle}. Click to view more: ''\nAre you sure you want to open this link?: ''\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: ''\n  Shorts: ''\n  Live: ''\n  Posts: ''\n  Sort By: ''\n  Counts:\n    Video Count: ''\n    Channel Count: ''\n    Subscriber Count: ''\n    View Count: ''\n    Like Count: ''\n    Comment Count: ''\n    Watching Count: ''\n\n# Search Bar\nSearch / Go to URL: ''\nSearch Bar:\n  Clear Input: ''\n  Remove: ''\nSearch character limit: ''\nSearch Listing:\n  Label:\n    4K: ''\n    8K: ''\n    VR180: ''\n    360 Video: ''\n    Subtitles: ''\n    New: ''\n    3D: ''\n    # Aria labels\n    Closed Captions: ''\n  # In Filter Button\nSearch Filters:\n  Search Filters: ''\n  Sort By:\n    Most Relevant: ''\n    Rating: ''\n    Upload Date: ''\n    View Count: ''\n  Time:\n    Time: ''\n    Any Time: ''\n    Last Hour: ''\n    Today: ''\n    This Week: ''\n    This Month: ''\n    This Year: ''\n  Type:\n    Type: ''\n    All Types: ''\n    Videos: ''\n    Channels: ''\n    Movies: ''\n    #& Playlists\n  Duration:\n    Duration: ''\n    All Durations: ''\n    Short (< 4 minutes): ''\n    Medium (4 - 20 minutes): ''\n    Long (> 20 minutes): ''\n  Features:\n    Features: ''\n    HD: ''\n    Subtitles: ''\n    Creative Commons: ''\n    3D: ''\n    Live: ''\n    4K: ''\n    360 Video: ''\n    Location: ''\n    HDR: ''\n    VR180: ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n  Clear Filters: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Sports: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Export Playlist: ''\n  Export list of URLs: ''\n  The playlist has been successfully exported: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  TotalTimePlaylist: \"\"\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      Video has been removed. Click here to undo.: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n\n      This playlist has a video with a duration error: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\n  DateOldestHistory: ''\n  DateNewestHistory: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Minimize to system tray: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Latte: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n      Everforest Dark Hard: ''\n      Everforest Dark Medium: ''\n      Everforest Dark Low: ''\n      Everforest Light Hard: ''\n      Everforest Light Medium: ''\n      Everforest Light Low: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Latte Mauve: ''\n      Catppuccin Latte Red: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n      Everforest Dark Red: ''\n      Everforest Dark Orange: ''\n      Everforest Dark Yellow: ''\n      Everforest Dark Green: ''\n      Everforest Dark Aqua: ''\n      Everforest Dark Blue: ''\n      Everforest Dark Purple: ''\n      Everforest Light Red: ''\n      Everforest Light Orange: ''\n      Everforest Light Yellow: ''\n      Everforest Light Green: ''\n      Everforest Light Aqua: ''\n      Everforest Light Blue: ''\n      Everforest Light Purple: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Autoplay Playlists: ''\n    Autoplay Videos: ''\n    Turn on Subtitles by Default: ''\n    Proxy Videos Through Invidious: ''\n    Default Viewing Mode:\n      Theater: ''\n      Default Viewing Mode: ''\n      Full Screen: ''\n      Picture in Picture: ''\n      External Player: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Remember Search History: ''\n    Save Watched Progress: ''\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: ''\n        Semi-auto: ''\n        Never: ''\n      Tooltip: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search History and Cache: ''\n    Are you sure you want to clear out your search history and cache?: ''\n    Search history and cache have been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Videos on Watch: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Posts: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Channel Courses: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Hide Subscriptions Posts: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Search history file: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Search history: ''\n    Import search history: ''\n    Export search history: ''\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    All search history has been successfully imported: ''\n    All search history has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Proxy Username: ''\n    Proxy Password: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Hide Uploader on Watch page: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: ''\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  Courses:\n    Courses: ''\n    This channel does not currently have any courses: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Watched Progress: ''\n  Watched Progress Saved: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Autoplay is off: ''\n    Autoplay is on: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Post: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  Hide {replyCount} replies: ''\n  View 1 reply from {channelName}: ''\n  View {replyCount} replies from {channelName} and others: ''\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos on Watch: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nshortcutLabelSeparator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: ''\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: ''\n  Reset Zoom: ''\n  Zoom In: ''\n  Zoom Out: ''\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n  Home: ''\n  End: ''\n  Skip to Next Video: ''\n  Skip to Previous Video: ''\n"
  },
  {
    "path": "static/locales/vi.yaml",
    "content": "Locale Name: Tiếng Việt\n\n# Webkit Menu Bar\nFile: 'Tệp'\nQuit: 'Thoát'\nEdit: 'Chỉnh sửa'\nUndo: 'Hoàn tác'\nRedo: 'Làm lại'\nCut: 'Cắt'\nCopy: 'Sao chép'\nPaste: 'Dán'\nDelete: 'Xóa'\nSelect all: 'Chọn tất cả'\nToggle Developer Tools: 'Bật/Tắt Công cụ dành cho nhà phát triển'\nActual size: 'Kích thước thật'\nZoom in: 'Phóng to'\nZoom out: 'Thu nhỏ'\nToggle fullscreen: 'Chuyển đổi toàn màn hình'\nWindow: 'Cửa sổ'\nMinimize: 'Thu nhỏ'\nClose: 'Đóng'\nBack: 'Quay lại'\nForward: 'Tiến tới'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Video'\n\n# Search Bar\n  Live: Trực tiếp\n  Shorts: Shorts\n  Posts: Bài đăng\n  Sort By: 'Sắp xếp theo'\n  Counts:\n    Subscriber Count: 1 người đăng ký | {count} người đăng ký\n    View Count: 1 lượt xem | {count} lượt xem\n    Channel Count: 1 kênh | {count} kênh\n    Video Count: 1 video | {count} video\n    Watching Count: 1 lượt xem | {count} lượt xem\n    Like Count: '{count} lượt thích'\n    Comment Count: '{count} bình luận'\nSearch / Go to URL: 'Tìm kiếm / Đi đến URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: 'Lọc tìm kiếm'\n  Sort By:\n    Most Relevant: 'Liên quan nhất'\n    Rating: 'Đánh giá'\n    Upload Date: 'Ngày tải lên'\n    View Count: 'Lượt xem'\n  Time:\n    Time: 'Thời gian'\n    Any Time: 'Mọi lúc'\n    Last Hour: 'Giờ vừa qua'\n    Today: 'Hôm nay'\n    This Week: 'Tuần này'\n    This Month: 'Tháng này'\n    This Year: 'Năm nay'\n  Type:\n    Type: 'Loại'\n    All Types: 'Tất cả các loại'\n    Videos: 'Video'\n    Channels: 'Kênh'\n    #& Playlists\n    Movies: Phim ảnh\n  Duration:\n    Duration: 'Thời lượng'\n    All Durations: 'Tất cả thời lượng'\n    Short (< 4 minutes): 'Ngắn (<4 phút)'\n    Long (> 20 minutes): 'Dài (> 20 phút)'\n  # On Search Page\n    Medium (4 - 20 minutes): Vừa (4 - 20 phút)\n  Search Results: 'Kết quả tìm kiếm'\n  Fetching results. Please wait: 'Đang lấy kết quả. Xin hãy chờ'\n  Fetch more results: 'Lấy thêm kết quả'\n# Sidebar\n  There are no more results for this search: Không còn kết quả nào cho tìm kiếm này\n  Features:\n    Features: Chức năng\n    Subtitles: Có phụ đề\n    3D: 3D\n    Creative Commons: Creative Commons\n    Location: Địa điểm\n    HD: HD\n    Live: Trực tiếp\n    4K: 4K\n    360 Video: Video 360 độ\n    HDR: HDR\n    VR180: VR180\n  Clear Filters: Xoá bộ lọc\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Đăng ký'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Danh sách Đăng ký đang trống. Bắt đầu bằng cách tìm kiếm và đăng ký các kênh hoặc nhập các đăng ký hiện có của bạn bằng cách đi đến Cài đặt dữ liệu và nhấn vào Nhập đăng ký.'\n  Load More Videos: Tải thêm video\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Hồ sơ này có nhiều đăng ký.  Đang buộc RSS để tránh bị giới hạn\n  Error Channels: Các kênh có lỗi\n  Subscriptions Tabs: Trang đăng ký\n  Disabled Automatic Fetching: Bạn đã vô hiệu hóa tự động tải đăng ký. Hãy tải lại danh sách đăng ký để xem chúng tại đây.\n  All Subscription Tabs Hidden: Tất cả các trang đăng ký đăng bị ẩn. Để xem nội dung ở đây, vui lòng bỏ ẩn một số trang ở trong mục \"{subsection}\" của \"{settingsSection}\".\n  Load More Posts: Tải thêm bài đăng\n  Empty Channels: Các kênh bạn đăng ký hiện chưa đăng video nào.\n  Empty Posts: Các kênh bạn đăng ký hiện chưa đăng bài đăng nào.\nTrending:\n  Trending: 'Xu hướng'\n  Gaming: Trò chơi\n  Trending Tabs: Trang Xu hướng\n  Sports: Thể thao\nMost Popular: 'Phổ biến nhất'\nPlaylists: 'Danh sách phát'\nUser Playlists:\n  Your Playlists: 'Danh sách phát của bạn'\n  Search bar placeholder: Tìm kiếm danh sách phát\n  Empty Search Message: Không có video nào trong danh sách phát này trùng với những gì bạn đang tìm\n  Remove from Playlist: Xóa khỏi danh sách phát\n  Playlist Name: Tên danh sách phát\n  Save Changes: Lưu thay đổi\n  Remove Watched Videos: Xóa video đã xem\n  Sort By:\n    LatestUpdatedFirst: Ngày cập nhật (Mới nhất)\n    LatestPlayedFirst: Ngày chơi (Mới nhất)\n    EarliestUpdatedFirst: Ngày cập nhật (Cũ nhất)\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: Ngày tạo (Mới nhất)\n    EarliestCreatedFirst: Ngày tạo (Cũ nhất)\n    EarliestPlayedFirst: Ngày chơi (Cũ nhất)\n  SinglePlaylistView:\n    Toast:\n      Video has been removed: Video đã được xóa\n      There was an issue with updating this playlist.: Đã có vấn đề xảy ra trong khi cập nhập danh sách phát.\n      Reverted to use {oldPlaylistName} for quick bookmark: Đã quay lại dùng {oldPlaylistName} cho dấu trang nhanh\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: Một số video trong danh sách phát này chưa được tải, bạn vẫn có thể nhấn vào đây để sao chép.\n      This playlist is protected and cannot be removed.: Danh sách phát này được bảo vệ và không thể bị xóa.\n      Playlist {playlistName} has been deleted.: Danh sách phát {playlistName} đã được xóa.\n      This playlist does not exist: Danh sách phát này không tồn tại\n      This video cannot be moved up.: Video này không thể được chuyển lên.\n      This video cannot be moved down.: Video này không thể được chuyển xuống.\n      There was a problem with removing this video: Đã có vấn để xảy ra trong khi xóa video này\n      This playlist is now used for quick bookmark: Danh sách này giờ đang được dùng để tạo dấu trang nhanh\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Danh sách này giờ đang được dùng để tạo dấu trang nhanh thay vì {oldPlaylistName}. Nhấn đây để hoàn tác\n      Playlist name cannot be empty. Please input a name.: Tên danh sách phát không thể để trống. Vui lòng nhập một tên.\n      Playlist has been updated.: Danh sách phát đã được cập nhật.\n      \"{videoCount} video(s) have been removed\": 1 video đã được xóa | {videoCount} video đã được xóa\n      There were no videos to remove.: Không có video nào để xóa.\n      This playlist is already being used for quick bookmark.: Danh sách phát này đã được dùng cho dấu trang nhanh rồi.\n      This playlist has a video with a duration error: Danh sách phát này có chứa một video trở lên không có thông tin thời lượng và sẽ được coi như thời lượng bằng không.\n      Video has been removed. Click here to undo.: Video đã được xóa. Nhấn vào đây để hoàn tác.\n    Search for Videos: Tìm kiếm video\n  You have no playlists. Click on the create new playlist button to create a new one.: Bạn đang không có danh sách phát nào. Nhấn vào nút tạo danh sách phát mới để tạo một cái mới.\n  This playlist currently has no videos.: Danh sách phát này hiện không có video nào.\n  Edit Playlist Info: Chỉnh sửa thông tin danh sách phát\n  Are you sure you want to delete this playlist? This cannot be undone: Bạn có chắc muốn xóa danh sách phát này? Việc này sẽ không thể được hoàn tác.\n  CreatePlaylistPrompt:\n    Create: Tạo mới\n    Toast:\n      Playlist {playlistName} has been successfully created.: Danh sách phát {playlistName} đã được tạo thành công.\n      There was an issue with creating the playlist.: Đã có vấn đề xảy ra trong khi tạo danh sách phát này.\n      There is already a playlist with this name. Please pick a different name.: Hiện đã có danh sách phát với tên này rồi. Vui lòng chọn một cái tên khác.\n    New Playlist Name: Tên danh sách phát mới\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: Chọn một danh sách phát để lưu video này vào | Chọn một danh sách phát để lưu {videoCount} video này vào\n    N playlists selected: Đã chọn {playlistCount}\n    Search in Playlists: Tìm trong danh sách phát\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"(Các) Video đã được thêm vào 1 danh sách phát | (Các) Video đã được thêm vào danh sách phát {playlistCount}\"\n      You haven't selected any playlist yet.: Bạn đang chưa chọn danh sách phát nào.\n    Save: Lưu\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": '{videoCount}/{totalVideoCount} đã có trong danh sách phát'\n    Added {count} Times: Đã được thêm | Đã được thêm {count} lần\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": '{videoCount}/{totalVideoCount} video sẽ được thêm'\n    Allow Adding Duplicate Video(s): Cho phép thêm video trùng lặp\n  Create New Playlist: Tạo danh sách phat mới\n  Playlist Description: Mô tả danh sách phát\n  Copy Playlist: Sao chép danh sách phát\n  Enable Quick Bookmark With This Playlist: Bật dấu trang nhanh với danh sách phát này\n  Add to Playlist: Thêm vào danh sách phát\n  Cancel: Hủy bỏ\n  Add to Favorites: Thêm vào {playlistName}\n  Remove from Favorites: Xóa khỏi {playlistName}\n  Move Video Down: Chuyển video xuống\n  Move Video Up: Chuyển video lên\n  Delete Playlist: Xóa danh sách phát\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Bạn có chắc muốn loại bỏ {playlistItemCount} video trùng lặp khỏi danh sách phát này không? Việc này sẽ không thể được hoàn tác.\n  Cannot delete the quick bookmark target playlist.: Không thể xóa danh sách phát vì nó được dùng cho dấu trang nhanh.\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Bạn có chắc muốn loại bỏ {playlistItemCount} video đã xem khỏi danh sách phát này không? Việc này sẽ không thể được hoàn tác.\n  Quick Bookmark Enabled: Dấu trang nhanh đã bật\n  Remove Duplicate Videos: Loại bỏ các video trùng lặp\n  Playlists with Matching Videos: Bao gồm video trong danh sách phát\n  Export Playlist: Xuất danh sách phát này\n  The playlist has been successfully exported: Đã xuất thành công danh sách phát này\n  TotalTimePlaylist: 'Tổng thời lượng: {duration}'\n  Export list of URLs: Xuất danh sách URL\nHistory:\n  # On History Page\n  History: 'Lịch sử'\n  Watch History: 'Lịch sử xem'\n  Your history list is currently empty.: Lịch sử của bạn hiện đang trống.\n  Search bar placeholder: Tìm trong lịch sử\n  Empty Search Message: Không có video nào trong lịch sử của bạn khớp với tìm kiếm của bạn\n  Case Sensitive Search: Phân biệt hoa thường\n  DateOldestHistory: Ngày xem (Cũ nhất)\n  DateNewestHistory: Ngày xem (Mới nhất)\nSettings:\n  # On Settings Page\n  Settings: 'Cài đặt'\n  General Settings:\n    General Settings: 'Chung'\n    Fallback to Non-Preferred Backend on Failure: 'Trở về Backend không mong muốn khi có lỗi'\n    Enable Search Suggestions: 'Bật gợi ý tìm kiếm'\n    Default Landing Page: 'Trang mặc định'\n    Locale Preference: 'Ngôn ngữ'\n    Preferred API Backend:\n      Preferred API Backend: 'API Backend'\n      Local API: 'API địa phương'\n      Invidious API: 'API Invidious'\n    Video View Type:\n      Video View Type: 'Kiểu xem video'\n      Grid: 'Lưới'\n      List: 'Danh sách'\n    Thumbnail Preference:\n      Thumbnail Preference: 'Thumbnail'\n      Default: 'Mặc định'\n      Beginning: 'Đầu'\n      Middle: 'Giữa'\n      End: 'Cuối'\n      Blur: Làm mờ\n      Hidden: Ẩn\n    Region for Trending: 'Phổ biến theo quốc gia'\n        #! List countries\n    Check for Latest Blog Posts: Kiểm tra bài đăng mới nhất\n    Check for Updates: Kiểm tra cập nhật\n    Current Invidious Instance: Phiên bản Invidious hiện tại\n    The currently set default instance is {instance}: Phiên bản Invidious mặc định hiện được đặt thành {instance}\n    No default instance has been set: Không có phiên bản mặc định nào được đặt\n    Current instance will be randomized on startup: Phiên bản hiện tại sẽ được chọn ngẫu nhiên khi khởi động\n    Set Current Instance as Default: Đặt Phiên bản hiện tại làm Mặc định\n    Clear Default Instance: Xóa phiên bản mặc định\n    External Link Handling:\n      Open Link: Mở liên kết\n      Ask Before Opening Link: Hỏi trước khi mở liên kết\n      No Action: Không hành động\n      External Link Handling: Xử lý liên kết bên ngoài\n    View all Invidious instance information: Xem tất cả thông tin phiên bản Invidious\n    System Default: Mặc định hệ thống\n    Auto Load Next Page:\n      Tooltip: Tự động tải các trang video và bình luận.\n      Label: Tự động nhấn tải thêm\n    Open Deep Links In New Window: Mở các URL được truyền đến FreeTube vào cửa sổ mới\n    Minimize to system tray: Thu nhỏ xuống khay hệ thống\n  Theme Settings:\n    Theme Settings: 'Chủ đề'\n    Match Top Bar with Main Color: 'Khớp thanh trên cùng với màu chính'\n    Base Theme:\n      Base Theme: 'Chủ đề mặc định'\n      Black: 'Đen'\n      Dark: 'Tối'\n      Light: 'Sáng'\n      Dracula: 'Dracula'\n      System Default: Mặc định hệ thống\n      Catppuccin Mocha: Catppuccin Mocha\n      Nordic: Nordic\n      Pastel Pink: Hồng phấn tiên\n      Hot Pink: Hồng nóng bỏng\n      Solarized Dark: Solarized Tối\n      Solarized Light: Solarized Sáng\n      Gruvbox Dark: Gruvbox Tối\n      Gruvbox Light: Gruvbox Sáng\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Low: Rừng tối Everforest thấp\n      Everforest Light Low: Ánh sáng Everforest thấp\n      Everforest Dark Hard: Everforest Dark Cứng\n      Everforest Dark Medium: Everforest tối trung bình\n      Everforest Light Hard: Everforest Nhẹ Cứng\n      Everforest Light Medium: Everforest Light trung bình\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: 'Màu chủ đề chính'\n      Red: 'Đỏ'\n      Pink: 'Hồng'\n      Purple: 'Tím'\n      Deep Purple: 'Tím đậm'\n      Indigo: 'Chàm'\n      Blue: 'Xanh lam'\n      Light Blue: 'Xanh nước biển'\n      Cyan: 'Xanh lơ'\n      Teal: 'Xanh mòng két'\n      Green: 'Xanh lục'\n      Light Green: 'Xanh lợt'\n      Lime: 'Vàng chanh'\n      Yellow: 'Vàng'\n      Amber: 'Hổ phách'\n      Orange: 'Cam'\n      Deep Orange: 'Cam đậm'\n      Dracula Cyan: 'Xanh lơ Dracula'\n      Dracula Green: 'Xanh lục Dracula'\n      Dracula Orange: 'Cam Dracula'\n      Dracula Pink: 'Hồng Dracula'\n      Dracula Purple: 'Tím Dracula'\n      Dracula Red: 'Đỏ Dracula'\n      Dracula Yellow: 'Vàng Dracula'\n      Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater Màu hoa hồng\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo Màu hồng hạc\n      Catppuccin Mocha Pink: Catppuccin Mocha Pink Màu hồng hạc\n      Catppuccin Mocha Mauve: Catppuccin Mocha Mauve - Màu tím\n      Catppuccin Mocha Red: Catppuccin Mocha Red Màu đỏ\n      Catppuccin Mocha Maroon: Catppuccin Mocha Maroon Màu nâu tim\n      Catppuccin Mocha Peach: Catppuccin Mocha Peach Màu đào\n      Catppuccin Mocha Yellow: Catppuccin Mocha Yellow Màu vàng\n      Catppuccin Mocha Green: Catppuccin Mocha Green Màu xanh lục\n      Catppuccin Mocha Teal: Catppuccin Mocha Teal Màu mòng két\n      Catppuccin Mocha Sky: Catppuccin Mocha Sky Màu xanh da trời\n      Catppuccin Mocha Sapphire: Catppuccin Mocha Sapphire màu xanh\n      Catppuccin Mocha Lavender: Catppuccin Mocha Lavender Màu tím nhạt\n      Catppuccin Mocha Blue: Catppuccin Mocha Blue Màu xanh\n      Solarized Yellow: Solarized Vàng\n      Solarized Orange: Solarized Cam\n      Solarized Red: Solarized Đỏ\n      Gruvbox Dark Yellow: Vàng Tối Cổ Điển\n      Gruvbox Dark Blue: Xanh Biển Tối\n      Gruvbox Dark Green: Xanh Rêu Đậm\n      Catppuccin Frappe Pink: Catppuccin Frappe Hồng\n      Catppuccin Frappe Mauve: Cà phê Frappe Catppuccin màu hoa cà\n      Catppuccin Frappe Teal: Cà phê Frappe Catppuccin màu xanh ngọc\n      Catppuccin Frappe Rosewater: Nước hoa hồng Catppuccin Frappe\n      Catppuccin Frappe Flamingo: Frappe Catppuccin Flamingo\n      Catppuccin Frappe Maroon: Cà phê Frappe Catppuccin màu nâu đỏ\n      Catppuccin Frappe Sky: Bầu trời Frappe Catppuccin\n      Gruvbox Light Red: Gruvbox Đỏ nhạt\n      Gruvbox Dark Orange: Gruvbox màu cam đậm\n      Gruvbox Light Blue: Gruvbox Xanh nhạt\n      Solarized Cyan: Màu lục lam được năng lượng mặt trời\n      Solarized Magenta: Magenta đã được năng lượng mặt trời hóa\n      Solarized Violet: Violet năng lượng mặt trời\n      Catppuccin Frappe Red: Cà phê Frappe Catppuccin Đỏ\n      Everforest Light Green: Everforest Xanh nhạt\n      Everforest Dark Purple: Everforest Tím Đậm\n      Catppuccin Frappe Blue: Cà phê Frappe Catppuccin màu xanh\n      Everforest Dark Yellow: Everforest Vàng Đậm\n      Everforest Dark Green: Rừng xanh đậm Everforest\n      Solarized Blue: Xanh dương năng lượng mặt trời\n      Everforest Dark Red: Everforest Đỏ Đậm\n      Everforest Dark Orange: Everforest Màu cam đậm\n      Everforest Dark Aqua: Rừng xanh thẳm Everforest\n      Everforest Dark Blue: Rừng xanh đậm Everforest\n      Everforest Light Red: Everforest Đỏ nhạt\n      Everforest Light Orange: Everforest cam nhạt\n      Gruvbox Light Purple: Gruvbox màu tím nhạt\n      Solarized Green: Xanh năng lượng mặt trời\n      Everforest Light Yellow: Everforest Vàng nhạt\n      Everforest Light Blue: Rừng xanh nhạt Everforest\n      Everforest Light Aqua: Everforest Ánh sáng Aqua\n      Everforest Light Purple: Everforest Tím nhạt\n      Catppuccin Frappe Yellow: Cà phê Frappe Catppuccin màu vàng\n      Catppuccin Frappe Peach: Cà phê Frappe Catppuccin đào\n      Catppuccin Frappe Green: Cà phê Frappe Catppuccin Xanh\n      Catppuccin Frappe Sapphire: Cà phê đá xay Catppuccin Sapphire\n      Catppuccin Frappe Lavender: Cà phê Frappe Catppuccin Hoa Oải Hương\n      Gruvbox Dark Purple: Gruvbox Tím Đậm\n      Gruvbox Dark Aqua: Gruvbox màu tối Aqua\n      Gruvbox Light Orange: Gruvbox màu cam nhạt\n      Catppuccin Latte Mauve: Catppuccin Latte Cẩm quỳ\n      Catppuccin Latte Red: Catppuccin Latte Đỏ\n    Secondary Color Theme: 'Màu chủ đề phụ'\n        #* Main Color Theme\n    UI Scale: Tỉ lệ UI\n    Disable Smooth Scrolling: Tắt cuộn mượt\n    Expand Side Bar by Default: Mở rộng thanh bên theo mặc định\n    Hide Side Bar Labels: Ẩn nhãn thanh bên\n    Hide FreeTube Header Logo: Ẩn logo FreeTube trên thanh trên\n  Player Settings:\n    Player Settings: 'Trình phát'\n    Play Next Video: 'Tự động phát video được đề xuất'\n    Turn on Subtitles by Default: 'Bật phụ đề theo mặc định'\n    Autoplay Videos: 'Tự phát video'\n    Proxy Videos Through Invidious: 'Proxy video qua Invidious'\n    Autoplay Playlists: 'Tự động phát danh sách phát Video'\n    Enable Theatre Mode by Default: 'Bật chế độ rạp hát theo mặc định'\n    Default Volume: 'Âm lượng mặc định'\n    Default Playback Rate: 'Tốc độ phát mặc định'\n    Default Video Format:\n      Default Video Format: 'Định dạng video mặc định'\n      Dash Formats: 'Định dạng DASH'\n      Legacy Formats: 'Định dạng Legacy'\n      Audio Formats: 'Định dạng âm thanh'\n    Default Quality:\n      Default Quality: 'Chất lượng mặc định'\n      Auto: 'Tự động'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Scroll Playback Rate Over Video Player: Con lăn chuột điểu chỉnh tốc độ phát lại\n    Scroll Volume Over Video Player: Con lăn chuột điểu chỉnh âm lượng\n    Display Play Button In Video Player: Hiển thị nút phát trong trình phát video\n    Next Video Interval: Quãng nghỉ giữa các video tự động phát\n    Fast-Forward / Rewind Interval: Khoảng thời gian tua đi / tua lại\n    Screenshot:\n      Enable: Bật chức năng chụp màn hình\n      Format Label: Định dạng chụp màn hình\n      Quality Label: Chất lượng chụp màn hình\n      File Name Label: Mẫu tên tệp\n      Folder Label: Thư mục ảnh chụp màn hình\n      Ask Path: Yêu cầu thư mục lưu\n      Folder Button: Chọn thư mục\n      Error:\n        Empty File Name: Tên tệp trống\n        Forbidden Characters: Các ký từ bị cấm\n      File Name Tooltip: Bạn có thể dùng các biến số dưới đây. %Y Năm 4 chữ số. %M Tháng 2 chữ số. %D Ngày 2 chữ số. %H Giờ 2 chữ số. %N Phút 2 chữ số. %S Giây 2 chữ số. %T Phầm trăm giây 3 chữ số. %s Giây Video. %t Phần trăm giây Video 3 chữ số. %i Video ID.\n    Max Video Playback Rate: Tốc độ phát lại tối đa\n    Video Playback Rate Interval: Khoảng cách tốc độ phát\n    Enter Fullscreen on Display Rotate: Bật toàn màn hình khi xoay\n    Skip by Scrolling Over Video Player: Tua video bằng con lăn chuột\n    Default Viewing Mode:\n      Theater: Rạp hát\n      Default Viewing Mode: Chế độ xem mặc định\n      Full Screen: Toàn màn hình\n      Picture in Picture: Hình trong hình\n      External Player: Trình phát ngoài ({externalPlayerName})\n    Autoplay Interruption Timer: Bộ đếm thời gian ngắt tự động phát\n  Subscription Settings:\n    Subscription Settings: 'Đăng ký'\n    Fetch Feeds from RSS: Cập nhật bảng tin qua RSS\n    Fetch Automatically: Tự động làm mới bảng tin\n    Confirm Before Unsubscribing: Nhắc xác nhận trước khi hủy đăng ký\n    'Limit the number of videos displayed for each channel': Giới hạn số video được hiển thị cho mỗi kênh\n    To: Xuống\n  Data Settings:\n    How do I import my subscriptions?: Làm sao để tôi nhập đăng ký?\n    Unknown data key: Key dữ liệu không xác định\n    Unable to write file: Không thể viết tệp\n    Unable to read file: Không thể đọc tệp\n    All watched history has been successfully exported: Tất cả lịch sử xem đã được xuất ra thành công\n    All watched history has been successfully imported: Tất cả lịch sử xem đã được nhập vào thành công\n    History object has insufficient data, skipping item: Lịch sử không đủ dữ liệu, đang bỏ qua mục này\n    Subscriptions have been successfully exported: Đăng ký đã được xuất thành công\n    Invalid history file: Tệp lịch sử không hợp lệ\n    Invalid subscriptions file: Tệp đăng ký không hợp lệ\n    All subscriptions have been successfully imported: Tất cả đăng ký đã được nhập vào thành công\n    All subscriptions and profiles have been successfully imported: Tất cả các đăng ký và hồ sơ đã được nhập thành công\n    Profile object has insufficient data, skipping item: Hồ sơ không đủ dữ liệu, đang bỏ qua mục này\n    Export History: Xuất lịch sử\n    Import History: Nhập lịch sử\n    Export NewPipe: Xuất NewPipe\n    Export YouTube: Xuất YouTube\n    Export FreeTube: Xuất FreeTube\n    Export Subscriptions: Xuất đăng ký\n    Import Subscriptions: Nhập đăng ký\n    Select Export Type: Chọn kiểu xuất ra\n    Data Settings: Dữ liệu\n    Manage Subscriptions: Quản lý đăng ký\n    Import Playlists: Nhập danh sách phát\n    All playlists has been successfully imported: Tất cả các danh sách phát đã được thêm vào thành công\n    All playlists has been successfully exported: Tất cả các danh sách phát đã được xuất thành công\n    Playlist insufficient data: Dữ liệu bị thiếu cho danh sách phát \"{playlist}\", bỏ qua mục này\n    Export Playlists: Xuất danh sách phát\n    History File: Tệp lịch sử\n    Playlist File: Tệp danh sách phát\n    Subscription File: Tệp đăng ký\n    Export Playlists For Older FreeTube Versions:\n      Label: Xuất danh sách phát cho các phiên bản FreeTube cũ hơn\n      Tooltip: \"Tùy chọn này sẽ gộp tất cả các danh sách phát vào một danh sách phát mang tên 'Ưa thích'.\\nCách để nhập & xuất video trong danh sách phát cho một phiên bản cũ hơn của FreeTube:\\n1. Xuất danh sách phát với tùy chọn này được bật.\\n2. Xóa tất cả các danh sách phát qua tùy chọn Xóa tất cả danh sách phát trong mục Cài đặt quyền riêng tư.\\n3. Mở phiên bản cũ hơn và nhập danh sách phát đã được xuất ra.\"\n    Search history: Lịch sử tìm kiếm\n    Import search history: Nhập lịch sử tìm kiếm\n    Export search history: Xuất lịch sử tìm kiếm\n    All search history has been successfully imported: Tất cả lịch sử tìm kiếm đã được nhập thành công\n    All search history has been successfully exported: Toàn bộ lịch sử tìm kiếm đã được xuất thành công\n    Search history file: Tập tin lịch sử tìm kiếm\n  Distraction Free Settings:\n    Hide Live Chat: Ẩn chat trực tiếp\n    Hide Popular Videos: Ẩn video phổ biến\n    Hide Trending Videos: Ẩn video xu hướng\n    Hide Recommended Videos: Ẩn video tiếp theo\n    Hide Comment Likes: Ẩn lượt thích bình luận\n    Hide Channel Subscribers: Ẩn số người đăng ký\n    Hide Video Likes And Dislikes: Ẩn lượt thích và không thích\n    Hide Video Views: Ẩn lượt xem\n    Distraction Free Settings: Giảm phân tâm\n    Hide Active Subscriptions: Ẩn đăng ký hiện hoạt\n    Hide Playlists: Ẩn danh sách phát\n    Hide Comments: Ẩn bình luận\n    Hide Live Streams: Ẩn phát trực tiếp\n    Hide Video Description: Ẩn mô tả video\n    Hide Sharing Actions: Ẩn nút chia sẻ\n    Hide Videos on Watch: 'Ẩn video khi đã xem'\n    Sections:\n      General: Chung\n      Side Bar: Thanh bên\n      Channel Page: Trang kênh\n      Subscriptions Page: Trang đăng ký\n      Watch Page: Trang trình chiếu video\n    Hide Channel Playlists: Ẩn trang \"Danh sách phát\" của kênh\n    Hide Featured Channels: Ẩn các kênh nổi bật\n    Hide Channels Placeholder: ID kênh\n    Hide Profile Pictures in Comments: Ẩn ảnh đại diện trong bình luận\n    Hide Chapters: Ẩn các chương\n    Hide Channels: Ẩn video từ các kênh\n    Hide Channel Releases: Ẩn trang \"Xuất bản\" của kênh\n    Hide Videos, Playlists and Channels Containing Text: Ẩn các video và danh sách phát có chứa\n    Hide Channels Invalid: ID kênh không hợp lệ\n    Hide Channel Shorts: Ẩn trang \"Shorts\" của kênh\n    Hide Subscriptions Shorts: Ẩn short từ các đăng ký\n    Hide Subscriptions Live: Ẩn video phát trực tiếp từ các đăng ký\n    Hide Upcoming Premieres: Ẩn video sắp ra mắt\n    Hide Channel Podcasts: Ẩn trang \"Podcast\" của kênh\n    Hide Channels Already Exists: ID kênh đã tồn tại\n    Hide Videos, Playlists and Channels Containing Text Placeholder: Từ, tiếng, hoặc cụm từ\n    Hide Subscriptions Videos: Ẩn video từ các đăng ký\n    Display Titles Without Excessive Capitalisation: Hiển thị tiêu đề không viết hoa quá mức\n    Show Added Items: Hiện các mục đã thêm\n    Hide Channel Home: Ẩn \"Trang chủ\" của kênh\n    Hide Channels API Error: Có lỗi khi truy xuất người dùng có ID đã cung cấp. Vui lòng kiểm tra lại xem ID có đúng không.\n    Hide Channels Disabled Message: Một số kênh đã bị chặn bằng ID và không được xử lý. Tính năng bị chặn trong khi các ID đó đang cập nhật\n    Hide Channel Courses: Ẩn Tab \"Khóa học\" của Kênh\n    Hide Subscriptions Posts: Ẩn bài đăng đăng ký\n    Hide Channel Posts: Ẩn tab \"Bài đăng\" của kênh\n  Privacy Settings:\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: Bạn có muốn xóa toàn bộ đăng ký và hồ sơ không? Điều này không thể phục hồi.\n    Remove All Subscriptions / Profiles: Xóa tất cả đăng ký / hồ sơ\n    Watch history has been cleared: Lịch sử xem đã được xóa\n    Are you sure you want to remove your entire watch history?: Bạn có thực sự muốn xóa toàn bộ lịch sử xem?\n    Remove Watch History: Xóa lịch sử xem\n    Search cache has been cleared: Bộ đệm của tìm kiếm đã xóa\n    Are you sure you want to clear out your search cache?: Bạn có chắc là muốn xóa bộ đệm của tìm kiếm?\n    Clear Search Cache: Xóa cache tìm kiếm\n    Save Watched Progress: Lưu quá trình xem\n    Remember History: Nhớ lịch sử xem\n    Privacy Settings: Quyền riêng tư\n    Remove All Playlists: Xóa tất cả danh sách phát\n    Are you sure you want to remove all your playlists?: Bạn có chắc muốn xóa tất cả các danh sách phát không?\n    All playlists have been removed: Đã xóa tất cả các danh sách phát\n    Save Watched Videos With Last Viewed Playlist: Lưu video đã xem với danh sách phát được xem lần cuối\n    Remember Search History: Nhớ lịch sử tìm kiếm\n    Clear Search History and Cache: Xóa lịch sử tìm kiếm và bộ đệm\n    Are you sure you want to clear out your search history and cache?: Bạn có chắc muốn xóa lịch sử tìm kiếm và bộ đệm của bạn?\n    Search history and cache have been cleared: Đã xóa lịch sử tìm kiếm và bộ đệm\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: Tự động\n        Semi-auto: Bán tự động\n        Never: Không\n      Tooltip: 'Tự động = Lưu mỗi khi thoát khỏi trang video, khi video kết thúc và gặp lỗi (ví dụ: giới hạn tốc độ và phiên xem đã hết hạn). Bán tự động = Như tự động, trừ lúc thoát khỏi trang video và có thể lưu tiến trình theo cách thủ công thông qua nút Lưu tiến trình đã xem, nằm bên dưới trình phát video.'\n  The app needs to restart for changes to take effect. Restart and apply change?: Ứng dụng cần được khởi động lại để chỉnh sửa có hiệu nghiệm. Khởi động lại và áp dụng cài đặt?\n  Proxy Settings:\n    Proxy Host: Máy chủ proxy\n    Region: Vùng\n    Country: Quốc gia\n    Proxy Settings: Proxy\n    Enable Tor / Proxy: Bật Tor / Proxy\n    Proxy Protocol: Giao thức proxy\n    Proxy Port Number: Số cổng proxy\n    City: Thành phố\n    Ip: IP\n    Your Info: Thông tin của bạn\n    Error getting network information. Is your proxy configured properly?: Lỗi nhận thông tin mạng. Proxy của bạn đã được cài đặc đúng cách chưa?\n    Clicking on Test Proxy will send a request to: Nhấn vào Thử proxy sẽ gửi yêu cầu đến\n    Test Proxy: Thử proxy\n    Proxy Warning: FreeTube không bao gồm proxy theo mặc định nhưng có thể kết nối đến một proxy bên ngoài, bao gồm các proxy chạy cục bộ như Tor hoặc các proxy SOCKS5 được cung cấp bởi một số các VPN. Nếu bạn sử dụng tính năng này, hãy đảm bảo proxy/Tor của bạn được cấu hình đúng cách, nếu không FreeTube sẽ không thể tải dữ liệu về được.\n    Proxy Username: Tên người dùng ủy quyền\n    Proxy Password: Mật khẩu Proxy\n  SponsorBlock Settings:\n    Enable SponsorBlock: Bật SponsorBlock\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL API SponsorBlock (Mặc định là https://sponsor.ajay.app)\n    Skip Options:\n      Skip Option: Tuỳ chọn bỏ qua\n      Show In Seek Bar: Hiển thị trong thanh tiến trình\n      Auto Skip: Tự động bỏ qua\n      Prompt To Skip: Nhắc nhở bỏ qua\n      Do Nothing: Không làm gì\n    Notify when sponsor segment is skipped: Thông báo khi đoạn quảng cáo bị bỏ qua\n    Category Color: Bản màu\n    SponsorBlock Settings: SponsorBlock\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': URL API ảnh xem trước DeArrow (Mặc định là https://dearrow-thumb.ajay.app)\n    UseDeArrowTitles: Dùng tiêu đề video từ DeArrow\n    UseDeArrowThumbnails: Dùng ảnh xem trước từ DeArrow\n  External Player Settings:\n    External Player Settings: Trình phát video bên ngoài\n    External Player: Trình phát video bên ngoài\n    Custom External Player Arguments: Tham số trình phát bên ngoài tùy chỉnh\n    Ignore Unsupported Action Warnings: Bỏ qua các cảnh bảo tác vụ không được hổ trợ\n    Custom External Player Executable: Chạy trình phát bên ngoài tuỳ chỉnh\n    Players:\n      None:\n        Name: Trống\n    Ignore Default Arguments: Bỏ qua tham số mặc định\n  Parental Control Settings:\n    Parental Control Settings: Kiểm soát của phụ huynh\n    Hide Unsubscribe Button: Ẩn nút huỷ đăng ký\n    Show Family Friendly Only: Chỉ hiển thị nội dung thân thiện với gia đình\n    Hide Search Bar: Ẩn thanh tìm kiếm\n    Hide Uploader on Watch page: Ẩn Người tải lên trên trang Xem\n  Password Dialog:\n    Password: Mật khẩu\n    Enter Password To Unlock: Nhập mật khẩu để mở cài đặt\n  Password Settings:\n    Set Password To Prevent Access: Đặt mặt khẩu để ngăn truy cập cài đặt\n    Password Settings: Mật khẩu\n    Remove Password: Xoá mật khẩu\n    Set Password: Đặt mật khẩu\n  Experimental Settings:\n    Warning: Những cài đặt này đều đang trong quá trình thử nghiệm, bật các tùy chọn cài đặt này có thể gây ra hoạt động bất ổn định. Hãy tạo phương án dự phòng trước khi bật!\n    Experimental Settings: Thử nghiệm\n    Replace HTTP Cache: Thay thế bộ đệm HTTP\n  Return to Settings Menu: Quay lại menu Cài đặt\n  Sort Settings Sections (A-Z): Sắp xếp các mục cài đặt (A-Z)\nAbout:\n  #On About page\n  About: 'Giới thiệu'\n  #& About\n#On Channel Page\n  Mastodon: Mastodon\n  Email: Email\n  Source code: Mã nguồn\n  FAQ: Câu hỏi thường gặp\n  Report a problem: Báo cáo sự cố\n  Help: Trợ giúp\n  Translate: Phiên dịch\n  Website: Trang web\n  Blog: Blog\n  Credits: Ghi công\n  Donate: Quyên tặng\n  GitHub issues: Sự cố GitHub\n  FreeTube Wiki: FreeTube Wiki\n  Beta: Thử nghiệm\n  Downloads / Changelog: Tải xuống / nhật ký thay đổi\n  GitHub releases: Bản phát hành GitHub\n  Please check for duplicates before posting: Vui lòng kiểm tra trùng lặp trước khi đăng\n  Chat on Matrix: Trò chuyện trên Matrix\n  room rules: quy định phòng chat\n  these people and projects: những người và dự án này\n  Discussions: Thảo luận\n  AGPLv3: giấy phép AGPLv3\nChannel:\n  Subscribe: 'Đăng ký'\n  Unsubscribe: 'Hủy đăng ký'\n  Search Channel: 'Tìm trong kênh'\n  Your search results have returned 0 results: 'Kết quả tìm kiếm của bạn là 0 kết quả'\n  Videos:\n    Videos: 'Video'\n    This channel does not currently have any videos: 'Kênh này hiện chưa có video'\n    Sort Types:\n      Newest: 'Mới nhất'\n      Oldest: 'Cũ nhất'\n      Most Popular: 'Phổ biến nhất'\n  Playlists:\n    Playlists: 'Danh sách phát'\n    This channel does not currently have any playlists: 'Kênh này hiện chưa có danh sách phát'\n    Sort Types:\n      Last Video Added: 'Video được thêm cuối cùng'\n      Newest: 'Mới nhất'\n      Oldest: 'Cũ nhất'\n  About:\n    About: 'Giới thiệu'\n    Channel Description: 'Miêu tả kênh'\n    Featured Channels: 'Kênh đặc sắc'\n    Tags:\n      Search for: Tìm kiếm cho \"{tag}\"\n      Tags: Thẻ\n    Joined: Đã tham gia\n    Location: Vị trí\n    Details: Chi tiết\n  Added channel to your subscriptions: Đã thêm kênh vào đăng ký của bạn\n  Removed subscription from {count} other channel(s): Đã xóa đăng ký từ {count} các kênh khác\n  Channel has been removed from your subscriptions: Kênh đã được xóa khỏi đăng ký của bạn\n  Live:\n    Live: Trực tiếp\n    This channel does not currently have any live streams: Kênh này hiện không có bất kì luồng phát trực tiếp nào\n  This channel does not allow searching: Kênh này không cho phép tìm kiếm\n  This channel does not exist: Kênh không tồn tại\n  Posts:\n    Posts: Bài đăng\n    This channel currently does not have any posts: Kênh này hiện không có bất kì bài đăng nào\n    votes: '{votes} bình chọn'\n    Reveal Answers: Hiện Câu trả lời\n    Hide Answers: Ẩn Câu trả lời\n    Video hidden by FreeTube: FreeTube đã ẩn video này\n    View Full Post: Mở rộng bài đăng\n    Viewing Posts Only Supported By Invidious: Việc xem các bài đăng chỉ được hỗ trợ qua Invidious. Hãy đi đến trang Cộng đồng của kênh để xem nội dung này mà không cần Invidious.\n  Releases:\n    Releases: Xuất bản\n    This channel does not currently have any releases: Kênh này hiện không có bất kỳ bản phát hành nào\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: Kênh này là kênh giới hạn độ tuổi và hiện tại không thể xem được trên FreeTube.\n  Channel Tabs: Trang kênh\n  Shorts:\n    This channel does not currently have any shorts: Kênh này hiện không có video shorts\n  Podcasts:\n    Podcasts: Podcast\n    This channel does not currently have any podcasts: Kênh này hiện không có podcast nào\n  Home:\n    Home: Trang chủ\n    View Playlist: Xem danh sách phát\n  Courses:\n    Courses: Các khóa học\n    This channel does not currently have any courses: Kênh này hiện không có khóa học nào\nVideo:\n  Open in YouTube: 'Mở trong Youtube'\n  Copy YouTube Link: 'Sao chép liên kết Youtube'\n  Open YouTube Embedded Player: 'Mở trình phát Youtube Embedded'\n  Copy YouTube Embedded Player Link: 'Sao chép liên kết trình phát YouTube đã được nhúng vào'\n  Open in Invidious: 'Mở trong Invidious'\n  Copy Invidious Link: 'Sao chép liên kết Invidious'\n  Views: 'Lượt xem'\n  Watched: 'Đã xem'\n  # As in a Live Video\n  Live: 'Trực tiếp'\n  Live Now: 'Đang trực tiếp'\n  Live Chat: 'Chat trực tiếp'\n  Enable Live Chat: 'Bật chat trực tiếp'\n  Live Chat is currently not supported in this build.: 'Chat trực tiếp không được hỗ trợ trong bản build này.'\n  Live chat is enabled. Chat messages will appear here once sent.: 'Chat trực tiếp đã bật. Thông điệp chat sẽ hiện ra ở đây khi gửi.'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Chat trực tiếp hiện tại không hỗ trợ với Invidious API. Một đường truyền trực tiếp đến Youtube là cần thiết.'\n  Published:\n    In less than a minute: Trong khoảng ít hơn 1 phút\n  Published on: 'Phát hành vào'\n#& Videos\n  Video has been removed from your history: Video đã được xóa khỏi lịch sử của bạn\n  Video has been marked as watched: Video đánh dấu đã xem\n  Remove From History: Xóa khỏi lịch sử\n  Mark As Watched: Đánh dấu đã xem\n  Starting soon, please refresh the page to check again: Sắp bắt đầu, vui lòng refresh trang để kiểm tra\n  Autoplay: Tự động phát\n  Previous: Trước\n  Next: Tiếp theo\n  Reverse Playlist: Đảo ngược danh sách phát\n  Shuffle Playlist: Trộn danh sách phát\n  Loop Playlist: Lặp lại danh sách phát\n  Open Channel in YouTube: Mở kênh này trên YouTube\n  Copy YouTube Channel Link: Sao chép liên kết của kênh\n  Sponsor Block category:\n    sponsor: Nhà tài trợ\n    intro: Giới thiệu\n    self-promotion: Tự thúc đẩy\n    interaction: Tương tác\n    music offtopic: Nhạc ngoại tuyến\n    outro: Kết thúc\n    recap: Tóm tắt\n    filler: Bộ lọc\n  Streamed on: Phát trực tiếp vào lúc\n  Started streaming on: Bắt đầu phát trực tiếp vào lúc\n  External Player:\n    playlist: danh sách phát\n    Unsupported Actions:\n      opening specific video in a playlist (falling back to opening the video): mở video cụ thể trong danh sách phát (quay lại mục mở video)\n      setting a playback rate: Đặt tốc độ tua lại\n      opening playlists: mở danh sách phát\n      starting video at offset: Bắt đầu video ở khoản giữa\n      shuffling playlists: xáo trộn danh sách phát\n      reversing playlists: đảo ngược danh sách phát\n      looping playlists: lập lại danh sách phát\n    OpeningTemplate: Mở {videoOrPlaylist} trong {externalPlayer}....\n    UnsupportedActionTemplate: '{externalPlayer} không hổ trợ: {action}'\n    OpenInTemplate: Mở trong {externalPlayer}\n    video: video\n  Open Channel in Invidious: Mở kênh ưu tiên\n  Copy Invidious Channel Link: Sao chép liên kết kênh Invidious\n  Video has been removed from your saved list: Video đã bị xoá khỏi danh sách lưu trữ của bạn\n  Video has been saved: Video đã được lưu\n  Save Video: Lưu Video\n  Scroll to Bottom: Cuộn xuống dưới\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Trò chuyện trực tiếp hiện không khả dụng trên luồng phát này. Chủ sở hữu có thể đã tắt chức năng này.\n  Hide Channel: Ẩn kênh này\n  More Options: Tùy chọn khác\n  Show Super Chat Comment: Hiển thị bình luận Super Chat\n  Upcoming: Sắp ra mắt\n  Premieres: Công chiếu\n  Unhide Channel: Hiển thị kênh này\n  Player:\n    Show Stats: Hiện thông tin nâng cao\n    Hide Stats: Ẩn thông tin nâng cao\n    Stats:\n      CodecsVideoAudio: 'Codec: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'\n      CodecsVideoAudioNoItags: 'Codec: {videoCodec} / {audioCodec}'\n      Bandwidth: 'Băng thông: {bandwidth} kbps'\n      Resolution: 'Độ phân giải: {width}x{height}{''@''}{frameRate}'\n      Player Dimensions: 'Kích thước trình xem: {width}x{height}'\n      CodecAudio: 'Codec: {audioCodec} ({audioItag})'\n      Bitrate: 'Tốc độ bit: {bitrate} kbps'\n      Volume: 'Âm lượng: {volumePercentage}%'\n      Buffered: 'Đã tải trước: {bufferedPercentage}%'\n      Video ID: 'ID video: {videoId}'\n      Stats: Thông tin nâng cao\n      Media Formats: 'Định dạng: {formats}'\n      Dropped Frames / Total Frames: 'Khung bị bỏ: {droppedFrames} / tổng số khung: {totalFrames}'\n    Skipped segment: Đã bỏ qua phân đoạn {segmentCategory}\n    You appear to be offline: Bạn có vẻ đang offline.\n    Playback will resume automatically when your connection comes back: Trình phát sẽ tự động tiếp tục khi bạn kết nối trở lại.\n    TranslatedCaptionTemplate: '{language} (được dịch từ \"{originalLanguage}\")'\n    Audio Tracks: Rãnh âm thanh\n    Theatre Mode: Chế độ rạp hát\n    Exit Theatre Mode: Thoát chế độ rạp hát\n    Full Window: Toàn cửa sổ\n    Exit Full Window: Thoát toàn cửa sổ\n    Take Screenshot: Chụp ảnh màn hình\n    Autoplay is off: Tự động phát đang tắt\n    Autoplay is on: Tự động phát đang bật\n  MembersOnly: Các video trả phí không thể được xem qua FreeTube vì chúng yêu cầu đăng nhập qua một tài khoản Google có đăng kí trả phí với kênh đã đăng các video đó.\n  AgeRestricted: Các video giới hạn độ tuổi không thể được xem qua FreeTube vì chúng yêu cầu đăng nhập qua Google và sử dụng một tài khoản YouTube đã được xác minh độ tuổi.\n  IP block: YouTube đang chặn địa chị IP của bạn khỏi việc xem video. Hãy thử sử dụng một VPN hoặc proxy khác.\n  DeArrow:\n    Show Modified Details: Hiện thông tin đã sửa đổi\n    Show Original Details: Hiện thông tin gốc\n#& Playlists\n  Unlisted: Không liệt kê\n  DRMProtected: Không thể phát video được bảo vệ DRM trong FreeTube vì chúng yêu cầu các thành phần nguồn đóng độc quyền. Nếu bạn muốn xem video này, vui lòng xem trên trang web chính thức của YouTube trong trình duyệt web hỗ trợ DRM.\n  Save Watched Progress: Lưu tiến trình đã xem\n  Watched Progress Saved: Xem tiến trình đã lưu\n  Popout Live Chat: Trò chuyện bật lên\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 'Thời gian quảng cáo đầu video còn lại: {remindingTimeSeconds}s'\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 'Thời gian chờ SABR còn lại: {remindingTimeSeconds}s'\nPlaylist:\n  #& About\n  View Full Playlist: 'Xem danh sách phát hoàn chỉnh'\n  Last Updated On: 'Update lần cuối vào'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: Danh sách phát\n  Sort By:\n    VideoDurationAscending: Thời lượng (Ngắn nhất)\n    DateAddedOldest: Ngày thêm (Cũ nhất)\n    AuthorDescending: Tác giả (Z-A)\n    VideoTitleAscending: Tiêu đề (A-Z)\n    VideoDurationDescending: Thời lượng (Dài nhất)\n    Custom: Tùy chỉnh\n    AuthorAscending: Tác giả (A-Z)\n    DateAddedNewest: Ngày thêm (Mới nhất)\n    VideoTitleDescending: Tiêu đề (Z-A)\n    PublishedNewest: Ngày xuất bản (Mới nhất)\n    PublishedOldest: Ngày xuất bản (Cũ nhất)\nChange Format:\n  Change Media Formats: 'Chuyển đổi định dạng video'\n  Use Dash Formats: 'Sử dụng định dạng DASH'\n  Use Legacy Formats: 'Sử dụng định dạng Legacy'\n  Use Audio Formats: 'Sử dụng dịnh đạng Âm Thanh'\n  Audio formats are not available for this video: Định dạng âm thanh không có sẵn cho video này\n  Dash formats are not available for this video: Định dạng DASH không có sẵn cho video này\n  Legacy formats are not available for this video: Định dạng legacy không có sẵn cho video này\nShare:\n  Share Video: 'Chia sẻ video'\n  Share Playlist: 'Chia sẻ danh sách phát'\n  Copy Link: 'Sao chép liên kết'\n  Open Link: 'Mở liên kết'\n  Copy Embed: 'Sao chép đã nhúng'\n  Open Embed: 'Mở đã nhúng'\n  # On Click\n  Invidious URL copied to clipboard: 'Invidious URL sao chép đến bộ nhớ tạm'\n  Invidious Embed URL copied to clipboard: 'Invidious Embed URL sao chép đến bộ nhớ tạm'\n  YouTube URL copied to clipboard: 'Youtube URL sao chép đến clipboard'\n  YouTube Embed URL copied to clipboard: 'Youtube Embed URL sao chép đến clipboard'\n  Include Timestamp: Có kèm dấu thời gian\n  YouTube Channel URL copied to clipboard: Đã sao chép liên kết kênh Youtube\n  Invidious Channel URL copied to clipboard: URL của kênh ưu tiên đã được sao chép\n  Share Channel: Chia sẻ kênh\n  Share Post: Chia sẻ bài viết\nMini Player: 'Trình phát Mini'\nComments:\n  Comments: 'Bình luận'\n  Click to View Comments: 'Nhấn để xem bình luận'\n  Getting comment replies, please wait: 'Đang lấy trả lời bình luận, vui lòng chờ'\n  Hide Comments: 'Ẩn bình luận'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: 'Không có bình luận nào cho video này'\n  Load More Comments: 'Tải thêm bình luận'\n  Newest first: Mới nhất trước\n  Top comments: Top bình luận\n  There are no more comments for this video: Không có bình luận cho video này\n  Member: Thành viên\n  Pinned by: Được ghim bởi\n  Show More Replies: Hiện thêm câu trả lời\n  View {replyCount} replies: Xem 1 phản hồi | Xem {replyCount} phản hồi\n  Hearted: Đã thả tim\n  Subscribed: Đã đăng ký\n  There are no comments available for this post: Không có bình luận nào cho bài đăng này\n  Hide {replyCount} replies: Ẩn 1 phản hồi | Ẩn {replyCount} phản hồi\n  View 1 reply from {channelName}: Xem 1 phản hồi từ {channelName}\n  View {replyCount} replies from {channelName} and others: Xem {replyCount} phản hồi từ {channelName} và những người khác\nUp Next: 'Tiếp theo'\n\n# Toast Messages\nLocal API Error (Click to copy): 'Local API lỗi (Nhấn để copy)'\nInvidious API Error (Click to copy): 'Invidious API lỗi (Nhấn để copy)'\nFalling back to Invidious API: 'Quay trở về Invidious API'\nFalling back to Local API: 'Quay trở về local API'\nLoop is now disabled: 'Lặp lại hiện đã tắt'\nLoop is now enabled: 'Lặp lại hiện đã bật'\nShuffle is now disabled: 'Xáo trộn hiện đã tắt'\nShuffle is now enabled: 'Xáo trộn hiện đã bật'\nPlaying Next Video: 'Phát video tiếp theo'\nPlaying Previous Video: 'Phát video trước'\nCanceled next video autoplay: 'Bỏ tự động phát video tiếp theo'\n'The playlist has ended. Enable loop to continue playing': 'Danh sách phát đã kết thúc. Bật lặp lại để tiếp tục phát'\n\nYes: 'Có'\nNo: 'Không'\nThe playlist has been reversed: Playlist đã được đảo ngược\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: Video này không có sẵn vì thiếu mất định dạng. Đây có thể xảy ra do giới hạn quốc gia.\nProfile:\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: Bạn có chắc chắn muốn xóa các kênh đã chọn không? Điều này sẽ không xóa kênh khỏi bất kì profile nào.\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : Đây là profile chính của bạn. Bạn có chắc là muốn xóa các kênh đã chọn không? Các kênh tương tự sẽ bị xóa trong profile nào mà chúng được tìm thấy.\n  No channel(s) have been selected: Không kênh nào được chọn\n  Add Selected To Profile: Thêm đã chọn vào Profile\n  Delete Selected: Xóa đã chọn\n  Select None: Chọn không\n  Select All: Chọn hết\n  '{number} selected': '{number} đã chọn'\n  Other Channels: Các kênh khác\n  Subscription List: Danh sách đăng ký\n  '{profile} is now the active profile': '{profile} bây giờ là hoạt động profile'\n  Your default profile has been changed to your primary profile: Profile mặc định của bạn đã thay đổi thành profile chính\n  Removed {profile} from your profiles: Đã xóa {profile} khỏi Profile của bạn\n  Your default profile has been set to {profile}: 'Profile mặc định của bạn đã được chỉnh về {profile}'\n  Profile has been updated: Profile đã được cập nhật\n  Profile has been created: Profile đã được tạo\n  Your profile name cannot be empty: Tên hồ sơ của bạn không được để trống\n  All subscriptions will also be deleted.: Tất cả đăng ký đều sẽ bị xóa.\n  Are you sure you want to delete this profile?: Bạn có chắc muốn xóa hồ sơ này?\n  Delete Profile: Xóa hồ sơ\n  Make Default Profile: Chọn làm hồ sơ mặc định\n  Update Profile: Cập nhật hồ sơ\n  Create Profile: Tạo hồ sơ\n  Profile Preview: Xem trước hồ sơ\n  Custom Color: Màu tùy chỉnh\n  Color Picker: Chọn màu\n  Edit Profile: Chỉnh sửa hồ sơ\n  Create New Profile: Tạo hồ sơ mới\n  Profile Manager: Quản lý hồ sơ\n  All Channels: Tất cả kênh\n  Profile Select: Chọn hồ sơ\n  Profile Filter: Bộ lọc hồ sơ\n  Profile Settings: Hồ sơ\n  Toggle Profile List: Mở/đóng danh sách hồ sơ\n  Edit Profile Name: Chỉnh sửa tên hồ sơ\n  Profile Name: Tên hồ sơ\n  Open Profile Dropdown: Mở danh sách hồ sơ\n  Create Profile Name: Tạo tên hồ sơ\n  Close Profile Dropdown: Đóng danh sách hồ sơ\nA new blog is now available, {blogTitle}. Click to view more: Một blog mới đã có, {blogTitle}. Nhấn để xem chi tiết\nDownload From Site: Tải từ website\nVersion {versionNumber} is now available!  Click for more details: Phiên bản {versionNumber} đã có! Click để xem chi tiết\nOpen New Window: Mở cửa sổ mới\nSearch Bar:\n  Clear Input: Xóa đầu vào\n  Remove: Xóa bỏ\nMore: Thêm\nAre you sure you want to open this link?: Bạn có chắc là bạn muốn mở liên kết này không?\nNew Window: Cửa sổ mới\nChannels:\n  Channels: Kênh\n  Title: Danh sách kênh\n  Search bar placeholder: Tìm kênh\n  Empty: Danh sách kênh của bạn hiện đang trống.\n  Unsubscribe Prompt: Bạn có chắc răng bạn muốn huỷ đăng ký kênh \"{channelName}\"?\n  Count: '{number} kênh đã tìm được.'\nTooltips:\n  General Settings:\n    Thumbnail Preference: Tất cả các hình thu nhỏ trên FreeTube sẽ được thay thế bằng khung hình của video, làm mờ hoặc ẩn thay vì hình thu nhỏ mặc định.\n    External Link Handling: \"Chọn tác vụ mặc định khi một liên kết không thể mở được nhập vào FreeTube.\\nTheo mặc định, FreeTube sẽ mở liên kết này trong trình duyệt mặc định của bạn.\\n\"\n    Fallback to Non-Preferred Backend on Failure: Khi API ưu tiên của bạn gặp sự cố, FreeTube sẽ tự động sử dụng API không ưu tiên của bạn làm phương án dự phòng khi nó được bật lên.\n    Preferred API Backend: Chọn backend mà FreeTube sử dụng để lấy dữ liệu. API cục bộ là một trình trích xuất tích hợp sẵn. API Invidious yêu cầu máy chủ Invidious để kết nối.\n    Invidious Instance: Phiên bản Invidious mà FreeTube sẽ kết nối với để gọi các lệnh API.\n    Region for Trending: Xu hướng khu vực cho phép bạn chọn các video thịnh hành của quốc gia mà bạn muốn hiển thị.\n    Open Deep Links In New Window: Các URL được truyền đến FreeTube, chẳng hạn như thông qua các trình mở rộng trình duyệt tự động chuyển hướng hay đối số khị mở qua dòng lệnh, sẽ được mở trên một cửa sổ mới.\n  Player Settings:\n    Proxy Videos Through Invidious: Sẽ kết nối với Invidious để cung cấp video thay vì kết nối trực tiếp với YouTube.\n    Default Video Format: Cài đặt các định dạng được dùng khi phát video. Định dạng DASH có thể phát với chất lượng cao hơn. Các định dạng cũ được giới hạn ở mức tối đa là 360p nhưng chúng tiêu tốn ít băng thông hơn. Định dạng âm thanh là những luồng chỉ phát âm thanh.\n    Scroll Playback Rate Over Video Player: Khi con trỏ chuột ở trên video, hãy nhấn và giữ phím Control (Phím Command trên máy Mac) và cuộn con lăn chuột tới hoặc lui để kiểm soát tốc độ phát. Nhấn và giữ phím Control (Phím Command trên Mac) và nhấp chuột trái để lập tức trở về tốc độ phát mặc định (1x trừ khi nó đã được thay đổi trong cài đặt).\n    Skip by Scrolling Over Video Player: Sử dụng con lăn chuột để bỏ qua video, kiểu MPV.\n  External Player Settings:\n    Custom External Player Arguments: Bất kỳ tham số dòng lệnh tùy chỉnh nào, bạn muốn được chuyển đến trình phát bên ngoài.\n    Custom External Player Executable: Theo mặc định, FreeTube sẽ giả định rằng trình phát bên ngoài đã chọn có thể được tìm thấy thông qua biến môi trường PATH. Nếu cần, bạn có thể đặt một đường dẫn tuỳ chọn ở đây.\n    Ignore Warnings: 'Loại bỏ cảnh báo khi trình phát bên ngoài hiện tại không hỗ trợ cho thao tác hiện tại (ví dụ: đảo ngược danh sách phát, v.v.).'\n    DefaultCustomArgumentsTemplate: \"(Mặc định: '{defaultCustomArguments}')\"\n    External Player: Chọn một trình phát bên ngoài sẽ hiển thị một biểu tượng để mở video (danh sách phát nếu được hỗ trợ) trong trình phát bên ngoài, trên hình thu nhỏ của video. Cảnh báo, cài đặt Invidious không ảnh hưởng đến trình phát bên ngoài.\n    Ignore Default Arguments: Không gửi các tham số mặc định đến trình phát bên ngoài ngoài URL của video (như tốc độ phát, URL danh sách phát, v.v.). Các tham số tùy chỉnh vẫn sẽ được gửi.\n  Subscription Settings:\n    Fetch Feeds from RSS: Khi được bật lên, FreeTube sẽ sử dụng RSS thay vì phương thức mặc định để lấy nguồn cấp dữ liệu đăng ký của bạn. RSS nhanh hơn và tránh việc bị chặn IP, nhưng không cung cấp thông tin nhất định như thời lượng video, trạng thái phát trực tiếp hoặc các bài đăng\n    Fetch Automatically: Khi được bật, FreeTube sẽ tự động lấy nguồn cấp dữ liệu đăng ký của bạn khi khởi động, khi mở cửa sổ mới.\n  Distraction Free Settings:\n    Hide Channels: Nhập tên kênh hoặc ID kênh để ẩn tất cả video, danh sách phát và chính kênh đó khỏi xuất hiện trong tìm kiếm, xu hướng, phổ biến nhất và được đề xuất. Tên kênh đã nhập phải khớp hoàn toàn và có phân biệt chữ hoa chữ thường.\n    Hide Subscriptions Live: Cài đặt này bị ghi đè bởi cài đặt \"{appWideSetting}\" trên toàn ứng dụng, trong phần \"{subsection}\" của \"{settingsSection}\"\n    Hide Videos, Playlists and Channels Containing Text: Nhập một từ khóa hoặc cụm từ (không phân biết hoa thường) để ẩn các video & danh sách phát có tiêu đề gốc chứa các mục đó khỏi FreeTube, ngoại trừ các video trong Lịch sử, các danh sách phát của bạn, và video trong các danh sách phát.\n    Hide Videos on Watch: Ẩn các video đã xem khỏi tab Video, Video ngắn và Trực tiếp trên trang Đăng ký và Kênh. Điều này không ảnh hưởng đến tab Trang chủ trên trang Kênh\n  SponsorBlock Settings:\n    UseDeArrowThumbnails: Thay thế thumbnail video bằng thumbnail gửi từ DeArrow.\n    UseDeArrowTitles: Thay thế tiêu đề video bằng tiêu đề do người dùng gửi từ DeArrow.\n  Experimental Settings:\n    Replace HTTP Cache: Tắt bộ nhớ đệm HTTP dựa trên đĩa của Electron và bật bộ nhớ đệm hình ảnh trong bộ nhớ tùy chỉnh. Sẽ dẫn đến việc sử dụng RAM tăng lên.\nPlaying Next Video Interval: Phát video tiếp theo ngay lập tức. Nhấn vào để hủy. | Phát video tiếp theo sau {nextVideoInterval} giây nữa. Nhấn vào để hủy. | Phát video tiếp theo sau {nextVideoInterval} giây. Nhấn vào để hủy.\nExternal link opening has been disabled in the general settings: Tính năng mở liên kết bên ngoài đã bị tắt trong cài đặt chung\nDefault Invidious instance has been cleared: Phiên bản Invidious mặc định đã bị xóa\nScreenshot Success: Ảnh chụp màn hình đã lưu\nScreenshot Error: Chụp màn hình không thành công. {error}\nDefault Invidious instance has been set to {instance}: Phiên bản Invidious mặc định đã được đặt thành {instance}\nUnknown YouTube url type, cannot be opened in app: Dạng YouTube URL không xác định, không thể mở trong ứng dụng này\nOk: Ok\nClipboard:\n  Copy failed: Sao chép vào bộ nhớ tạm thất bại\n  Cannot access clipboard without a secure connection: Không thể truy cập clipboard nếu không có kết nối an toàn\nGo to page: Đi đến {page}\nClose Banner: Đóng thanh trên\nChapters:\n  Chapters: Chương\n  Key Moments: Khoảnh khắc chính\nChannel Unhidden: '{channel} đã bị xóa khỏi bộ lọc kênh'\nTag already exists: Thẻ \"{tagName}\" đã tồn tại\nHashtag:\n  This hashtag does not currently have any videos: Hashtag này hiện không có bất kỳ video nào\n  Hashtag: Hashtag\nAge Restricted:\n  This channel is age restricted: Kênh này bị giới hạn độ tuổi\n  This video is age restricted: Video này bị giới hạn độ tuổi\nPreferences: Tuỳ chỉnh\nChannel Hidden: '{channel} đã thêm vào bộ lọc kênh'\nTrimmed input must be at least N characters long: Dữ liệu nhập bị cắt bớt phải dài ít nhất 1 ký tự | Dữ liệu nhập bị cắt bớt phải dài ít nhất {length} ký tự\nFeed:\n  Refresh Feed: Tải lại {subscriptionName}\n  Feed Last Updated: 'Lần cuối cập nhật {feedName}: {date}'\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: Có phụ đề\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: Mới\n    3D: 3D\n    Closed Captions: Có phụ đề\nSearch character limit: Chuỗi tìm kiếm vượt quá độ dài {searchCharacterLimit} ký tự cho phép\nYes, Open Link: Có, mở liên kết\nCancel: Hủy bỏ\nMoments Ago: vừa xong\nYes, Delete: Có, xóa đi\nDisplay Label: '{label}: {value}'\ncheckmark: ✓\nYes, Restart: Có, khởi đông lại đi\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: Mũi tên xuống\n  arrowleft: Mũi tên trái\n  arrowright: Mũi tên phải\n  arrowup: Mũi tên lên\n  plus: Cộng\n  shift: Shift\n  enter: Enter\nRight-click or hold to see history: Giữ hoặc nhấn chuột phải để xem lịch sử\nAutoplay Interruption Timer: Tự động phát bị hủy do không có hành động trong {autoplayInterruptionIntervalHours} giờ\nDescription:\n  Expand Description: '...thêm'\n  Collapse Description: Ẩn bớt\nKeyboardShortcutPrompt:\n  Mute: Bật/Tắt tiếng\n  Next Chapter: Tua đến chương sau\n  Skip by Tenths: Tua đến 0~9 phần mười của video\n  Keyboard Shortcuts: Phím tắt bàn phím\n  Sections:\n    Video:\n      Playback: 'Video: Phát lại'\n      General: 'Video: Chung'\n    App:\n      Situational: 'Ứng dụng: Theo bối cảnh'\n      General: 'Ứng dụng: Chung'\n  History Backward: Lùi một trang\n  Refresh: Cập nhật luồng video\n  Focus Secondary Search: Đặt con trỏ bàn phím vào thanh tìm kiếm phụ (nếu có)\n  Stats: Hiện thống kê video\n  Fullscreen: Bật/tắt toàn màn hình\n  Captions: Bật/tắt phụ đề\n  Picture in Picture: Bặt/tắt hình trong hình\n  Full Window: Bật/tắt toàn cửa sổ\n  Reset Zoom: Đặt lại tỉ lệ phóng UI\n  Large Rewind: Tua lại video 2 nấc theo cài đặt nhân tốc độ phát lại\n  Zoom In: Phóng to\n  Next Frame: Khung ảnh sau (khi tạm dừng)\n  Volume Up: Tăng âm lượng\n  Small Rewind: Tua lại video 1 nấc theo cài đặt nhân tốc độ phát lại\n  Toggle Developer Tools: Hiện công cụ nhà phát triển\n  Small Fast Forward: Tua đi video 1 nấc theo cài đặt nhân tốc độ phát lại\n  Decrease Video Speed: Giảm tốc độ video 1 nấc theo cài đặt\n  Last Chapter: Tua về chương trước\n  Volume Down: Giảm âm lượng\n  Increase Video Speed: Tăng tốc độ video 1 nấc theo cài đặt\n  New Window: Tạo cửa sổ mới\n  Play: Phát/tạm dừng\n  Large Fast Forward: Tua đi video 2 nấc theo cài đặt nhân tốc độ phát lại\n  Take Screenshot: Chụp ảnh màn hình\n  Zoom Out: Thu nhỏ\n  Focus Search: Đặt con trỏ bàn phím vào thanh tìm kiếm\n  Show Keyboard Shortcuts: Hiện phím tắt bàn phím\n  History Forward: Tiến một trang\n  Navigate to Settings: Đi đến trang Cài đặt\n  Navigate to History: Đi đến trang Lịch sử\n  Minimize Window: Thu nhỏ cửa sổ\n  Theatre Mode: Bật/tắt chế độ rạp hát\n  Close Window: Đóng cửa sổ\n  Search in New Window: Tìm kiếm trong cửa sổ mới\n  Last Frame: Khung ảnh trước (khi tạm dừng)\n  End: Di chuyển tới cuối video\n  Home: Di chuyển đến đầu video\n  Skip to Next Video: Chuyển sang video tiếp theo trong danh sách phát hoặc video được đề xuất tiếp theo\n  Skip to Previous Video: Chuyển về video trước trong danh sách phát\nshortcutLabelSeparator: ｜\nCompact side navigation: Điều hướng bên nhỏ gọn\nExpand side navigation: Mở rộng điều hướng bên\n"
  },
  {
    "path": "static/locales/vls.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: 'West-Vlams'\n\n# Webkit Menu Bar\nFile: 'Bestand'\nNew Window: 'Nieuw koader'\nPreferences: 'Vôrkeurn'\nQuit: 'Stopn'\nEdit: 'Anpasn'\nUndo: 'Were wegdoen'\nRedo: 'Erdoene'\nCut: 'Snien'\nCopy: 'Kopiëern'\nPaste: 'Plakn'\nDelete: 'Wegdoen'\nSelect all: 'Olles selecteern'\nToggle Developer Tools: 'Ontwikkeloars gerjidschap anzetn'\nActual size: '''D echte grôte'\nZoom in: 'Vergrôtn'\nZoom out: 'Verkljin'\nToggle fullscreen: 'Vul skerm anzetn'\nWindow: 'Koader'\nMinimize: 'Kljinne moakn'\nClose: 'Toedoen'\nBack: 'Werekjirn'\nForward: 'Vôrût'\nOpen New Window: 'Nieuw koader opendoen'\nGo to page: 'Na dizn {page} goane'\nClose Banner: 'Banner toedeoene'\n\nVersion {versionNumber} is now available!  Click for more details: 'Versie {versionNumber}\n  is beschikboar!..Klikt ier vo mjir details'\nDownload From Site: 'Download van de site'\nA new blog is now available, {blogTitle}. Click to view more: 'Der is ne nieuwn blog\n  ût, {blogTitle}. Klikt ier vo mjir te ziene'\nAre you sure you want to open this link?: 'Ziej zeker daj die link wilt opendoene?'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: 'Videos'\n  Shorts: 'Korte videos'\n  Live: 'Rechtstreeks'\n  Sort By: 'Azwu sorteern'\n  Counts:\n    Video Count: '1 video | {count} videos'\n    Channel Count: '1 kanoal | {count} kanoaln'\n    Subscriber Count: '1 abonnee | {count} abonnees'\n    View Count: '1 gekeekn | {count} gekeekn'\n    Like Count: '1 die et gjist vindt | {count} die et gjist vindn'\n    Comment Count: '1 reactie | {count} reacties'\n    Watching Count: '1 ant kiekn | {count} ant kiekn'\n\n# Search Bar\nSearch / Go to URL: 'Zoekn / Nar URL goane'\nSearch Bar:\n  Clear Input: 'Invoer wegdoene'\nSearch character limit: 'Zoek ipdracht is {searchCharacterLimit} karakters te lange'\nSearch Listing:\n  Label:\n    4K: '4K'\n    Subtitles: 'Ondertekst'\n    # Aria labels\n    Closed Captions: 'Geslootn ondertitels'\n  # In Filter Button\n    8K: 8K\nSearch Filters:\n  Search Filters: 'Zoekfilters'\n  Sort By:\n    Most Relevant: 'Tmjist relevante'\n    Rating: 'Score'\n    Upload Date: 'Doatum dat online stoat'\n    View Count: 'Oevele dan der gekeekn eine'\n  Time:\n    Time: 'Den tîd'\n    Any Time: 'Van geliek wanjir'\n    Last Hour: 'Tlatste eure'\n    Today: 'Vandoage'\n    This Week: 'Dizze weke'\n    This Month: 'Dizze moande'\n    This Year: 'Diz joar'\n  Type:\n    Type: 'De soarte'\n    All Types: 'Ol de soartn'\n    Videos: 'Videos'\n    Channels: 'Kanoaln'\n    Movies: 'Films'\n    #& Playlists\n  Duration:\n    Duration: 'Oe lange dat deurt'\n    All Durations: 'Al de meugelijke deuroaties'\n    Short (< 4 minutes): 'Kort (< 4 minutn)'\n    Medium (4 - 20 minutes): 'Tussen de twji (4 - 20 minutn)'\n    Long (> 20 minutes): 'Lange (> 20 minutn)'\n  Features:\n    Features: 'Functies'\n    HD: 'HD'\n    Subtitles: 'Ondertekst'\n    Creative Commons: 'Creative Commons'\n    3D: '3D'\n    Live: 'Rechtstreeks'\n    4K: '4K'\n    360 Video: '360 video'\n    Location: 'Locoatie'\n    HDR: 'HDR'\n    VR180: 'VR180'\n  # On Search Page\n  Search Results: 'Zoek resultoatn'\n  Fetching results. Please wait: 'Resultoatn ant ipoaln. Efkes geduld alsjeblieft'\n  Fetch more results: 'Mjir resultoatn ipoaln'\n  There are no more results for this search: 'Der zin gin resultoatn nimji vo dize\n    zoekipdracht'\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: 'Abonnees'\n  # channels that were likely deleted\n  Error Channels: 'Kanoaln me foutn'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Tstoat\n    vo de moment nietn in jon lîste van abonnees. Vo der te ziene goaj moetn startn\n    me joe te abonneern.'\n  Disabled Automatic Fetching: 'Gêit otomoatisch abonnees ipoaln ofgezet. Erload jon\n    abonnees voor ze ier te ziene.'\n  Empty Channels: 'Jon geabonneerde kanoaln ein vo de moment gin videos.'\n  Empty Posts: 'Der zin vo de moment gin berichtn van jon geabonneerde kanoaln.'\n  Load More Videos: 'Mjir videos loadn'\n  Load More Posts: 'Mjir berichtn loadn'\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Turn on Subtitles by Default: ''\n    Autoplay Videos: ''\n    Proxy Videos Through Invidious: ''\n    Autoplay Playlists: ''\n    Enable Theatre Mode by Default: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Save Watched Progress: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search Cache: ''\n    Are you sure you want to clear out your search cache?: ''\n    Search cache has been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Export Playlists For Older FreeTube Versions:\n      Label: ''\n      # |- = Keep newlines, No newline at end\n      Tooltip: |\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: 'Olles selecteern'\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The\n    same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: 'Videos'\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\n    Viewing Posts Only Supported By Invidious: ''\nVideo:\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  # Context: View 10 Replies, View 1 Reply, View 1 Reply from Owner, View 2 Replies from Owner and others\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutPrompt:\n  Toggle Developer Tools: Ontwikkeloars gerjidschap anzetn\n  Zoom Out: Verkljin\n  Zoom In: Vergrôtn\n  Fullscreen: Vul skerm anzetn\n"
  },
  {
    "path": "static/locales/xh.yaml",
    "content": "# Put the name of your locale in the same language\nLocale Name: ''\n\n# Webkit Menu Bar\nFile: ''\nNew Window: ''\nPreferences: ''\nQuit: ''\nEdit: ''\nUndo: ''\nRedo: ''\nCut: ''\nCopy: ''\nPaste: ''\nDelete: ''\nSelect all: ''\nToggle Developer Tools: ''\nActual size: ''\nZoom in: ''\nZoom out: ''\nToggle fullscreen: ''\nWindow: ''\nMinimize: ''\nClose: ''\nCompact side navigation: ''\nExpand side navigation: ''\nBack: ''\nForward: ''\nRight-click or hold to see history: ''\nOpen New Window: ''\nGo to page: ''\nClose Banner: ''\n\nVersion {versionNumber} is now available!  Click for more details: ''\nDownload From Site: ''\nA new blog is now available, {blogTitle}. Click to view more: ''\nAre you sure you want to open this link?: ''\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: ''\n  Shorts: ''\n  Live: ''\n  Posts: ''\n  Sort By: ''\n  Counts:\n    Video Count: ''\n    Channel Count: ''\n    Subscriber Count: ''\n    View Count: ''\n    Like Count: ''\n    Comment Count: ''\n    Watching Count: ''\n\n# Search Bar\nSearch / Go to URL: ''\nSearch Bar:\n  Clear Input: ''\n  Remove: ''\nSearch character limit: ''\nSearch Listing:\n  Label:\n    4K: ''\n    8K: ''\n    VR180: ''\n    360 Video: ''\n    Subtitles: ''\n    New: ''\n    3D: ''\n    # Aria labels\n    Closed Captions: ''\n  # In Filter Button\nSearch Filters:\n  Search Filters: ''\n  Sort By:\n    Most Relevant: ''\n    Rating: ''\n    Upload Date: ''\n    View Count: ''\n  Time:\n    Time: ''\n    Any Time: ''\n    Last Hour: ''\n    Today: ''\n    This Week: ''\n    This Month: ''\n    This Year: ''\n  Type:\n    Type: ''\n    All Types: ''\n    Videos: ''\n    Channels: ''\n    Movies: ''\n    #& Playlists\n  Duration:\n    Duration: ''\n    All Durations: ''\n    Short (< 4 minutes): ''\n    Medium (4 - 20 minutes): ''\n    Long (> 20 minutes): ''\n  Features:\n    Features: ''\n    HD: ''\n    Subtitles: ''\n    Creative Commons: ''\n    3D: ''\n    Live: ''\n    4K: ''\n    360 Video: ''\n    Location: ''\n    HDR: ''\n    VR180: ''\n  # On Search Page\n  Search Results: ''\n  Fetching results. Please wait: ''\n  Fetch more results: ''\n  There are no more results for this search: ''\n  Clear Filters: ''\n# Sidebar\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: ''\n  # channels that were likely deleted\n  Error Channels: ''\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: ''\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': ''\n  Disabled Automatic Fetching: ''\n  Empty Channels: ''\n  Empty Posts: ''\n  Load More Videos: ''\n  Load More Posts: ''\n  Subscriptions Tabs: ''\n  All Subscription Tabs Hidden: ''\nMore: ''\nChannels:\n  Channels: ''\n  Title: ''\n  Search bar placeholder: ''\n  Count: ''\n  Empty: ''\n  Unsubscribe Prompt: ''\nTrending:\n  Trending: ''\n  Gaming: ''\n  Sports: ''\n  Trending Tabs: ''\nMost Popular: ''\nFeed:\n  Feed Last Updated: ''\n  Refresh Feed: ''\nPlaylists: ''\nUser Playlists:\n  Your Playlists: ''\n  You have no playlists. Click on the create new playlist button to create a new one.: ''\n  Empty Search Message: ''\n  Search bar placeholder: ''\n  Playlists with Matching Videos: ''\n\n  This playlist currently has no videos.: ''\n\n  Create New Playlist: ''\n\n  Add to Playlist: ''\n  Add to Favorites: ''\n  Remove from Favorites: ''\n\n  Move Video Up: ''\n  Move Video Down: ''\n  Remove from Playlist: ''\n\n  Playlist Name: ''\n  Playlist Description: ''\n\n  Save Changes: ''\n  Cancel: ''\n  Edit Playlist Info: ''\n  Copy Playlist: ''\n  Remove Duplicate Videos: ''\n  Remove Watched Videos: ''\n  Enable Quick Bookmark With This Playlist: ''\n  Quick Bookmark Enabled: ''\n  Export Playlist: ''\n  Export list of URLs: ''\n  The playlist has been successfully exported: ''\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: ''\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: ''\n  Delete Playlist: ''\n  Cannot delete the quick bookmark target playlist.: ''\n  Are you sure you want to delete this playlist? This cannot be undone: ''\n\n  TotalTimePlaylist: \"\"\n\n  Sort By:\n    NameAscending: ''\n    NameDescending: ''\n\n    LatestCreatedFirst: ''\n    EarliestCreatedFirst: ''\n\n    LatestUpdatedFirst: ''\n    EarliestUpdatedFirst: ''\n\n    LatestPlayedFirst: ''\n    EarliestPlayedFirst: ''\n  SinglePlaylistView:\n    Search for Videos: ''\n\n    Toast:\n      This video cannot be moved up.: ''\n      This video cannot be moved down.: ''\n      Video has been removed: ''\n      Video has been removed. Click here to undo.: ''\n      There was a problem with removing this video: ''\n\n      This playlist is already being used for quick bookmark.: ''\n      This playlist is now used for quick bookmark: ''\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: ''\n      Reverted to use {oldPlaylistName} for quick bookmark: ''\n\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: ''\n      Playlist name cannot be empty. Please input a name.: ''\n      Playlist has been updated.: ''\n      There was an issue with updating this playlist.: ''\n      \"{videoCount} video(s) have been removed\": \"\"\n      There were no videos to remove.: ''\n      This playlist is protected and cannot be removed.: ''\n      Playlist {playlistName} has been deleted.: ''\n\n      This playlist does not exist: ''\n\n      This playlist has a video with a duration error: ''\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: ''\n    N playlists selected: ''\n    Search in Playlists: ''\n    Allow Adding Duplicate Video(s): ''\n    Save: ''\n\n    Added {count} Times: ''\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": ''\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": ''\n\n    Toast:\n      You haven't selected any playlist yet.: ''\n      \"Video(s) added to {playlistCount} playlists\": \"\"\n  CreatePlaylistPrompt:\n    New Playlist Name: ''\n    Create: ''\n\n    Toast:\n      There is already a playlist with this name. Please pick a different name.: ''\n      Playlist {playlistName} has been successfully created.: ''\n      There was an issue with creating the playlist.: ''\nHistory:\n  # On History Page\n  History: ''\n  Watch History: ''\n  Your history list is currently empty.: ''\n  Empty Search Message: ''\n  Search bar placeholder: \"\"\n  Case Sensitive Search: ''\n  DateOldestHistory: ''\n  DateNewestHistory: ''\nSettings:\n  # On Settings Page\n  Settings: ''\n  Sort Settings Sections (A-Z): ''\n  Return to Settings Menu: ''\n  The app needs to restart for changes to take effect. Restart and apply change?: ''\n  General Settings:\n    General Settings: ''\n    Check for Updates: ''\n    Check for Latest Blog Posts: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Enable Search Suggestions: ''\n    Open Deep Links In New Window: ''\n    Minimize to system tray: ''\n    Auto Load Next Page:\n      Label: ''\n      Tooltip: ''\n    Default Landing Page: ''\n    Locale Preference: ''\n    System Default: ''\n    Preferred API Backend:\n      Preferred API Backend: ''\n      Local API: ''\n      Invidious API: ''\n    Video View Type:\n      Video View Type: ''\n      Grid: ''\n      List: ''\n    Thumbnail Preference:\n      Thumbnail Preference: ''\n      Default: ''\n      Beginning: ''\n      Middle: ''\n      End: ''\n      Hidden: ''\n      Blur: ''\n    Current Invidious Instance: ''\n    The currently set default instance is {instance}: ''\n    No default instance has been set: ''\n    Current instance will be randomized on startup: ''\n    Set Current Instance as Default: ''\n    Clear Default Instance: ''\n    View all Invidious instance information: ''\n    Region for Trending: ''\n    #! List countries\n    External Link Handling:\n      External Link Handling: ''\n      Open Link: ''\n      Ask Before Opening Link: ''\n      No Action: ''\n  Theme Settings:\n    Theme Settings: ''\n    Match Top Bar with Main Color: ''\n    Expand Side Bar by Default: ''\n    Disable Smooth Scrolling: ''\n    UI Scale: ''\n    Hide Side Bar Labels: ''\n    Hide FreeTube Header Logo: ''\n    Base Theme:\n      Base Theme: ''\n      Black: ''\n      Dark: ''\n      System Default: ''\n      Light: ''\n      Dracula: ''\n      Catppuccin Frappe: ''\n      Catppuccin Latte: ''\n      Catppuccin Mocha: ''\n      Pastel Pink: ''\n      Hot Pink: ''\n      Nordic: ''\n      Gruvbox Dark: ''\n      Gruvbox Light: ''\n      Solarized Dark: ''\n      Solarized Light: ''\n      Everforest Dark Hard: ''\n      Everforest Dark Medium: ''\n      Everforest Dark Low: ''\n      Everforest Light Hard: ''\n      Everforest Light Medium: ''\n      Everforest Light Low: ''\n    Main Color Theme:\n      Main Color Theme: ''\n      Red: ''\n      Pink: ''\n      Purple: ''\n      Deep Purple: ''\n      Indigo: ''\n      Blue: ''\n      Light Blue: ''\n      Cyan: ''\n      Teal: ''\n      Green: ''\n      Light Green: ''\n      Lime: ''\n      Yellow: ''\n      Amber: ''\n      Orange: ''\n      Deep Orange: ''\n      Dracula Cyan: ''\n      Dracula Green: ''\n      Dracula Orange: ''\n      Dracula Pink: ''\n      Dracula Purple: ''\n      Dracula Red: ''\n      Dracula Yellow: ''\n      Catppuccin Frappe Rosewater: ''\n      Catppuccin Frappe Flamingo: ''\n      Catppuccin Frappe Pink: ''\n      Catppuccin Frappe Mauve: ''\n      Catppuccin Frappe Red: ''\n      Catppuccin Frappe Maroon: ''\n      Catppuccin Frappe Peach: ''\n      Catppuccin Frappe Yellow: ''\n      Catppuccin Frappe Green: ''\n      Catppuccin Frappe Teal: ''\n      Catppuccin Frappe Sky: ''\n      Catppuccin Frappe Sapphire: ''\n      Catppuccin Frappe Blue: ''\n      Catppuccin Frappe Lavender: ''\n      Catppuccin Latte Mauve: ''\n      Catppuccin Latte Red: ''\n      Catppuccin Mocha Rosewater: ''\n      Catppuccin Mocha Flamingo: ''\n      Catppuccin Mocha Pink: ''\n      Catppuccin Mocha Mauve: ''\n      Catppuccin Mocha Red: ''\n      Catppuccin Mocha Maroon: ''\n      Catppuccin Mocha Peach: ''\n      Catppuccin Mocha Yellow: ''\n      Catppuccin Mocha Green: ''\n      Catppuccin Mocha Teal: ''\n      Catppuccin Mocha Sky: ''\n      Catppuccin Mocha Sapphire: ''\n      Catppuccin Mocha Blue: ''\n      Catppuccin Mocha Lavender: ''\n      Gruvbox Dark Green: ''\n      Gruvbox Dark Yellow: ''\n      Gruvbox Dark Blue: ''\n      Gruvbox Dark Purple: ''\n      Gruvbox Dark Aqua: ''\n      Gruvbox Dark Orange: ''\n      Gruvbox Light Red: ''\n      Gruvbox Light Blue: ''\n      Gruvbox Light Purple: ''\n      Gruvbox Light Orange: ''\n      Solarized Yellow: ''\n      Solarized Orange: ''\n      Solarized Red: ''\n      Solarized Magenta: ''\n      Solarized Violet: ''\n      Solarized Blue: ''\n      Solarized Cyan: ''\n      Solarized Green: ''\n      Everforest Dark Red: ''\n      Everforest Dark Orange: ''\n      Everforest Dark Yellow: ''\n      Everforest Dark Green: ''\n      Everforest Dark Aqua: ''\n      Everforest Dark Blue: ''\n      Everforest Dark Purple: ''\n      Everforest Light Red: ''\n      Everforest Light Orange: ''\n      Everforest Light Yellow: ''\n      Everforest Light Green: ''\n      Everforest Light Aqua: ''\n      Everforest Light Blue: ''\n      Everforest Light Purple: ''\n    Secondary Color Theme: ''\n        #* Main Color Theme\n  Player Settings:\n    Player Settings: ''\n    Play Next Video: ''\n    Autoplay Playlists: ''\n    Autoplay Videos: ''\n    Turn on Subtitles by Default: ''\n    Proxy Videos Through Invidious: ''\n    Default Viewing Mode:\n      Theater: ''\n      Default Viewing Mode: ''\n      Full Screen: ''\n      Picture in Picture: ''\n      External Player: ''\n    Scroll Volume Over Video Player: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n    Display Play Button In Video Player: ''\n    Enter Fullscreen on Display Rotate: ''\n    Next Video Interval: ''\n    Autoplay Interruption Timer: ''\n    Fast-Forward / Rewind Interval: ''\n    Default Volume: ''\n    Default Playback Rate: ''\n    Max Video Playback Rate: ''\n    Video Playback Rate Interval: ''\n    Default Video Format:\n      Default Video Format: ''\n      Dash Formats: ''\n      Legacy Formats: ''\n      Audio Formats: ''\n    Default Quality:\n      Default Quality: ''\n      Auto: ''\n      144p: ''\n      240p: ''\n      360p: ''\n      480p: ''\n      720p: ''\n      1080p: ''\n      1440p: ''\n      4k: ''\n      8k: ''\n    Screenshot:\n      Enable: ''\n      Format Label: ''\n      Quality Label: ''\n      Ask Path: ''\n      Folder Label: ''\n      Folder Button: ''\n      File Name Label: ''\n      File Name Tooltip: ''\n      Error:\n        Forbidden Characters: ''\n        Empty File Name: ''\n  External Player Settings:\n    External Player Settings: ''\n    External Player: ''\n    Ignore Unsupported Action Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Executable: ''\n    Custom External Player Arguments: ''\n    Players:\n      None:\n        Name: ''\n  Privacy Settings:\n    Privacy Settings: ''\n    Remember History: ''\n    Remember Search History: ''\n    Save Watched Progress: ''\n    Watched Progress Saving Mode:\n      Modes:\n        Auto: ''\n        Semi-auto: ''\n        Never: ''\n      Tooltip: ''\n    Save Watched Videos With Last Viewed Playlist: ''\n    Clear Search History and Cache: ''\n    Are you sure you want to clear out your search history and cache?: ''\n    Search history and cache have been cleared: ''\n    Remove Watch History: ''\n    Are you sure you want to remove your entire watch history?: ''\n    Watch history has been cleared: ''\n    Remove All Subscriptions / Profiles: ''\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: ''\n    Remove All Playlists: ''\n    All playlists have been removed: ''\n    Are you sure you want to remove all your playlists?: ''\n  Subscription Settings:\n    Subscription Settings: ''\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n    'Limit the number of videos displayed for each channel': ''\n    To: ''\n    Confirm Before Unsubscribing: ''\n  Distraction Free Settings:\n    Distraction Free Settings: ''\n    Sections:\n      Side Bar: ''\n      Subscriptions Page: ''\n      Channel Page: ''\n      Watch Page: ''\n      General: ''\n    Hide Video Views: ''\n    Hide Video Likes And Dislikes: ''\n    Hide Channel Subscribers: ''\n    Hide Comment Likes: ''\n    Hide Recommended Videos: ''\n    Hide Trending Videos: ''\n    Hide Popular Videos: ''\n    Hide Playlists: ''\n    Hide Live Chat: ''\n    Hide Active Subscriptions: ''\n    Hide Video Description: ''\n    Hide Comments: ''\n    Hide Profile Pictures in Comments: ''\n    Display Titles Without Excessive Capitalisation: ''\n    Hide Live Streams: ''\n    Hide Upcoming Premieres: ''\n    Hide Sharing Actions: ''\n    Hide Videos on Watch: ''\n    Hide Chapters: ''\n    Hide Channels: ''\n    Hide Channels Disabled Message: ''\n    Hide Channels Placeholder: ''\n    Hide Channels Invalid: ''\n    Hide Channels API Error: ''\n    Hide Channels Already Exists: ''\n    Hide Featured Channels: ''\n    Hide Channel Playlists: ''\n    Hide Channel Posts: ''\n    Hide Channel Home: ''\n    Hide Channel Shorts: ''\n    Hide Channel Podcasts: ''\n    Hide Channel Releases: ''\n    Hide Channel Courses: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos, Playlists and Channels Containing Text Placeholder: ''\n    Hide Subscriptions Videos: ''\n    Hide Subscriptions Shorts: ''\n    Hide Subscriptions Live: ''\n    Hide Subscriptions Posts: ''\n    Show Added Items: ''\n  Data Settings:\n    Data Settings: ''\n    Select Export Type: ''\n    Import Subscriptions: ''\n    Subscription File: ''\n    History File: ''\n    Playlist File: ''\n    Search history file: ''\n    Export Subscriptions: ''\n    Export FreeTube: ''\n    Export YouTube: ''\n    Export NewPipe: ''\n    Import History: ''\n    Export History: ''\n    Import Playlists: ''\n    Export Playlists: ''\n    Search history: ''\n    Import search history: ''\n    Export search history: ''\n    Profile object has insufficient data, skipping item: ''\n    All subscriptions and profiles have been successfully imported: ''\n    All subscriptions have been successfully imported: ''\n    Invalid subscriptions file: ''\n    Invalid history file: ''\n    Subscriptions have been successfully exported: ''\n    History object has insufficient data, skipping item: ''\n    All watched history has been successfully imported: ''\n    All watched history has been successfully exported: ''\n    Playlist insufficient data: ''\n    All playlists has been successfully imported: ''\n    All playlists has been successfully exported: ''\n    All search history has been successfully imported: ''\n    All search history has been successfully exported: ''\n    Unable to read file: ''\n    Unable to write file: ''\n    Unknown data key: ''\n    How do I import my subscriptions?: ''\n    Manage Subscriptions: ''\n  Proxy Settings:\n    Proxy Settings: ''\n    Proxy Warning: ''\n    Enable Tor / Proxy: ''\n    Proxy Protocol: ''\n    Proxy Host: ''\n    Proxy Port Number: ''\n    Proxy Username: ''\n    Proxy Password: ''\n    Clicking on Test Proxy will send a request to: ''\n    Test Proxy: ''\n    Your Info: ''\n    Ip: ''\n    Country: ''\n    Region: ''\n    City: ''\n    Error getting network information. Is your proxy configured properly?: ''\n  SponsorBlock Settings:\n    SponsorBlock Settings: ''\n    Enable SponsorBlock: ''\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': ''\n    Notify when sponsor segment is skipped: ''\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': ''\n    Skip Options:\n      Skip Option: ''\n      Auto Skip: ''\n      Show In Seek Bar: ''\n      Prompt To Skip: ''\n      Do Nothing: ''\n    Category Color: ''\n  Parental Control Settings:\n    Parental Control Settings: ''\n    Hide Unsubscribe Button: ''\n    Hide Uploader on Watch page: ''\n    Show Family Friendly Only: ''\n    Hide Search Bar: ''\n  Experimental Settings:\n    Experimental Settings: ''\n    Warning: ''\n    Replace HTTP Cache: ''\n  Password Dialog:\n    Password: ''\n    Enter Password To Unlock: ''\n  Password Settings:\n    Password Settings: ''\n    Set Password To Prevent Access: ''\n    Set Password: ''\n    Remove Password: ''\nAbout:\n  #On About page\n  About: ''\n  Beta: ''\n  Source code: ''\n  Licensed under the {licenseLink}: ''\n  AGPLv3: ''\n  Downloads / Changelog: ''\n  GitHub releases: ''\n  Help: ''\n  FreeTube Wiki: ''\n  FAQ: ''\n  Discussions: ''\n  Report a problem: ''\n  GitHub issues: ''\n  Please check for duplicates before posting: ''\n  Website: ''\n  Blog: ''\n  Email: ''\n  Mastodon: ''\n  Chat on Matrix: ''\n  Please read the {roomRulesLink}: ''\n  room rules: ''\n  Translate: ''\n  Credits: ''\n  FreeTube is made possible by {creditsPageLink}: ''\n  these people and projects: ''\n  Donate: ''\n\nProfile:\n  Profile Settings: ''\n  Toggle Profile List: ''\n  Profile Select: ''\n  Profile Filter: ''\n  All Channels: ''\n  Profile Manager: ''\n  Create New Profile: ''\n  Edit Profile: ''\n  Edit Profile Name: ''\n  Create Profile Name: ''\n  Profile Name: ''\n  Color Picker: ''\n  Custom Color: ''\n  Profile Preview: ''\n  Create Profile: ''\n  Update Profile: ''\n  Make Default Profile: ''\n  Delete Profile: ''\n  Are you sure you want to delete this profile?: ''\n  All subscriptions will also be deleted.: ''\n  Your profile name cannot be empty: ''\n  Profile has been created: ''\n  Profile has been updated: ''\n  Your default profile has been set to {profile}: ''\n  Removed {profile} from your profiles: ''\n  Your default profile has been changed to your primary profile: ''\n  '{profile} is now the active profile': ''\n  Subscription List: ''\n  Other Channels: ''\n  '{number} selected': ''\n  Select All: ''\n  Select None: ''\n  Delete Selected: ''\n  Add Selected To Profile: ''\n  No channel(s) have been selected: ''\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : ''\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: ''\n  Close Profile Dropdown: ''\n  Open Profile Dropdown: ''\n#On Channel Page\nChannel:\n  Subscribe: ''\n  Unsubscribe: ''\n  Channel has been removed from your subscriptions: ''\n  Removed subscription from {count} other channel(s): ''\n  Added channel to your subscriptions: ''\n  Search Channel: ''\n  Your search results have returned 0 results: ''\n  This channel does not exist: ''\n  This channel does not allow searching: ''\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: ''\n  Channel Tabs: ''\n  Videos:\n    Videos: ''\n    This channel does not currently have any videos: ''\n    Sort Types:\n      Newest: ''\n      Oldest: ''\n      Most Popular: ''\n  Shorts:\n    This channel does not currently have any shorts: ''\n  Live:\n    Live: ''\n    This channel does not currently have any live streams: ''\n  Playlists:\n    Playlists: ''\n    This channel does not currently have any playlists: ''\n    Sort Types:\n      Last Video Added: ''\n      Newest: ''\n      Oldest: ''\n  Home:\n    Home: ''\n    View Playlist: ''\n  Podcasts:\n    Podcasts: ''\n    This channel does not currently have any podcasts: ''\n  Releases:\n    Releases: ''\n    This channel does not currently have any releases: ''\n  Courses:\n    Courses: ''\n    This channel does not currently have any courses: ''\n  About:\n    About: ''\n    Channel Description: ''\n    Tags:\n      Tags: ''\n      Search for: ''\n    Details: ''\n    Joined: ''\n    Location: ''\n    Featured Channels: ''\n  Posts:\n    This channel currently does not have any posts: ''\n    votes: ''\n    View Full Post: ''\n    Reveal Answers: ''\n    Hide Answers: ''\n    Video hidden by FreeTube: ''\nVideo:\n  IP block: ''\n  MembersOnly: ''\n  AgeRestricted: ''\n  DRMProtected: ''\n  More Options: ''\n  Mark As Watched: ''\n  Remove From History: ''\n  Video has been marked as watched: ''\n  Video has been removed from your history: ''\n  Save Watched Progress: ''\n  Watched Progress Saved: ''\n  Save Video: ''\n  Video has been saved: ''\n  Video has been removed from your saved list: ''\n  Open in YouTube: ''\n  Copy YouTube Link: ''\n  Open YouTube Embedded Player: ''\n  Copy YouTube Embedded Player Link: ''\n  Open in Invidious: ''\n  Copy Invidious Link: ''\n  Open Channel in YouTube: ''\n  Copy YouTube Channel Link: ''\n  Open Channel in Invidious: ''\n  Copy Invidious Channel Link: ''\n  Hide Channel: ''\n  Unhide Channel: ''\n  Views: ''\n  Loop Playlist: ''\n  Shuffle Playlist: ''\n  Reverse Playlist: ''\n  Previous: ''\n  Next: ''\n  Watched: ''\n  Autoplay: ''\n  Starting soon, please refresh the page to check again: ''\n  # As in a Live Video\n  Premieres: ''\n  Upcoming: ''\n  Unlisted: ''\n  Live: ''\n  Live Now: ''\n  Live Chat: ''\n  Enable Live Chat: ''\n  Popout Live Chat: ''\n  Live Chat is currently not supported in this build.: ''\n  Live chat is enabled. Chat messages will appear here once sent.: ''\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': ''\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': ''\n  Show Super Chat Comment: ''\n  Scroll to Bottom: ''\n  Published:\n    In less than a minute: ''\n  Published on: ''\n  Streamed on: ''\n  Started streaming on: ''\n  DeArrow:\n    Show Original Details: ''\n    Show Modified Details: ''\n  Sponsor Block category:\n    sponsor: ''\n    intro: ''\n    outro: ''\n    self-promotion: ''\n    interaction: ''\n    music offtopic: ''\n    recap: ''\n    filler: ''\n  External Player:\n    OpenInTemplate: ''\n    video: ''\n    playlist: ''\n    OpeningTemplate: ''\n    UnsupportedActionTemplate: ''\n    Unsupported Actions:\n      starting video at offset: ''\n      setting a playback rate: ''\n      opening playlists: ''\n      opening specific video in a playlist (falling back to opening the video): ''\n      reversing playlists: ''\n      shuffling playlists: ''\n      looping playlists: ''\n  Player:\n    TranslatedCaptionTemplate: ''\n    Audio Tracks: ''\n    Autoplay is off: ''\n    Autoplay is on: ''\n    Theatre Mode: ''\n    Exit Theatre Mode: ''\n    Full Window: ''\n    Exit Full Window: ''\n    Take Screenshot: ''\n    Show Stats: ''\n    Hide Stats: ''\n    Stats:\n      Stats: ''\n      Video ID: ''\n      Media Formats: ''\n      Resolution: ''\n      Player Dimensions: ''\n      Bitrate: ''\n      Volume: ''\n      Bandwidth: ''\n      Buffered: ''\n      Dropped Frames / Total Frames: ''\n      CodecAudio: ''\n      CodecsVideoAudio: ''\n      CodecsVideoAudioNoItags: ''\n    You appear to be offline: ''\n    Playback will resume automatically when your connection comes back: ''\n    Skipped segment: ''\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': ''\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': ''\n#& Playlists\nPlaylist:\n  #& About\n  Playlist: ''\n  View Full Playlist: ''\n  Last Updated On: ''\n  Sort By:\n    DateAddedNewest: ''\n    DateAddedOldest: ''\n    PublishedNewest: ''\n    PublishedOldest: ''\n    AuthorAscending: ''\n    AuthorDescending: ''\n    VideoTitleAscending: ''\n    VideoTitleDescending: ''\n    VideoDurationAscending: ''\n    VideoDurationDescending: ''\n    Custom: ''\n\n# On Video Watch Page\n#* Published\n#& Views\nChange Format:\n  Change Media Formats: ''\n  Use Dash Formats: ''\n  Use Legacy Formats: ''\n  Use Audio Formats: ''\n  Dash formats are not available for this video: ''\n  Audio formats are not available for this video: ''\n  Legacy formats are not available for this video: ''\nShare:\n  Share Video: ''\n  Share Post: ''\n  Share Channel: ''\n  Share Playlist: ''\n  Include Timestamp: ''\n  Copy Link: ''\n  Open Link: ''\n  Copy Embed: ''\n  Open Embed: ''\n  # On Click\n  Invidious URL copied to clipboard: ''\n  Invidious Embed URL copied to clipboard: ''\n  Invidious Channel URL copied to clipboard: ''\n  YouTube URL copied to clipboard: ''\n  YouTube Embed URL copied to clipboard: ''\n  YouTube Channel URL copied to clipboard: ''\nClipboard:\n  Copy failed: ''\n  Cannot access clipboard without a secure connection: ''\n\nChapters:\n  Chapters: ''\n  Key Moments: ''\n\nMini Player: ''\nComments:\n  Comments: ''\n  Click to View Comments: ''\n  Getting comment replies, please wait: ''\n  There are no more comments for this video: ''\n  Hide Comments: ''\n  Top comments: ''\n  Newest first: ''\n  View {replyCount} replies: ''\n  Hide {replyCount} replies: ''\n  View 1 reply from {channelName}: ''\n  View {replyCount} replies from {channelName} and others: ''\n  Show More Replies: ''\n  There are no comments available for this video: ''\n  There are no comments available for this post: ''\n  Load More Comments: ''\n  Pinned by: ''\n  Member: ''\n  Subscribed: ''\n  Hearted: ''\n\nUp Next: ''\nDescription:\n  Expand Description: ''\n  Collapse Description: ''\n\n#Tooltips\nTooltips:\n  General Settings:\n    Preferred API Backend: ''\n    Fallback to Non-Preferred Backend on Failure: ''\n    Thumbnail Preference: ''\n    Invidious Instance: ''\n    Region for Trending: ''\n    External Link Handling: |\n    Open Deep Links In New Window: ''\n  Player Settings:\n    Proxy Videos Through Invidious: ''\n    Default Video Format: ''\n    Scroll Playback Rate Over Video Player: ''\n    Skip by Scrolling Over Video Player: ''\n  External Player Settings:\n    External Player: ''\n    Custom External Player Executable: ''\n    Ignore Warnings: ''\n    Ignore Default Arguments: ''\n    Custom External Player Arguments: ''\n    DefaultCustomArgumentsTemplate: \"\"\n  Distraction Free Settings:\n    Hide Channels: ''\n    Hide Subscriptions Live: ''\n    Hide Videos, Playlists and Channels Containing Text: ''\n    Hide Videos on Watch: ''\n  Subscription Settings:\n    Fetch Feeds from RSS: ''\n    Fetch Automatically: ''\n  Experimental Settings:\n    Replace HTTP Cache: ''\n  SponsorBlock Settings:\n    UseDeArrowTitles: ''\n    UseDeArrowThumbnails: ''\n\n# Toast Messages\nLocal API Error (Click to copy): ''\nInvidious API Error (Click to copy): ''\nFalling back to Invidious API: ''\nFalling back to Local API: ''\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: ''\nUnknown YouTube url type, cannot be opened in app: ''\nLoop is now disabled: ''\nLoop is now enabled: ''\nShuffle is now disabled: ''\nShuffle is now enabled: ''\nThe playlist has been reversed: ''\nPlaying Next Video: ''\nPlaying Previous Video: ''\nPlaying Next Video Interval: ''\nCanceled next video autoplay: ''\nAutoplay Interruption Timer: ''\n\nDefault Invidious instance has been set to {instance}: ''\nDefault Invidious instance has been cleared: ''\n'The playlist has ended. Enable loop to continue playing': ''\nAge Restricted:\n  This channel is age restricted: ''\n  This video is age restricted: ''\nExternal link opening has been disabled in the general settings: ''\nScreenshot Success: ''\nScreenshot Error: ''\nChannel Hidden: ''\nChannel Unhidden: ''\nTrimmed input must be at least N characters long: ''\nTag already exists: ''\n\nHashtag:\n  Hashtag: ''\n  This hashtag does not currently have any videos: ''\nMoments Ago: ''\nYes: ''\nNo: ''\nOk: ''\nYes, Delete: ''\nYes, Restart: ''\nYes, Open Link: ''\nCancel: ''\n# symbol used to indicate that an item is correct\ncheckmark: ''\n# French is the only language that should change this (they have a space before the colon)\nDisplay Label: ''\nKeyboardShortcutTemplate: ''\nshortcutJoinOperator: ''\nshortcutLabelSeparator: ''\nKeys:\n  alt: ''\n  ctrl: ''\n  shift: ''\n  enter: ''\n  plus: ''\n  arrowdown: ''\n  arrowleft: ''\n  arrowright: ''\n  arrowup: ''\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: ''\n  Sections:\n    Video:\n      Playback: ''\n      General: ''\n    App:\n      Situational: ''\n      General: ''\n  Show Keyboard Shortcuts: ''\n  History Backward: ''\n  History Forward: ''\n  New Window: ''\n  Navigate to Settings: ''\n  Navigate to History: ''\n  Refresh: ''\n  Focus Secondary Search: ''\n  Captions: ''\n  Stats: ''\n  Fullscreen: ''\n  Picture in Picture: ''\n  Large Rewind: ''\n  Play: ''\n  Large Fast Forward: ''\n  Mute: ''\n  Decrease Video Speed: ''\n  Increase Video Speed: ''\n  Full Window: ''\n  Theatre Mode: ''\n  Take Screenshot: ''\n  Minimize Window: ''\n  Close Window: ''\n  Toggle Developer Tools: ''\n  Reset Zoom: ''\n  Zoom In: ''\n  Zoom Out: ''\n  Focus Search: ''\n  Search in New Window: ''\n  Last Frame: ''\n  Next Frame: ''\n  Volume Up: ''\n  Volume Down: ''\n  Small Rewind: ''\n  Small Fast Forward: ''\n  Last Chapter: ''\n  Next Chapter: ''\n  Skip by Tenths: ''\n  Home: ''\n  End: ''\n  Skip to Next Video: ''\n  Skip to Previous Video: ''\n"
  },
  {
    "path": "static/locales/zh-CN.yaml",
    "content": "# Webkit Menu Bar\nFile: '文件'\nQuit: '退出'\nEdit: '编辑'\nUndo: '撤销'\nRedo: '恢复'\nCut: '剪切'\nCopy: '复制'\nPaste: '粘贴'\nDelete: '删除'\nSelect all: '全选'\nToggle Developer Tools: '切换开发者工具'\nActual size: '实际尺寸'\nZoom in: '放大'\nZoom out: '缩小'\nToggle fullscreen: '切换全屏'\nWindow: '窗口'\nMinimize: '最小化'\nClose: '关闭'\nBack: '后退'\nForward: '前进'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: '视频'\n  Shorts: 短视频\n  Live: 直播\n  Posts: 帖子\n  Sort By: 排序依据\n\n# Search Bar\n  Counts:\n    Video Count: 1 个视频 | {count} 个视频\n    Channel Count: 1 个频道 | {count} 个频道\n    Subscriber Count: 1 位订阅者 | {count} 位订阅者\n    View Count: 1 次观看 | {count} 次观看\n    Watching Count: 1 人正在观看 | {count} 人正在观看\n    Like Count: 1 个赞 | {count} 个赞\n    Comment Count: 1 条评论 | {count} 条评论\nSearch / Go to URL: '搜索 / 前往URL'\n  # In Filter Button\nSearch Filters:\n  Search Filters: '搜索过滤'\n  Sort By:\n    Most Relevant: '最相关'\n    Rating: '评分'\n    Upload Date: '上传日期'\n    View Count: '观看数量'\n  Time:\n    Time: '发布时间'\n    Any Time: '任何时间'\n    Last Hour: '一小时内'\n    Today: '今天'\n    This Week: '本周'\n    This Month: '本月'\n    This Year: '本年'\n  Type:\n    Type: '类型'\n    All Types: '所有类型'\n    Videos: '视频'\n    Channels: '频道'\n    #& Playlists\n    Movies: 电影\n  Duration:\n    Duration: '时长'\n    All Durations: '所有时长'\n    Short (< 4 minutes): '短（< 4分钟）'\n    Long (> 20 minutes): '长（> 20分钟）'\n  # On Search Page\n    Medium (4 - 20 minutes): 中等（4-20 分钟）\n  Search Results: '搜索结果'\n  Fetching results. Please wait: '摘取结果中。请稍候'\n  Fetch more results: '摘取更多结果'\n# Sidebar\n  There are no more results for this search: 对于本搜索没有更多结果\n  Features:\n    Subtitles: 字幕\n    Creative Commons: Creative Commons 授权\n    360 Video: 全景视频\n    Features: 特性\n    HD: 高清\n    3D: 三维立体\n    Live: 直播\n    4K: 4K\n    Location: 位置\n    HDR: HDR（高动态范围）\n    VR180: VR180\n  Clear Filters: 清除筛选器\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: '订阅'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': '您的订阅列表目前是空的。如果想要导入订阅，可以转到“数据设置”并选择“导入订阅”，或者搜索频道并订阅。'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 这个配置文件有大量订阅。 强制RSS已防止速率限制\n  Load More Videos: 加载更多视频\n  Error Channels: 有错误的频道\n  Disabled Automatic Fetching: 你仅用了自动订阅获取。刷新订阅在此处看到它们。\n  Empty Channels: 你订阅的频道当前没有任何视频。\n  Subscriptions Tabs: 订阅标签页\n  All Subscription Tabs Hidden: 所有的订阅标签页均被隐藏。要在此查看内容，请在 \"{subsection}\" 部分取消隐藏某些标签页，此部分位于 \"{settingsSection}\"。\n  Load More Posts: 加载更多帖子\n  Empty Posts: 你已订阅的频道当前没有任何帖子。\nTrending:\n  Trending: '热门'\n  Trending Tabs: 流行标签\n  Gaming: 游戏\n  Sports: 体育\nMost Popular: '最流行'\nPlaylists: '播放列表'\nUser Playlists:\n  Your Playlists: '您的播放列表'\n  Search bar placeholder: 搜索播放列表\n  Empty Search Message: 此播放列表中没有匹配你搜索的视频\n  AddVideoPrompt:\n    Search in Playlists: 在播放列表中搜索\n    Save: 保存\n    Toast:\n      \"Video(s) added to {playlistCount} playlists\": \"视频已添加到 1 个播放列表 | 视频已添加到 {playlistCount} 个播放列表\"\n      You haven't selected any playlist yet.: 你尚未选中任何播放列表。\n    Select a playlist to add your N videos to: 选择一个播放列表来添加你的视频 | 选择一个播放列表来添加你的 {videoCount} 个视频\n    N playlists selected: 选中了 {playlistCount} 个播放列表\n    Added {count} Times: 已添加了 {count} 次\n    Allow Adding Duplicate Video(s): 允许添加重复视频\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": 将添加 {videoCount} 个视频，共 {totalVideoCount} 个视频\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": 已添加 {videoCount} 个视频，共 {totalVideoCount} 个视频\n  SinglePlaylistView:\n    Toast:\n      There were no videos to remove.: 没有可删除的视频。\n      Video has been removed: 视频已被删除\n      Playlist has been updated.: 播放列表已更新。\n      There was an issue with updating this playlist.: 更新此播放列表遇到问题。\n      This video cannot be moved up.: 无法上移此视频。\n      This playlist is protected and cannot be removed.: 此播放列表受保护，无法删除。\n      Playlist {playlistName} has been deleted.: 播放列表 {playlistName} 已被删除。\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 播放列表中的某些视频尚未加载。如果仍需复制，请单击此处。\n      This playlist does not exist: 此播放列表不存在\n      Playlist name cannot be empty. Please input a name.: 播放列表名不能为空。请输入一个名称。\n      There was a problem with removing this video: 删除此视频遇到问题\n      \"{videoCount} video(s) have been removed\": 1 则视频已被删除 | {videoCount} 则视频已被删除\n      This video cannot be moved down.: 无法下移此视频。\n      This playlist is now used for quick bookmark: 此播放列表现用于快速添加书签\n      Reverted to use {oldPlaylistName} for quick bookmark: 恢复到使用播放列表 {oldPlaylistName} 进行快速添加书签操作\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: 此播放列表现用于快速添加书签，而非 {oldPlaylistName}。单击此处撤销\n      This playlist is already being used for quick bookmark.: 此播放列表已被用于快速书签。\n      This playlist has a video with a duration error: 此播放列表包含至少一个没有持续时间的视频，排序时将按照持续时间为 0 对待此视频。\n      Video has been removed. Click here to undo.: 视频已被删除。单击此处撤销。\n    Search for Videos: 搜索视频\n  Are you sure you want to delete this playlist? This cannot be undone: 你确定要删除此播放列表吗？此操作无法撤销。\n  Sort By:\n    LatestPlayedFirst: 播放日期（最新优先）\n    EarliestCreatedFirst: 创建日期（最早优先）\n    LatestCreatedFirst: 创建日期（最新优先）\n    EarliestUpdatedFirst: 更新日期（最早优先）\n    NameDescending: Z-A\n    EarliestPlayedFirst: 播放日期（最早优先）\n    LatestUpdatedFirst: 更新日期（最新优先）\n    NameAscending: A-Z\n  You have no playlists. Click on the create new playlist button to create a new one.: 你没有播放列表。单击新建播放列表来新建一个。\n  Remove from Playlist: 从播放列表删除\n  Save Changes: 保存更改\n  CreatePlaylistPrompt:\n    Create: 创建\n    Toast:\n      There was an issue with creating the playlist.: 创建播放列表遇到问题。\n      Playlist {playlistName} has been successfully created.: 成功创建了播放列表 {playlistName}。\n      There is already a playlist with this name. Please pick a different name.: 已经存在同名播放列表。请另选一个名称。\n    New Playlist Name: 新播放列表名\n  This playlist currently has no videos.: 播放列表当前无视频。\n  Add to Playlist: 添加到播放列表\n  Move Video Down: 下移视频\n  Playlist Name: 播放列表名称\n  Remove Watched Videos: 删除已观看的视频\n  Move Video Up: 上移视频\n  Cancel: 取消\n  Delete Playlist: 删除播放列表\n  Create New Playlist: 新建播放列表\n  Edit Playlist Info: 编辑播放列表信息\n  Copy Playlist: 复制播放列表\n  Playlist Description: 播放列表描述\n  Add to Favorites: 添加到播放列表 {playlistName}\n  Enable Quick Bookmark With This Playlist: 开启使用此播放列表来快速添加书签\n  Remove from Favorites: 从播放列表 {playlistName} 删除\n  Playlists with Matching Videos: 有匹配视频的播放列表\n  Quick Bookmark Enabled: 启用了快速书签\n  Cannot delete the quick bookmark target playlist.: 无法删除快速书签目标播放列表。\n  Remove Duplicate Videos: 删除重复视频\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 你确定要从此播放列表删除 1 个已观看视频吗？此操作无法撤销。 | 你确定要从此播放列表删除 {playlistItemCount} 个已观看视频吗？此操作无法撤销。\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: 你确定要从此播放列表中删除 1 个重复视频吗？无法撤销删除。| 你确定要从此播放列表中删除 {playlistItemCount} 个重复视频吗？无法撤销删除。\n  Export Playlist: 导出播放清单\n  The playlist has been successfully exported: 成功导出播放清单\n  TotalTimePlaylist: 总时间：{duration}\n  Export list of URLs: 导出 URL 列表\nHistory:\n  # On History Page\n  History: '历史记录'\n  Watch History: '观看历史记录'\n  Your history list is currently empty.: 您的历史记录列表目前是空的。\n  Search bar placeholder: 在播放历史中搜索\n  Empty Search Message: 历史记录中没有匹配你搜索的视频\n  Case Sensitive Search: 区分大小写的搜索\n  DateOldestHistory: 观看日期（最早优先）\n  DateNewestHistory: 观看日期（最新优先）\nSettings:\n  # On Settings Page\n  Settings: '设置'\n  General Settings:\n    General Settings: '常规'\n    Fallback to Non-Preferred Backend on Failure: '失败时回撤到非首选后端'\n    Enable Search Suggestions: '允许搜索建议'\n    Default Landing Page: '默认加载页面'\n    Locale Preference: '地域偏好'\n    Preferred API Backend:\n      Preferred API Backend: '首选API后端'\n      Local API: '本地API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: '视频观看类型'\n      Grid: '网格'\n      List: '列表'\n    Thumbnail Preference:\n      Thumbnail Preference: '缩略图偏好'\n      Default: '默认'\n      Beginning: '开始'\n      Middle: '中间'\n      End: '结尾'\n      Hidden: 隐藏缩略图\n      Blur: 模糊\n    Region for Trending: '热门区域'\n        #! List countries\n    Check for Updates: 检查更新\n    Check for Latest Blog Posts: 检查最新的博客贴\n    View all Invidious instance information: 浏览所有Invidious实例\n    System Default: 系统默认\n    The currently set default instance is {instance}: 当前设置的默认实例是 {instance}\n    No default instance has been set: 还未设置默认实例\n    Current instance will be randomized on startup: 当前实例在启动时将会随机化\n    Set Current Instance as Default: 将当前实例设为默认\n    Clear Default Instance: 清除默认实例\n    Current Invidious Instance: 当前所用的 Invidious 实例\n    External Link Handling:\n      Ask Before Opening Link: 打开链接前询问\n      No Action: 无操作\n      External Link Handling: 外部链接处理\n      Open Link: 打开链接\n    Auto Load Next Page:\n      Label: 自动加载下一页\n      Tooltip: 自动加载额外页面和评论。\n    Open Deep Links In New Window: 在新窗口打开传递到 FreeTube 的 URL\n    Minimize to system tray: 最小化到系统托盘\n  Theme Settings:\n    Theme Settings: '主题'\n    Match Top Bar with Main Color: '顶部菜单栏对应主颜色'\n    Base Theme:\n      Base Theme: '基本主题'\n      Black: '黑'\n      Dark: '深'\n      Light: '浅'\n      Dracula: 'Dracula'\n      System Default: 系统默认\n      Catppuccin Mocha: Catppuccin Mocha\n      Pastel Pink: 淡粉\n      Hot Pink: 亮粉\n      Nordic: Nordic\n      Solarized Light: 日照白\n      Solarized Dark: 日照黑\n      Gruvbox Dark: Gruvbox Dark\n      Gruvbox Light: Gruvbox Light\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Dark Hard: Everforest Dark （强）\n      Everforest Dark Medium: Everforest Dark （中度）\n      Everforest Dark Low: Everforest Dark （弱）\n      Everforest Light Medium: Everforest Light （中度）\n      Everforest Light Low: Everforest Light （弱）\n      Everforest Light Hard: Everforest Light （强）\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: '主题色'\n      Red: '红'\n      Pink: '粉'\n      Purple: '紫'\n      Deep Purple: '深紫'\n      Indigo: '靛蓝'\n      Blue: '蓝'\n      Light Blue: '浅蓝'\n      Cyan: '青'\n      Teal: '浅灰'\n      Green: '绿'\n      Light Green: '浅绿'\n      Lime: '青柠绿'\n      Yellow: '黄'\n      Amber: '黄褐'\n      Orange: '橙'\n      Deep Orange: '深橙'\n      Dracula Cyan: 'Dracula 青'\n      Dracula Green: 'Dracula 绿'\n      Dracula Orange: 'Dracula 橙'\n      Dracula Pink: 'Dracula 粉'\n      Dracula Purple: 'Dracula 紫'\n      Dracula Red: 'Dracula 红'\n      Dracula Yellow: 'Dracula 黄'\n      Catppuccin Mocha Pink: Catppuccin Mocha 粉\n      Catppuccin Mocha Peach: Catppuccin Mocha 桃红\n      Catppuccin Mocha Yellow: Catppuccin Mocha 黄\n      Catppuccin Mocha Sapphire: Catppuccin Mocha 宝石蓝\n      Catppuccin Mocha Rosewater: Catppuccin Mocha 玫瑰水\n      Catppuccin Mocha Maroon: Catppuccin Mocha 褐紫红\n      Catppuccin Mocha Green: Catppuccin Mocha 绿\n      Catppuccin Mocha Teal: Catppuccin Mocha 蓝绿\n      Catppuccin Mocha Sky: Catppuccin Mocha 天蓝\n      Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo\n      Catppuccin Mocha Mauve: Catppuccin Mocha 紫\n      Catppuccin Mocha Red: Catppuccin Mocha 红\n      Catppuccin Mocha Blue: Catppuccin Mocha 蓝\n      Catppuccin Mocha Lavender: Catppuccin Mocha 薰衣草\n      Solarized Orange: 日照橙\n      Solarized Magenta: 日照品红\n      Solarized Cyan: 日照青\n      Solarized Green: 日照绿\n      Solarized Yellow: 日照黄\n      Solarized Red: 日照红\n      Solarized Blue: 日照蓝\n      Solarized Violet: 日照紫\n      Gruvbox Dark Aqua: Gruvbox Dark 蓝绿\n      Gruvbox Light Red: Gruvbox Light 红\n      Gruvbox Light Blue: Gruvbox Light 蓝\n      Gruvbox Light Purple: Gruvbox Light 紫\n      Gruvbox Dark Yellow: Gruvbox Dark 黄\n      Gruvbox Dark Blue: Gruvbox Dark 蓝\n      Gruvbox Dark Purple: Gruvbox Dark 紫\n      Gruvbox Light Orange: Gruvbox Light 橙\n      Gruvbox Dark Green: Gruvbox Dark 绿\n      Gruvbox Dark Orange: Gruvbox Dark 橙\n      Catppuccin Frappe Rosewater: Catppuccin Frappe 玫瑰水\n      Catppuccin Frappe Lavender: Catppuccin Frappe 薰衣草\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Mauve: Catppuccin Frappe 紫\n      Catppuccin Frappe Maroon: Catppuccin Frappe 褐紫红\n      Catppuccin Frappe Sapphire: Catppuccin Frappe 宝石蓝\n      Catppuccin Frappe Teal: Catppuccin Frappe 蓝绿\n      Catppuccin Frappe Pink: Catppuccin Frappe 粉\n      Catppuccin Frappe Sky: Catppuccin Frappe 天蓝\n      Catppuccin Frappe Red: Catppuccin Frappe 红\n      Catppuccin Frappe Yellow: Catppuccin Frappe 黄\n      Catppuccin Frappe Peach: Catppuccin Frappe 桃红\n      Catppuccin Frappe Green: Catppuccin Frappe 绿\n      Catppuccin Frappe Blue: Catppuccin Frappe 蓝\n      Everforest Dark Red: Everforest Dark红\n      Everforest Dark Orange: Everforest Dark橙\n      Everforest Dark Yellow: Everforest Dark黄\n      Everforest Dark Green: Everforest Dark绿\n      Everforest Dark Aqua: Everforest Dark Aqua\n      Everforest Dark Blue: Everforest Dark蓝\n      Everforest Dark Purple: Everforest Dark紫\n      Everforest Light Red: Everforest Light 红\n      Everforest Light Orange: Everforest Light 橙\n      Everforest Light Yellow: Everforest Light 黄\n      Everforest Light Green: Everforest Light 绿\n      Everforest Light Aqua: Everforest Light Aqua\n      Everforest Light Blue: Everforest Light 蓝\n      Everforest Light Purple: Everforest 淡紫\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n    Secondary Color Theme: '次主题色'\n        #* Main Color Theme\n    UI Scale: UI缩放\n    Expand Side Bar by Default: 默认展开侧边栏\n    Disable Smooth Scrolling: 禁用平滑滚动\n    Hide Side Bar Labels: 隐藏侧边栏标签\n    Hide FreeTube Header Logo: 隐藏 FreeTube 标题徽标\n  Player Settings:\n    Player Settings: '播放器'\n    Play Next Video: '自动播放推荐的视频'\n    Turn on Subtitles by Default: '默认开启字幕'\n    Autoplay Videos: '自动开始视频'\n    Proxy Videos Through Invidious: '通过Invidious代理视频'\n    Autoplay Playlists: '自动播放播放列表视频'\n    Enable Theatre Mode by Default: '默认允许剧场模式'\n    Default Volume: '默认音量'\n    Default Playback Rate: '默认回放速率'\n    Default Video Format:\n      Default Video Format: '默认视频格式'\n      Dash Formats: 'Dash格式'\n      Legacy Formats: '传统格式'\n      Audio Formats: '音频格式'\n    Default Quality:\n      Default Quality: '默认质量'\n      Auto: '自动'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: 自动播放倒计时器\n    Display Play Button In Video Player: 在视频播放器上显示播放按钮\n    Scroll Volume Over Video Player: 在视频播放器上滑动音量\n    Fast-Forward / Rewind Interval: 快进/快退间隔\n    Scroll Playback Rate Over Video Player: 滚动调整视频播放器回放速度\n    Max Video Playback Rate: 视频最大播放速率\n    Video Playback Rate Interval: 视频播放速率间隔\n    Screenshot:\n      Format Label: 截屏格式\n      Quality Label: 截屏质量\n      Ask Path: 询问保存文件夹\n      File Name Label: 文件名模式\n      Error:\n        Forbidden Characters: 禁止的字符\n        Empty File Name: 空文件名\n      Folder Button: 选择文件夹\n      File Name Tooltip: 你可以使用下面的变量。 %Y 年份 4 位数。 %M 月份 2 位数。 %D 天 2 位数。 %H 小时 2 位数。 %N 分钟 2 位数。 %S 秒 2 位数。 %T 毫秒 3 位数。 %s 视频秒。 %t 视频毫秒 3 位数。 %i 视频 ID。\n      Enable: 启用截屏图标\n      Folder Label: 截屏文件夹\n    Enter Fullscreen on Display Rotate: 屏幕旋转时进入全屏\n    Skip by Scrolling Over Video Player: 从视频播放器一侧滚动到另一侧来跳过视频\n    Autoplay Interruption Timer: 自动播放中断计时器\n    Default Viewing Mode:\n      Default Viewing Mode: 默认观看模式\n      Picture in Picture: 画中画\n      External Player: 外部播放器({externalPlayerName})\n      Theater: 影院\n      Full Screen: 全屏\n  Subscription Settings:\n    Subscription Settings: '订阅'\n    Fetch Feeds from RSS: 从RSS摘取推送\n    Fetch Automatically: 自动抓取订阅源\n    Confirm Before Unsubscribing: 避免意外取消订阅\n\n    'Limit the number of videos displayed for each channel': 限制每个频道展示的视频数\n    To: 到\n  Privacy Settings:\n    Are you sure you want to remove your entire watch history?: 您确认想移除您的全部观看历史记录？\n    Are you sure you want to clear out your search cache?: 您确定想清除您的搜索缓存？\n    Save Watched Progress: 保存观看进度\n    Remember History: 记住观看历史\n    Privacy Settings: 隐私\n    Watch history has been cleared: 观看历史记录已清除\n    Remove Watch History: 移除观看历史记录\n    Search cache has been cleared: 搜索缓存已清除\n    Clear Search Cache: 清除搜索缓存\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 您确定您想移除所有订阅和配置文件吗？这无法撤销。\n    Remove All Subscriptions / Profiles: 移除所有订阅 / 配置文件\n    Save Watched Videos With Last Viewed Playlist: 记住上次看过的播放列表中看过的视频 ID\n    All playlists have been removed: 已删除所有播放列表\n    Remove All Playlists: 删除所有播放列表\n    Are you sure you want to remove all your playlists?: 你确定要删除所有播放列表吗？\n    Clear Search History and Cache: 清除搜索历史和缓存\n    Remember Search History: 记住搜索历史\n    Are you sure you want to clear out your search history and cache?: 你确定要清除搜索历史和缓存吗？\n    Search history and cache have been cleared: 已清除搜索历史和缓存\n    Watched Progress Saving Mode:\n      Tooltip: “自动”=每次视频结束以及发生错误（如速率受限和观看会话过期）退出视频页面时进行保存。“半自动”=除视频页面退出外和“自动”类似，可通过位于视频播放器下方的“保存已观看进度”按钮手动保存进度。\n      Modes:\n        Auto: 自动\n        Semi-auto: 半自动\n        Never: 从不\n  Data Settings:\n    Subscriptions have been successfully exported: 订阅已成功导出\n    Invalid subscriptions file: 无效的订阅文件\n    All subscriptions have been successfully imported: 所有订阅已成功导入\n    All subscriptions and profiles have been successfully imported: 所有订阅和配置文件已成功导入\n    Profile object has insufficient data, skipping item: 文件物件数据不足，正在跳过项目\n    How do I import my subscriptions?: 我要如何导入我的订阅？\n    Unknown data key: 未知的数据密钥\n    Unable to write file: 无法写入文件\n    Unable to read file: 无法读取文件\n    All watched history has been successfully exported: 所有观看的历史记录已成功导出\n    All watched history has been successfully imported: 所有观看的历史记录已成功导入\n    History object has insufficient data, skipping item: 历史记录物件数据不足，正在跳过项目\n    Invalid history file: 无效的历史记录文件\n    Import History: 导入历史记录\n    Export History: 导出历史记录\n    Export NewPipe: 导出NewPipe\n    Export YouTube: 导出YouTube\n    Export FreeTube: 导出FreeTube\n    Export Subscriptions: 导出订阅\n    Import Subscriptions: 导入订阅\n    Select Export Type: 选择导出类型\n    Data Settings: 数据\n    Manage Subscriptions: 管理订阅\n    Import Playlists: 导入播放列表\n    Export Playlists: 导出播放列表\n    Playlist insufficient data: '\"{playlist}\" 播放列表数据不足，正在跳过'\n    All playlists has been successfully imported: 已成功导入所有播放列表\n    All playlists has been successfully exported: 所有播放列表已成功导出\n    Playlist File: 播放列表文件\n    Subscription File: 订阅文件\n    History File: 历史文件\n    Export Playlists For Older FreeTube Versions:\n      Tooltip: \"此选项将所有播放列表中的视频导出到一个名为'Favorities'的播放列表文件\\n如何为老版本的 FreeTube 导出&导入播放列表中的视频：\\n 1. 启用此选项来导出播放列表\\n2. 使用“隐私”设置下的“删除所有播放列表”选项来删除所有现存播放列表\\n3. 启动老版本的 FreeTube 并导入导出的播放列表。“\"\n      Label: 为老版本 FreeTube 导出播放列表\n    Search history file: 搜索历史文件\n    Search history: 搜索历史\n    Import search history: 导入搜索历史\n    Export search history: 导出搜索历史\n    All search history has been successfully imported: 成功导入了所有搜索历史\n    All search history has been successfully exported: 成功导出了所有搜索历史\n  Distraction Free Settings:\n    Hide Popular Videos: 隐藏流行视频\n    Hide Trending Videos: 隐藏热门视频\n    Hide Recommended Videos: 隐藏推荐视频\n    Hide Comment Likes: 隐藏评论点赞\n    Hide Live Chat: 隐藏在线聊天\n    Hide Channel Subscribers: 隐藏频道订阅者\n    Hide Video Likes And Dislikes: 隐藏视频喜欢与不喜欢\n    Hide Video Views: 隐藏视频观看数量\n    Distraction Free Settings: 零打扰\n    Hide Active Subscriptions: 隐藏活跃的订阅\n    Hide Playlists: 隐藏播放列表\n    Hide Live Streams: 隐藏直播\n    Hide Sharing Actions: 隐藏分享操作\n    Hide Videos on Watch: '观看时隐藏视频'\n    Hide Comments: 隐藏评论\n    Hide Video Description: 隐藏视频描述\n    Hide Chapters: 隐藏章节\n    Hide Upcoming Premieres: 隐藏即将到来的首映\n    Hide Channels: 隐藏频道中的视频\n    Hide Channels Placeholder: 频道ID\n    Display Titles Without Excessive Capitalisation: 去除标题中对字母大写和标点符号的过度使用\n    Hide Featured Channels: 隐藏精选频道\n    Hide Channel Playlists: 隐藏频道“播放列表”标签\n    Hide Channel Shorts: 隐藏频道“短视频”标签\n    Sections:\n      Side Bar: 侧边栏\n      Channel Page: 频道页\n      Watch Page: 观看页\n      General: 常规\n      Subscriptions Page: 订阅页\n    Hide Channel Podcasts: 隐藏频道“播客”标签\n    Hide Channel Releases: 隐藏频道“发布”标签\n    Hide Subscriptions Shorts: 隐藏订阅短视频\n    Hide Subscriptions Videos: 隐藏订阅视频\n    Hide Subscriptions Live: 隐藏订阅直播\n    Hide Profile Pictures in Comments: 在评论中隐藏个人资料图片\n    Hide Channels Invalid: 提供的频道 ID 无效\n    Hide Channels Disabled Message: 使用 ID 屏蔽了某些频道，这些频道未被处理。当这些 ID 在升级时，功能被停用\n    Hide Channels Already Exists: 频道 ID 已存在\n    Hide Channels API Error: 获取 ID 为所提供值的用户出错。请再次检查 ID 是否正确。\n    Hide Videos, Playlists and Channels Containing Text: 隐藏包含文本的视频和播放列表\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 单词、单词片段或词组\n    Hide Channel Home: 隐藏频道“主页”标签\n    Show Added Items: 显示已添加项目\n    Hide Channel Courses: 隐藏频道“课程”标签\n    Hide Channel Posts: 隐藏频道“帖子”标签\n    Hide Subscriptions Posts: 隐藏订阅者帖子\n  The app needs to restart for changes to take effect. Restart and apply change?: 应用需要重启让修改生效。重启以应用修改？\n  Proxy Settings:\n    Proxy Protocol: 代理协议\n    Enable Tor / Proxy: 使用Tor/代理\n    Proxy Settings: 代理\n    Error getting network information. Is your proxy configured properly?: 获取网络信息错误。您的代理配置是否正确？\n    City: 城市\n    Region: 地区\n    Country: 国家\n    Ip: IP地址\n    Your Info: 你的信息\n    Test Proxy: 测试代理\n    Clicking on Test Proxy will send a request to: 点击测试代理将会发送一个请求给\n    Proxy Port Number: 代理端口号\n    Proxy Host: 代理主机\n    Proxy Warning: FreeTube 没有内置的代理，但可以连接到外部代理，例如像 Tor 这样运行在你机器上的代理，或者如某些 VPN 提供的 SOCKS5 代理这样的外部代理。如果开启了代理选项，请确保你的代理/Tor 正确配置，否则 FreeTube 无法获取任何数据。\n    Proxy Username: 代理用户名\n    Proxy Password: 代理密码\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: 当赞助商时间被跳过时通知\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': 赞助商区域调用的API地址（默认是 https://sponsor.ajay.app）\n    Enable SponsorBlock: 开启赞助商区域\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Auto Skip: 自动跳过\n      Show In Seek Bar: 显示在查找栏中\n      Prompt To Skip: 提示跳过\n      Do Nothing: 什么也不做\n      Skip Option: 跳过选项\n    Category Color: 类别颜色\n    UseDeArrowTitles: 使用 DeArrow 视频标题\n    UseDeArrowThumbnails: 对缩略图使用 DeArrow\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow 缩略图生成器 API Url （默认值 https://dearrow-thumb.ajay.app）\n  External Player Settings:\n    Custom External Player Arguments: 定制外部播放器的参数\n    Custom External Player Executable: 自定义外部播放器的可执行文件\n    Ignore Unsupported Action Warnings: 忽略不支持的行为的警告\n    External Player: 外部播放器\n    External Player Settings: 外部播放器\n    Players:\n      None:\n        Name: 无\n    Ignore Default Arguments: 忽略默认变量\n  Parental Control Settings:\n    Parental Control Settings: 家长控制\n    Show Family Friendly Only: 仅显示“家庭友好”视频\n    Hide Search Bar: 隐藏搜索栏\n    Hide Unsubscribe Button: 隐藏“取消订阅”按钮\n    Hide Uploader on Watch page: 在观看页面隐藏上传者\n  Experimental Settings:\n    Experimental Settings: 实验性\n    Warning: 这些设置是实验性的，启用可能导致崩溃。强烈建议进行备份。使用风险自负！\n    Replace HTTP Cache: 替换 HTTP 缓存\n  Password Dialog:\n    Password: 密码\n    Enter Password To Unlock: 输入密码解锁设置\n  Password Settings:\n    Password Settings: 密码\n    Set Password To Prevent Access: 设置密码防止访问设置\n    Set Password: 设置密码\n    Remove Password: 删除密码\n  Sort Settings Sections (A-Z): 对设置部分进行排序（A-Z）\n  Return to Settings Menu: 返回设置菜单\n  SABR:\n    Label: 启用 SABR 为 DASH 后端\n    Tooltip: SABR 在未来版本中将成为唯一后端，无法禁用。提供此开关是以防提早实实施有不可恢复的问题。\nAbout:\n  #On About page\n  About: '关于'\n  #& About\n#On Channel Page\n  Source code: 源代码\n  Beta: 测试版\n  Website: 网站\n  Blog: 博客\n  Email: 电子邮件\n  Donate: 捐款\n  Credits: 贡献者\n  Translate: 翻译\n  Chat on Matrix: 在 Matrix 上聊天\n  Mastodon: Mastodon\n  FAQ: 常见问题\n  FreeTube Wiki: FreeTube维基\n  Help: 说明\n  GitHub releases: GitHub 版本\n  Please check for duplicates before posting: 请在发布前检查是否与现有问题重复\n  GitHub issues: Github 问题\n  Report a problem: 报告问题\n  Downloads / Changelog: 下载 / 更新日志\n  room rules: 聊天室规则\n  these people and projects: 这些人和项目\n  Discussions: 讨论\n  AGPLv3: AGPLv3\n  Licensed under the {licenseLink}: 在 {licenseLink} 许可证下授权\n  Please read the {roomRulesLink}: 请阅读 {roomRulesLink}\n  FreeTube is made possible by {creditsPageLink}: 没有 {creditsPageLink} 就不可能有 FreeTube\nChannel:\n  Subscribe: '订阅'\n  Unsubscribe: '取消订阅'\n  Search Channel: '搜索频道'\n  Your search results have returned 0 results: '您的搜索结果是0结果'\n  Videos:\n    Videos: '视频'\n    This channel does not currently have any videos: '这个频道目前没有任何视频'\n    Sort Types:\n      Newest: '最新'\n      Oldest: '最早'\n      Most Popular: '最流行'\n  Playlists:\n    Playlists: '播放列表'\n    This channel does not currently have any playlists: '这个频道目前没有任何播放列表'\n    Sort Types:\n      Last Video Added: '最新添加的视频'\n      Newest: '最新'\n      Oldest: '最早'\n  About:\n    About: '关于'\n    Channel Description: '频道描述'\n    Featured Channels: '列出频道'\n    Tags:\n      Search for: 搜索“{tag}”标签\n      Tags: 标签\n    Details: 详情\n    Joined: 已加入\n    Location: 位置\n  Removed subscription from {count} other channel(s): 从{count}个其他频道移除订阅\n  Added channel to your subscriptions: 已新增频道至您的订阅\n  Channel has been removed from your subscriptions: 频道已从您的订阅中移除\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 此频道对观众年龄进行了限制，当前无法在 FreeTube 中查看。\n  Channel Tabs: 频道标签页\n  This channel does not exist: 此频道不存在\n  This channel does not allow searching: 此频道不允许搜索\n  Posts:\n    This channel currently does not have any posts: 此频道当前没有任何帖子\n    votes: '{votes} 票'\n    Reveal Answers: 揭晓答案\n    Hide Answers: 隐藏答案\n    Video hidden by FreeTube: 视频被 FreeTube 隐藏\n    View Full Post: 查看完整帖子\n    Viewing Posts Only Supported By Invidious: 仅 Invidious 支持查看帖子。请转到频道的社区标签页在不用 Invidious 情况下查看内容。\n  Live:\n    Live: 直播\n    This channel does not currently have any live streams: 此频道当前没有任何直播流\n  Shorts:\n    This channel does not currently have any shorts: 此频道目前没有任何短视频\n  Podcasts:\n    This channel does not currently have any podcasts: 此频道当前无任何播客节目\n    Podcasts: 播客\n  Releases:\n    Releases: 发布\n    This channel does not currently have any releases: 此频道当前无任何发布\n  Home:\n    Home: 主页\n    View Playlist: 查看播放列表\n  Courses:\n    Courses: 课程\n    This channel does not currently have any courses: 此频道当前没有任何课程\nVideo:\n  Open in YouTube: '在YouTube中打开'\n  Copy YouTube Link: '复制YouTube链接'\n  Open YouTube Embedded Player: '打开YouTube内嵌播放器'\n  Copy YouTube Embedded Player Link: '复制YouTube内嵌播放器链接'\n  Open in Invidious: '在Invidious中打开'\n  Copy Invidious Link: '复制Invidious链接'\n  Views: '观看'\n  Watched: '已观看'\n  # As in a Live Video\n  Live: '直播'\n  Live Now: '现在直播'\n  Live Chat: '在线聊天'\n  Enable Live Chat: '允许在线聊天'\n  Live Chat is currently not supported in this build.: '在线聊天在此版本中目前不被支持。'\n  Live chat is enabled. Chat messages will appear here once sent.: '在线聊天结束。 聊天信息一旦发送将出现在这里。'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': '在线聊天目前不被Invidious API支持。 需要直接连接YouTube。'\n  Published:\n    In less than a minute: 不到一分钟\n  Published on: '发布于'\n#& Videos\n  Video has been removed from your history: 视频已从您的历史记录中移除\n  Mark As Watched: 标记为已观看\n  Video has been marked as watched: 视频已标记为已观看\n  Remove From History: 从历史记录中移除\n  Autoplay: 自动播放\n  Previous: 上一个\n  Next: 下一个\n  Reverse Playlist: 反向播放列表\n  Shuffle Playlist: 随机播放列表\n  Loop Playlist: 循环播放列表\n  Starting soon, please refresh the page to check again: 即将开始，请刷新页面再次检查\n  Copy Invidious Channel Link: 复制Invidious频道连结\n  Open Channel in Invidious: 在Invidious打开频道\n  Copy YouTube Channel Link: 复制YouTube频道链接\n  Open Channel in YouTube: 在YouTube打开频道\n  Started streaming on: 开始在线直播于\n  Streamed on: 在线直播于\n  Video has been removed from your saved list: 视频已从你的播放列表移除\n  Video has been saved: 视频已保存\n  Save Video: 保存视频到播放列表\n  External Player:\n    OpenInTemplate: 在 {externalPlayer} 中打开\n    video: 视频\n    playlist: 播放列表\n    UnsupportedActionTemplate: '{externalPlayer} 不支持：{action}'\n    OpeningTemplate: 在 {externalPlayer} 中打开 {videoOrPlaylist} …\n    Unsupported Actions:\n      setting a playback rate: 设置播放速率\n      opening specific video in a playlist (falling back to opening the video): 打开播放列表中的特定视频 (退回到打开视频）\n      reversing playlists: 颠倒播放列表\n      shuffling playlists: 打乱播放列表次序\n      looping playlists: 循环播放列表中曲目\n      starting video at offset: 在偏移处开始视频\n      opening playlists: 打开播放列表\n  Sponsor Block category:\n    outro: 结尾部分\n    self-promotion: 自我推销\n    interaction: 互动\n    music offtopic: 无关音乐\n    intro: 介绍\n    sponsor: 赞助者\n    recap: 回顾\n    filler: 过滤器\n  Premieres: 首映\n  Scroll to Bottom: 滚动到底部\n  Show Super Chat Comment: 显示超级聊天评论\n  Upcoming: 即将到来\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 实时聊天对此音视频流不可用。上传者可能禁用了它。\n  Unhide Channel: 显示频道\n  Hide Channel: 隐藏频道\n  More Options: 更多选项\n  Player:\n    Audio Tracks: 音轨\n    Theatre Mode: 影院模式\n    Full Window: 全窗口\n    Exit Full Window: 退出全窗口\n    Take Screenshot: 截屏\n    Show Stats: 显示统计信息\n    Hide Stats: 隐藏统计信息\n    Stats:\n      Stats: 统计信息\n      Video ID: 视频 ID： {videoId}\n      Media Formats: 媒体格式：{formats}\n      Resolution: 分辨率：{width}x{height}{'@'}{frameRate}\n      Player Dimensions: 播放器尺寸： {width}x{height}\n      Bitrate: 比特率：{bitrate} kbps\n      Volume: 音量：{volumePercentage}%\n      Buffered: 已缓冲：{bufferedPercentage}%\n      Dropped Frames / Total Frames: 丢弃帧：{droppedFrames} / 总帧数： {totalFrames}\n      CodecAudio: 编解码器：{audioCodec} ({audioItag})\n      CodecsVideoAudioNoItags: 编解码器：{videoCodec} / {audioCodec}\n      Bandwidth: 带宽：{bandwidth} kbps\n      CodecsVideoAudio: 编解码器：{videoCodec} ({videoItag}) / {audioCodec} ({audioItag})\n    You appear to be offline: 你似乎处于离线状态。\n    Playback will resume automatically when your connection comes back: 网络连接恢复时，将自动继续播放。\n    TranslatedCaptionTemplate: '{language} (翻译自 \"{originalLanguage}\")'\n    Exit Theatre Mode: 推出影院模式\n    Skipped segment: 跳过了 {segmentCategory} 部分\n    Autoplay is off: 自动播放关闭\n    Autoplay is on: 自动播放开启\n  IP block: 你的 IP 地址被 Youtube 禁止观看视频。请试着切换到不同的 VPN 或代理。\n  MembersOnly: 无法用 FreeTube 观看仅供会员的视频，因这些视频需要 Google 登录以及上传者频道的付费会员身份。\n  AgeRestricted: 无法用 FreeTube 观看受限年龄的视频，因这些视频需要 Google 登录并使用验证过年龄的 YouTube 账户。\n  Unlisted: 不公开列出的视频\n  DeArrow:\n    Show Modified Details: 显示修改过的详情\n    Show Original Details: 显示原始详情\n  DRMProtected: FreeTube 无法播放受 DRM 保护的视频，因它们需要专有的、闭源的部件。如果要观看此视频，，请在启用了 DRM 的网页浏览器中在官方 YouTube 网站上观看。\n#& Playlists\n  Watched Progress Saved: 保存了已观看进度\n  Save Watched Progress: 保存已观看进度\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 剩余的预滚动广告时间:：{remindingTimeSeconds} 秒\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 剩余 SABR 后退时间：{remindingTimeSeconds} 秒\n  Popout Live Chat: 弹出式聊天\nPlaylist:\n  #& About\n  View Full Playlist: '查看完整播放列表'\n  Last Updated On: '最后更新于'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: 播放列表\n  Sort By:\n    DateAddedNewest: 添加日期（最新优先）\n    DateAddedOldest: 添加日期（最早优先）\n    AuthorAscending: 作者名（A-Z）\n    AuthorDescending: 作者名（Z-A）\n    VideoTitleDescending: 标题（Z-A)\n    Custom: 自定义\n    VideoTitleAscending: 标题（A-Z）\n    VideoDurationAscending: 持续时间（最短的优先）\n    VideoDurationDescending: 持续时间（最长的优先）\n    PublishedOldest: 发布日期（最早优先）\n    PublishedNewest: 发布日期（最新优先）\nChange Format:\n  Change Media Formats: '更换视频格式'\n  Use Dash Formats: '使用Dash格式'\n  Use Legacy Formats: '使用传统格式'\n  Use Audio Formats: '使用音频格式'\n  Audio formats are not available for this video: 这个视频没有音频格式\n  Dash formats are not available for this video: 这个视频没有Dash格式\n  Legacy formats are not available for this video: 旧格式对这个视频不可用\nShare:\n  Share Video: '分享视频'\n  Share Playlist: '分享播放列表'\n  Copy Link: '复制链接'\n  Open Link: '打开链接'\n  Copy Embed: '复制内嵌'\n  Open Embed: '打开内嵌'\n  # On Click\n  Invidious URL copied to clipboard: '复制Invidious URL到剪贴板'\n  Invidious Embed URL copied to clipboard: '复制Invidious内嵌URL到剪贴板'\n  YouTube URL copied to clipboard: '复制YouTube URL到剪切板'\n  YouTube Embed URL copied to clipboard: '复制YouTube内嵌URL到剪贴板'\n  Include Timestamp: 包含时间戳\n  YouTube Channel URL copied to clipboard: YouTube频道URL已复制到剪贴板\n  Invidious Channel URL copied to clipboard: Invidious频道URL已复制到剪贴板\n  Share Channel: 分享频道\n  Share Post: 分享帖子\nMini Player: '迷你播放器'\nComments:\n  Comments: '评论'\n  Click to View Comments: '点击观看评论'\n  Getting comment replies, please wait: '获取评论中，请稍候'\n  Hide Comments: '隐藏评论'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: '这个视频没有评论'\n  Load More Comments: '加载更多评论'\n  There are no more comments for this video: 此视频无更多评论\n  Newest first: 最新优先\n  Top comments: 最热评论\n  Show More Replies: 显示更多回复\n  Pinned by: 置顶人\n  Member: 成员\n  Hearted: 喜欢的\n  View {replyCount} replies: 查看 1 条回复|查看 {replyCount} 条回复\n  Subscribed: 已订阅\n  There are no comments available for this post: 此帖子没有评论\n  Hide {replyCount} replies: 隐藏 1 条回复| 隐藏 {replyCount} 条回复\n  View 1 reply from {channelName}: 查看 1 条来自 {channelName}的回复\n  View {replyCount} replies from {channelName} and others: 查看 {replyCount} 条来自 {channelName} 和其他频道的回复\nUp Next: 'Up Next'\n\n# Toast Messages\nLocal API Error (Click to copy): '本地API错误（点击复制）'\nInvidious API Error (Click to copy): 'Invidious API错误（点击复制）'\nFalling back to Invidious API: '回退到Invidious API'\nFalling back to Local API: '回退到本地API'\nLoop is now disabled: '循环播放现在被禁用'\nLoop is now enabled: '循环播放现在被允许'\nShuffle is now disabled: '随机播放现在被禁用'\nShuffle is now enabled: '随机播放现在被禁用'\nPlaying Next Video: '将播放下一视频'\nPlaying Previous Video: '将播放上一视频'\nCanceled next video autoplay: '取消的自动播放下一视频'\n'The playlist has ended. Enable loop to continue playing': '播放列表已结束。 允许循环播放以继续播放'\n\nYes: '是'\nNo: '否'\nLocale Name: 简体中文\nProfile:\n  '{profile} is now the active profile': '{profile}现在是使用中的配置文件'\n  Removed {profile} from your profiles: 已从您的配置文件移除{profile}\n  Your default profile has been set to {profile}: 您的默认配置文件已设定为{profile}\n  Your default profile has been changed to your primary profile: 您的默认配置文件已变为您的主配置文件\n  Profile has been updated: 配置文件已更新\n  Profile has been created: 配置文件已建立\n  Your profile name cannot be empty: 您的配置文件名不能是空的\n  All subscriptions will also be deleted.: 所有订阅将会被删除。\n  Are you sure you want to delete this profile?: 您确认您想删除这个配置文件吗？\n  Delete Profile: 删除配置文件\n  Make Default Profile: 设为默认配置文件\n  Update Profile: 更新配置文件\n  Create Profile: 建立配置文件\n  Profile Preview: 配置文件预览\n  Edit Profile: 编辑配置文件\n  Create New Profile: 建立新配置文件\n  Profile Manager: 配置文件管理器\n  Custom Color: 自定义颜色\n  Color Picker: 选色器\n  All Channels: 所有频道\n  Profile Select: 选择配置文件\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 您确定您想删除选择的频道？ 这不会从其他配置文件中删除频道。\n  Add Selected To Profile: 添加选择的到配置文件\n  Delete Selected: 删除选择的\n  '{number} selected': '{number}选择的'\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 这是您的主配置文件。 您确定您想删除选择的频道？ 相同的频道中任何找到的配置文件会被删除。\n  No channel(s) have been selected: 无频道已选择\n  Select None: 全不选\n  Select All: 全选\n  Other Channels: 其他频道\n  Subscription List: 订阅列表\n  Profile Settings: 个人资料\n  Profile Filter: 个人资料筛选器\n  Toggle Profile List: 切换个人资料列表\n  Open Profile Dropdown: 打开配置文件下拉菜单\n  Close Profile Dropdown: 关闭配置文件下拉菜单\n  Profile Name: 配置文件名\n  Edit Profile Name: 编辑配置文件名\n  Create Profile Name: 创建配置文件名\nThe playlist has been reversed: 播放列表已反转\nA new blog is now available, {blogTitle}. Click to view more: 已有新的博客，{blogTitle}。点击以查看更多\nDownload From Site: 从网站下载\nVersion {versionNumber} is now available!  Click for more details: 版本{versionNumber}已可使用！  点击以取得更多信息\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 没有这个视频因为缺少格式。这个可能发生由于国家不可用。\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: 启用后，FreeTube 将使用 RSS 而非默认方式来取得您的订阅推送。RSS 更快而且可避免 IP 封锁，但不提供某些信息，如视频长度，直播状态或帖子\n    Fetch Automatically: 启用后，打开新窗口和开启 FreeTube 时，FreeTube 会自动抓取你的订阅源。\n  Player Settings:\n    Default Video Format: 设置播放视频时使用的格式。DASH 格式可以播放更高质量的视频。 传统格式限制为最大 360p，但使用较少的带宽。 音频格式是纯音频流。\n    Proxy Videos Through Invidious: 将连接到 Invidious而非直接连接到 YouTube 来提供影片。\n    Scroll Playback Rate Over Video Player: 当光标位于视频上方时，按住 Control 键(Mac 上的 Command 键)，前后滚动鼠标滚轮，控制播放速度。按住 Control 键(Mac 上的 Command 键)，左键点击鼠标快速返回到默认播放速率(1x，除非在设置中改变了数值)。\n    Skip by Scrolling Over Video Player: 使用滚轮跳过视频，MPV 风格。\n  General Settings:\n    Invidious Instance: FreeTube 要连接到哪个 Invidious 实例进行 API 调用。\n    Thumbnail Preference: FreeTube 中所有缩略图会被替换为模糊不清或隐藏的视频帧而非默认缩略图。\n    Fallback to Non-Preferred Backend on Failure: 当您的首选API有问题时，FreeTube将自动尝试使用您的非首选API 作为后备方案。\n    Preferred API Backend: 选择FreeTube 要用于取得数据的后端。本地API 是内置提取器。Invidious API需要Invidious服务器才能连接。\n    Region for Trending: 热门区域让您挑选您想要显示哪个国家的热门视频。\n    External Link Handling: \"选择单击一个无法在 FreeTube 中打开的链接时触发的默认操作。\\n默认情况下，FreeTube 将在您的默认浏览器中打开所点击链接。\\n\"\n    Open Deep Links In New Window: 在新窗口由浏览器的重定向扩展或命令行变量传递到 FreeTube 的 URL。\n  External Player Settings:\n    External Player: 选择一个外部播放器将在缩略图上显示一个图标，用于在外部播放器中打开视频(播放列表，如果支持)。警告，Invidious 设置不影响外部播放器。\n    Custom External Player Executable: 默认情况下，FreeTube 假设选择的外部播放器可以通过 PATH 环境变量找到。如果需要，可以在这里设置自定义路径。\n    Ignore Warnings: 当前外部播放器不支持当前操作时(例如，颠倒播放列表文件顺序)，抑制警告。\n    DefaultCustomArgumentsTemplate: \"(默认: '{defaultCustomArguments}')\"\n    Custom External Player Arguments: 任何你希望传递给外部播放器的自定义命令行参数。\n    Ignore Default Arguments: 不要向外部播放器发送除视频 URL 外的任何默认变量（如播放速度、播放列表 URL 等）。自定义变量仍将被传递。\n  Experimental Settings:\n    Replace HTTP Cache: 禁用 Electron 基于磁盘的 HTTP 缓存，启用自定义内存中图像缓存。会增加内存的使用。\n  Distraction Free Settings:\n    Hide Channels: 输入频道 ID 使其中的所有视频、播放列表和频道本身不出现在搜索结果、时下流行、最受欢迎和推荐中。 输入的频道 ID 必须完全匹配，并且区分大小写。\n    Hide Subscriptions Live: 此设置被应用级的 \"{appWideSetting}\" 设置所覆盖，\"{appWideSetting}\" 位于 \"{subsection}\" 部分，该部分在 \"{settingsSection}\" 中\n    Hide Videos, Playlists and Channels Containing Text: 输入单词、单词片段或词组（区分大小写）在整个 FreeTube 软件中隐藏所有原始标题包含这些内容的视频和播放列表。注意：历史记录、你的播放列表和播放列表内的视频不受限制约束。\n    Hide Videos on Watch: 在订阅和频道页上的视频、短视频和直播标签页中隐藏已观看的视频。这不影响频道页上的主页\n  SponsorBlock Settings:\n    UseDeArrowTitles: 使用来自 DeArrow 的用户提交的标题替换原始视频标题。\n    UseDeArrowThumbnails: 用来自 DeArrow 的缩略图替换原本的视频缩略图。\nMore: 更多\nOpen New Window: 打开新窗口\nSearch Bar:\n  Clear Input: 清空输入\n  Remove: 删除\nAre you sure you want to open this link?: 您确定要打开此链接吗？\nUnknown YouTube url type, cannot be opened in app: 未知的 YouTube url 类型，不能在应用程序中打开\nExternal link opening has been disabled in the general settings: 外部链接打开在常规设置中被禁用\nDefault Invidious instance has been set to {instance}: 默认的 Invidious 实例已被设置为 {instance}\nPlaying Next Video Interval: 马上播放下一个视频。单击取消。| {nextVideoInterval} 秒内播放下个视频。单击取消。 | {nextVideoInterval} 秒内播放下个视频。单击取消。\nDefault Invidious instance has been cleared: 已清除默认的 Invidious 实例\nScreenshot Error: 截屏失败。{error}\nScreenshot Success: 已保存截屏\nNew Window: 新窗口\nChannels:\n  Search bar placeholder: 搜索频道\n  Count: 找到了 {number} 个频道。\n  Channels: 频道\n  Title: 频道列表\n  Empty: 你的频道列表当前为空。\n  Unsubscribe Prompt: 你确定你要取消订阅 \"{channelName}\" 吗？\nClipboard:\n  Copy failed: 未能复制到剪贴板\n  Cannot access clipboard without a secure connection: 没有安全连接无法访问剪贴板\nChapters:\n  Chapters: 章节\n  Key Moments: 关键时刻\nPreferences: 选项\nOk: 好\nHashtag:\n  Hashtag: 话题标签\n  This hashtag does not currently have any videos: 此话题标签下当前没有任何短视频\nGo to page: 转到页{page}\nChannel Hidden: '{channel} 频道已添加到频道过滤器'\nChannel Unhidden: 从频道过滤器删除了{channel} 频道\nTag already exists: '\"{tagName}\" 标签已存在'\nTrimmed input must be at least N characters long: 缩减输入的长度需至少为 1 个字符 | 缩减输入的长度需至少为 {length} 个字符\nClose Banner: 关闭横幅\nAge Restricted:\n  This video is age restricted: 此视频有年龄限制\n  This channel is age restricted: 此频道有年龄限制\ncheckmark: ✓\nDisplay Label: '{label}: {value}'\nMoments Ago: 片刻前\nFeed:\n  Feed Last Updated: '{feedName} 上次更新: {date}'\n  Refresh Feed: 刷新 {subscriptionName}\nYes, Open Link: 是，打开链接\nCancel: 取消\nYes, Delete: 是，删除\nYes, Restart: 是，重启\nSearch character limit: 搜索词超过了 {searchCharacterLimit} 字符的上限\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: 字幕\n    Closed Captions: 隐藏式字幕\n    New: 新的\n    3D: 3D\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: 向下箭头 (↓)\n  arrowleft: 向左箭头(←)\n  arrowright: 向右箭头(→)\n  arrowup: 向上箭头 (↑)\n  enter: Enter\n  shift: Shift\n  plus: +\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nRight-click or hold to see history: 右键单击或静止不动查看历史记录\nAutoplay Interruption Timer: 由于 {autoplayInterruptionIntervalHours} 小时不活跃，自动播放被取消\nDescription:\n  Expand Description: '...更多'\n  Collapse Description: 显示较少\nKeyboardShortcutPrompt:\n  Keyboard Shortcuts: 键盘快捷键\n  Sections:\n    Video:\n      Playback: 视频： 播放\n      General: 视频： 常规\n    App:\n      General: 应用：常规\n      Situational: 应用：情景\n  Show Keyboard Shortcuts: 显示键盘快捷键\n  History Backward: 往前一页\n  History Forward: 往后一页\n  New Window: 创建新窗口\n  Refresh: 刷新订阅源最新内容\n  Focus Secondary Search: 聚焦第二搜索栏（如果有的话）\n  Captions: 开/关字幕\n  Picture in Picture: 切换画中画模式\n  Large Rewind: 后退 10 秒/根据当前视频播放速率后退\n  Play: 播放/暂停\n  Large Fast Forward: 前进 10 秒/根据当前视频播放速率快进\n  Mute: 切换静音\n  Decrease Video Speed: 根据视频播放速率间隔降低视频速度\n  Increase Video Speed: 根据视频播放速率间隔提高视频速度\n  Full Window: 切换整个窗口\n  Theatre Mode: 切换影院模式\n  Take Screenshot: 截屏\n  Close Window: 关闭窗口\n  Toggle Developer Tools: 切换开发者工具\n  Reset Zoom: 重置缩放级别/用户界面缩放比例\n  Zoom In: 缩小\n  Focus Search: 聚焦搜索栏\n  Search in New Window: 在新窗口中搜索\n  Last Frame: 前一帧（暂停时）\n  Next Frame: 下一帧（暂停时）\n  Volume Down: 降低音量\n  Small Rewind: 根据后退间隔和当前视频播放速率后退 X 秒\n  Small Fast Forward: 根据快进间隔和当前视频播放速率快进 X 秒\n  Last Chapter: 上一章节\n  Skip by Tenths: 按比例跳过视频（3 表示跳到持续时间的 30%）\n  Navigate to History: 导航到历史页面\n  Volume Up: 提高音量\n  Navigate to Settings: 导航到设置页面\n  Stats: 显示视频统计数据\n  Fullscreen: 切换全屏\n  Minimize Window: 最小化窗口\n  Zoom Out: 放大\n  Next Chapter: 下一章节\n  End: 跳转到视频结尾\n  Home: 跳转到视频开头\n  Skip to Next Video: 跳到播放列表中下一个视频或下一个推荐的视频\n  Skip to Previous Video: 跳到播放列表中前一个视频\nshortcutLabelSeparator: ｜\nCompact side navigation: 紧凑侧边栏导航\nExpand side navigation: 扩展侧边栏导航\n"
  },
  {
    "path": "static/locales/zh-TW.yaml",
    "content": "# Webkit Menu Bar\nFile: '檔案'\nQuit: '結束'\nEdit: '編輯'\nUndo: '復原'\nRedo: '恢復'\nCut: '剪下'\nCopy: '複製'\nPaste: '貼上'\nDelete: '刪除'\nSelect all: '全選'\nToggle Developer Tools: '切換開發者工具'\nActual size: '實際大小'\nZoom in: '放大'\nZoom out: '縮小'\nToggle fullscreen: '切換全螢幕'\nWindow: '視窗'\nMinimize: '縮至最小'\nClose: '關閉'\nBack: '返回'\nForward: '前進'\n\n# Global\n# Anything shared among components / views should be put here\nGlobal:\n  Videos: '影片'\n  Shorts: 短片\n  Live: 直播\n  Posts: 貼文\n  Sort By: '排序方式'\n\n# Search Bar\n  Counts:\n    Video Count: 1 部影片 | {count} 部影片\n    Channel Count: 1 個頻道 | {count} 個頻道\n    Subscriber Count: 1 個訂閱者 | {count} 個訂閱者\n    View Count: 1 次檢視 | {count} 次檢視\n    Watching Count: 1 個正在觀看 | {count} 個正在觀看\n    Comment Count: 1 則留言 | {count} 則留言\n    Like Count: 1 個喜歡 | {count} 個喜歡\nSearch / Go to URL: '搜尋/ 前往網址'\n  # In Filter Button\nSearch Filters:\n  Search Filters: '搜尋過濾器'\n  Sort By:\n    Most Relevant: '最相關'\n    Rating: '評分'\n    Upload Date: '上傳日期'\n    View Count: '觀看次數'\n  Time:\n    Time: '時間'\n    Any Time: '任何時間'\n    Last Hour: '最近一小時'\n    Today: '今天'\n    This Week: '本週'\n    This Month: '本月'\n    This Year: '今年'\n  Type:\n    Type: '類型'\n    All Types: '所有類別'\n    Videos: '影片'\n    Channels: '頻道'\n    #& Playlists\n    Movies: 電影\n  Duration:\n    Duration: '影片長度'\n    All Durations: '所有長度'\n    Short (< 4 minutes): '短（小於4分鐘）'\n    Long (> 20 minutes): '長（大於20分鐘）'\n  # On Search Page\n    Medium (4 - 20 minutes): 中（4到20 分鐘）\n  Search Results: '搜尋結果'\n  Fetching results. Please wait: '正在擷取結果。請稍候'\n  Fetch more results: '擷取更多結果'\n# Sidebar\n  There are no more results for this search: 此搜尋無更多結果\n  Features:\n    Live: 直播\n    4K: 4K\n    360 Video: 360 影片\n    Location: 位置\n    HDR: HDR\n    VR180: VR180\n    Features: 功能\n    HD: HD\n    Subtitles: 字幕\n    Creative Commons: 創用CC\n    3D: 3D\n  Clear Filters: 清除篩選\nSubscriptions:\n    # On Subscriptions Page\n  Subscriptions: '訂閱'\n  'Your Subscription list is currently empty. Start adding subscriptions to see them here.': '您的訂閱清單目前是空的。如果您想要匯入您的訂閱，您可以前往「資料設定」，然後選取「匯入訂閱」，或者您也可以搜尋頻道並訂閱。'\n  This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: 這個設定檔有大量訂閱。 強制RSS以防止速率限制\n  Load More Videos: 載入更多影片\n  Error Channels: 有錯誤的頻道\n  Disabled Automatic Fetching: 您已停用自動訂閱擷取。重新整理訂閱以在此處檢視。\n  Empty Channels: 您訂閱的頻道目前沒有任何影片。\n  Subscriptions Tabs: 訂閱分頁\n  All Subscription Tabs Hidden: 所有訂閱分頁均已隱藏。要檢視此處的內容，請取消隱藏「{settingsSection}」中「{subsection}」區塊中的一些分頁。\n  Load More Posts: 載入更多影片\n  Empty Posts: 您訂閱的頻道目前沒有任何影片。\nTrending:\n  Trending: '發燒影片'\n  Trending Tabs: 熱門分頁\n  Gaming: 遊戲\n  Sports: 運動\nMost Popular: '最受歡迎'\nPlaylists: '播放清單'\nUser Playlists:\n  Your Playlists: '您的播放清單'\n  Search bar placeholder: 搜尋播放清單\n  Empty Search Message: 此播放清單中沒有與您的搜尋相符的影片\n  This playlist currently has no videos.: 此播放清單目前沒有影片。\n  Create New Playlist: 建立新播放清單\n  Add to Playlist: 新增至播放清單\n  Move Video Up: 向上移動影片\n  Move Video Down: 向下移動影片\n  Remove from Playlist: 從播放清單移除\n  Playlist Name: 播放清單名稱\n  Playlist Description: 播放清單描述\n  Cancel: 取消\n  Edit Playlist Info: 編輯播放清單資訊\n  Copy Playlist: 複製播放清單\n  Delete Playlist: 刪除播放清單\n  Are you sure you want to delete this playlist? This cannot be undone: 您確定您想要刪除播放清單嗎？這無法還原。\n  Sort By:\n    NameAscending: A-Z\n    NameDescending: Z-A\n    LatestCreatedFirst: 建立日期（最新）\n    LatestUpdatedFirst: 更新日期（最新）\n    EarliestUpdatedFirst: 更新日期（最舊）\n    LatestPlayedFirst: 播放日期（最新）\n    EarliestPlayedFirst: 播放日期（最舊）\n    EarliestCreatedFirst: 建立日期（最舊）\n  SinglePlaylistView:\n    Toast:\n      This video cannot be moved up.: 此影片無法向上移動。\n      This video cannot be moved down.: 此影片無法向下移動。\n      Video has been removed: 影片已被移除\n      There was a problem with removing this video: 移除此影片時發生問題\n      Some videos in the playlist are not loaded yet. Click here to copy anyway.: 播放清單中的某些影片尚未載入。請按此處複製。\n      Playlist name cannot be empty. Please input a name.: 播放清單名稱不能為空。請輸入名稱。\n      Playlist has been updated.: 播放清單已更新。\n      There were no videos to remove.: 沒有影片要移除。\n      This playlist is protected and cannot be removed.: 此播放清單受保護且無法移除。\n      There was an issue with updating this playlist.: 更新此播放清單時發生問題。\n      \"{videoCount} video(s) have been removed\": 移除了 1 部影片 | 移除了 {videoCount} 部影片\n      Playlist {playlistName} has been deleted.: 播放清單 {playlistName} 已刪除。\n      This playlist does not exist: 此播放清單不存在\n      This playlist is now used for quick bookmark: 此播放清單現在用於快速書籤\n      This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: 此播放清單現在用於快速書籤，而非 {oldPlaylistName}。點擊此處撤銷\n      Reverted to use {oldPlaylistName} for quick bookmark: 恢復為使用 {oldPlaylistName} 進行快速書籤\n      This playlist is already being used for quick bookmark.: 此播放清單已用於快速書籤。\n      This playlist has a video with a duration error: 此播放清單至少包含一個沒有時間長度的影片，則會以時間長度為零的方式排序。\n      Video has been removed. Click here to undo.: 已移除影片。點選此處以還原。\n    Search for Videos: 搜尋影片\n  AddVideoPrompt:\n    Select a playlist to add your N videos to: 選擇要新增影片的播放清單 | 選擇播放清單以將您的 {videoCount} 部影片新增至其中\n    N playlists selected: 已選取 {playlistCount}\n    Search in Playlists: 在播放清單中搜尋\n    Save: 儲存\n    Toast:\n      You haven't selected any playlist yet.: 您尚未選取任何播放清單。\n      \"Video(s) added to {playlistCount} playlists\": \"影片已新增至 1 個播放清單 | 影片已新增至 {playlistCount} 個播放清單\"\n    Added {count} Times: 已新增 | 新增了 {count} 次\n    Allow Adding Duplicate Video(s): 允許新增重複影片\n    \"{videoCount}/{totalVideoCount} Videos Already Added\": 已新增 {videoCount}/{totalVideoCount} 部影片\n    \"{videoCount}/{totalVideoCount} Videos Will Be Added\": 將會新增 {videoCount}/{totalVideoCount} 部影片\n  CreatePlaylistPrompt:\n    New Playlist Name: 新播放清單名稱\n    Toast:\n      Playlist {playlistName} has been successfully created.: 已成功建立播放清單 {playlistName}。\n      There was an issue with creating the playlist.: 建立播放清單時發生問題。\n      There is already a playlist with this name. Please pick a different name.: 已有一個同名的播放清單。請挑選其他名稱。\n    Create: 建立\n  You have no playlists. Click on the create new playlist button to create a new one.: 您沒有播放清單。按一下建立新播放清單按鈕以建立新的。\n  Save Changes: 儲存變更\n  Remove Watched Videos: 移除已觀看的影片\n  Add to Favorites: 新增至 {playlistName}\n  Remove from Favorites: 從 {playlistName} 移除\n  Enable Quick Bookmark With This Playlist: 啟用此播放清單的快速書籤\n  Playlists with Matching Videos: 包含相符影片的播放清單\n  Quick Bookmark Enabled: 已啟用快速書籤\n  Cannot delete the quick bookmark target playlist.: 無法刪除快速書籤目標播放清單。\n  Remove Duplicate Videos: 移除重複的影片\n  Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: 您確定要從此播放清單中刪除 1 個重複的影片嗎？這無法還原。 | 您確定要從此播放清單中刪除 {playlistItemCount} 個重複影片嗎？這無法還原。\n  Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: 您確定要從此播放清單中刪除 1 個觀看過的影片嗎？這無法還原。 | 您確定要從此播放清單中刪除已觀看的 {playlistItemCount} 個影片嗎？這無法還原。\n  Export Playlist: 匯出此播放清單\n  The playlist has been successfully exported: 播放清單已成功匯出\n  TotalTimePlaylist: '總時長: {duration}'\n  Export list of URLs: 匯出 URL 清單\nHistory:\n  # On History Page\n  History: '觀看紀錄'\n  Watch History: '觀看紀錄'\n  Your history list is currently empty.: 尚未觀賞過任何影片，因此觀看紀錄清單為空。\n  Search bar placeholder: 在觀看紀錄中搜尋\n  Empty Search Message: 您的歷史紀錄中沒有與您的搜尋相符的影片\n  Case Sensitive Search: 區分大小寫的搜尋\n  DateOldestHistory: 觀看日期（最新）\n  DateNewestHistory: 觀看日期（最新）\nSettings:\n  # On Settings Page\n  Settings: '設定'\n  General Settings:\n    General Settings: '一般'\n    Fallback to Non-Preferred Backend on Failure: '連線失敗時連線到非預設伺服器'\n    Enable Search Suggestions: '啟用搜尋建議'\n    Default Landing Page: '預設加載頁面'\n    Locale Preference: '介面語言'\n    Preferred API Backend:\n      Preferred API Backend: '偏好API伺服器'\n      Local API: '本機 API'\n      Invidious API: 'Invidious API'\n    Video View Type:\n      Video View Type: '影片觀看類別'\n      Grid: '網格'\n      List: '清單'\n    Thumbnail Preference:\n      Thumbnail Preference: '影片縮圖偏好'\n      Default: '預設'\n      Beginning: '片頭'\n      Middle: '中間'\n      End: '片尾'\n      Hidden: 隱藏\n      Blur: 模糊\n    Region for Trending: '發燒影片區域'\n        #! List countries\n    Check for Latest Blog Posts: 檢查最新的部落格貼文\n    Check for Updates: 檢查更新\n    View all Invidious instance information: 檢視所有 Invidious 站台的資訊\n    System Default: 系統預設值\n    Clear Default Instance: 清除預設站台\n    Set Current Instance as Default: 設定目前站台為預設值\n    Current instance will be randomized on startup: 目前站台將在啟動時隨機選擇\n    No default instance has been set: 未設定預設的站台\n    The currently set default instance is {instance}: 目前設定的預設站台為 {instance}\n    Current Invidious Instance: 目前的 Invidious 站台\n    External Link Handling:\n      No Action: 無動作\n      Ask Before Opening Link: 開啟連結前詢問\n      Open Link: 開啟連結\n      External Link Handling: 外部連結處理\n    Auto Load Next Page:\n      Tooltip: 自動載入額外頁面與留言。\n      Label: 自動載入下一頁\n    Open Deep Links In New Window: 在新視窗中開啟傳遞給 FreeTube 的 URL\n    Minimize to system tray: 最小化至系統匣\n  Theme Settings:\n    Theme Settings: '主題'\n    Match Top Bar with Main Color: '頂部功能表欄對應主色彩'\n    Base Theme:\n      Base Theme: '基本主題'\n      Black: '黑色'\n      Dark: '深色'\n      Light: '淺色'\n      Dracula: 'Dracula'\n      System Default: 系統預設值\n      Catppuccin Mocha: 卡布奇諾摩卡\n      Pastel Pink: 淡粉紅色\n      Hot Pink: 亮粉紅色\n      Nordic: 北歐\n      Solarized Dark: 暖色調 暗色\n      Solarized Light: Solarized Light\n      Gruvbox Dark: Gruvbox 深色\n      Gruvbox Light: Gruvbox 淺色\n      Catppuccin Frappe: Catppuccin Frappe\n      Everforest Light Low: 永恆森林 輕度 淺色\n      Everforest Dark Hard: 永恆森林 重度 深色\n      Everforest Dark Medium: 永恆森林 中度 深色\n      Everforest Dark Low: 永恆森林 輕度 深色\n      Everforest Light Hard: 永恆森林 重度 淺色\n      Everforest Light Medium: 永恆森林 中度 淺色\n      Catppuccin Latte: Catppuccin Latte\n    Main Color Theme:\n      Main Color Theme: '主題色'\n      Red: '紅'\n      Pink: '粉'\n      Purple: '紫'\n      Deep Purple: '深紫'\n      Indigo: '靛藍'\n      Blue: '藍'\n      Light Blue: '淺藍'\n      Cyan: '青'\n      Teal: '淺灰'\n      Green: '綠'\n      Light Green: '淺綠'\n      Lime: '青檸綠'\n      Yellow: '黃'\n      Amber: '黃褐'\n      Orange: '橙'\n      Deep Orange: '深橙'\n      Dracula Cyan: '德古拉 青'\n      Dracula Green: '德古拉 綠'\n      Dracula Orange: '德古拉 橙'\n      Dracula Pink: '德古拉 粉'\n      Dracula Purple: '德古拉 紫'\n      Dracula Red: '德古拉 红'\n      Dracula Yellow: '德古拉 黄'\n      Catppuccin Mocha Yellow: 卡布奇諾摩卡黃色\n      Catppuccin Mocha Green: 卡布奇諾摩卡綠色\n      Catppuccin Mocha Flamingo: 卡布奇諾摩卡紅鶴\n      Catppuccin Mocha Teal: 卡布奇諾摩卡藍綠色\n      Catppuccin Mocha Rosewater: 卡布奇諾摩卡玫瑰水\n      Catppuccin Mocha Lavender: 卡布奇諾摩卡薰衣草色\n      Catppuccin Mocha Blue: 卡布奇諾摩卡藍色\n      Catppuccin Mocha Pink: 卡布奇諾摩卡粉紅\n      Catppuccin Mocha Red: 卡布奇諾摩卡紅色\n      Catppuccin Mocha Mauve: 卡布奇諾摩卡紫紅色\n      Catppuccin Mocha Maroon: 卡布奇諾摩卡褐紅色\n      Catppuccin Mocha Sky: 卡布奇諾摩卡天藍色\n      Catppuccin Mocha Peach: 卡布奇諾摩卡桃紅色\n      Catppuccin Mocha Sapphire: 卡布奇諾摩卡藍寶石色\n      Solarized Yellow: Solarized 黃色\n      Solarized Orange: Solarized 橘色\n      Solarized Red: Solarized 紅色\n      Solarized Magenta: Solarized 洋紅色\n      Solarized Violet: Solarized 紫色\n      Solarized Blue: Solarized 藍色\n      Solarized Cyan: Solarized 青色\n      Solarized Green: Solarized 綠色\n      Gruvbox Light Red: Gruvbox 淺紅色\n      Gruvbox Dark Green: Gruvbox 深綠色\n      Gruvbox Dark Yellow: Gruvbox 深黃色\n      Gruvbox Dark Blue: Gruvbox 深藍色\n      Gruvbox Dark Purple: Gruvbox 深紫色\n      Gruvbox Dark Aqua: Gruvbox 深水藍色\n      Gruvbox Dark Orange: Gruvbox 深橘色\n      Gruvbox Light Blue: Gruvbox 淺藍色\n      Gruvbox Light Purple: Gruvbox 淺紫色\n      Gruvbox Light Orange: Gruvbox 淺橘色\n      Catppuccin Frappe Flamingo: Catppuccin Frappe Flamingo\n      Catppuccin Frappe Pink: Catppuccin Frappe Pink\n      Catppuccin Frappe Mauve: Catppuccin Frappe Mauve\n      Catppuccin Frappe Red: Catppuccin Frappe Red\n      Catppuccin Frappe Peach: Catppuccin Frappe Peach\n      Catppuccin Frappe Yellow: Catppuccin Frappe Yellow\n      Catppuccin Frappe Green: Catppuccin Frappe Green\n      Catppuccin Frappe Teal: Catppuccin Frappe Teal\n      Catppuccin Frappe Sapphire: Catppuccin Frappe Sapphire\n      Catppuccin Frappe Blue: Catppuccin Frappe Blue\n      Catppuccin Frappe Sky: Catppuccin Frappe Sky\n      Catppuccin Frappe Rosewater: Catppuccin Frappe Rosewater\n      Catppuccin Frappe Maroon: Catppuccin Frappe Maroon\n      Catppuccin Frappe Lavender: Catppuccin Frappe Lavender\n      Everforest Dark Red: 常青林深紅色\n      Everforest Dark Yellow: Everforest 深黃色\n      Everforest Dark Orange: Everforest 深橙色\n      Everforest Light Orange: 永恆森林淺橙色\n      Everforest Light Yellow: 常青森林 淺黃色\n      Everforest Dark Green: 常青森林深綠色\n      Everforest Dark Aqua: 永恆森林深海藍\n      Everforest Dark Blue: 永恆森林 深藍色\n      Everforest Dark Purple: 永恆森林深紫色\n      Everforest Light Red: 常青森林淺紅色\n      Everforest Light Green: 常青森林淺綠色\n      Everforest Light Aqua: Everest 淺綠色\n      Everforest Light Purple: 永恆森林 淺紫色\n      Everforest Light Blue: Everforest 淡藍色\n      Catppuccin Latte Mauve: Catppuccin Latte Mauve\n      Catppuccin Latte Red: Catppuccin Latte Red\n    Secondary Color Theme: '次要主題色'\n        #* Main Color Theme\n    UI Scale: UI縮放\n    Expand Side Bar by Default: 預設展開側邊欄\n    Disable Smooth Scrolling: 停用平滑捲動\n    Hide Side Bar Labels: 隱藏側邊欄標籤\n    Hide FreeTube Header Logo: 隱藏 FreeTube 標題圖示\n  Player Settings:\n    Player Settings: '播放器'\n    Play Next Video: '自動播放建議影片'\n    Turn on Subtitles by Default: '預設啟用字幕'\n    Autoplay Videos: '自動開始播放影片'\n    Proxy Videos Through Invidious: '透過Invidious代理影片'\n    Autoplay Playlists: '自動播放播放清單影片'\n    Enable Theatre Mode by Default: '預設開啟劇場模式'\n    Default Volume: '預設音量'\n    Default Playback Rate: '預設播放速度'\n    Default Video Format:\n      Default Video Format: '預設影片格式'\n      Dash Formats: 'DASH 格式'\n      Legacy Formats: '傳統格式'\n      Audio Formats: '音訊格式'\n    Default Quality:\n      Default Quality: '預設畫質'\n      Auto: '自動'\n      144p: '144p'\n      240p: '240p'\n      360p: '360p'\n      480p: '480p'\n      720p: '720p'\n      1080p: '1080p'\n      1440p: '1440p'\n      4k: '4k'\n      8k: '8k'\n    Next Video Interval: 自動播放倒數計時器\n    Scroll Volume Over Video Player: 在影片播放器上捲動以變更音量\n    Display Play Button In Video Player: 在影片播放器中顯示播放按鈕\n    Fast-Forward / Rewind Interval: 快轉／倒帶間隔\n    Scroll Playback Rate Over Video Player: 在影片播放程式上捲動播放速度\n    Max Video Playback Rate: 最大影片播放速率\n    Video Playback Rate Interval: 影片播放速率間隔\n    Screenshot:\n      Enable: 啟用螢幕截圖\n      Format Label: 螢幕截圖格式\n      Quality Label: 螢幕截圖品質\n      Folder Button: 選取資料夾\n      File Name Label: 檔案名稱模式\n      Error:\n        Forbidden Characters: 禁止的字元\n        Empty File Name: 空的檔案名稱\n      Ask Path: 詢問儲存的資料夾\n      Folder Label: 螢幕截圖資料夾\n      File Name Tooltip: 您可以使用下方的變數。%Y 為四位數的年份。%M 為兩位數的月份。%D 為兩位數的日。%H 為兩位數的小時。%N 為兩位數的分鐘。%S 為兩位數的秒數。%T 為三位數的毫秒。%s 為影片的秒數。%t 為三位數的影片毫秒數。%i 為影片 ID。\n    Enter Fullscreen on Display Rotate: 在顯示旋轉時進入全螢幕\n    Skip by Scrolling Over Video Player: 捲動影片播放器跳過\n    Autoplay Interruption Timer: 自動播放中斷計時器\n    Default Viewing Mode:\n      Theater: 劇院\n      Default Viewing Mode: 預設觀賞模式\n      Full Screen: 全螢幕\n      Picture in Picture: 畫中畫\n      External Player: 外部播放器（{externalPlayerName}）\n  Subscription Settings:\n    Subscription Settings: '訂閱'\n    Fetch Feeds from RSS: 從RSS擷取推送\n    Fetch Automatically: 自動擷取 Feed\n    Confirm Before Unsubscribing: 避免意外取消訂閱\n\n    'Limit the number of videos displayed for each channel': 限制每個頻道顯示的影片數量\n    To: 到\n  Privacy Settings:\n    Watch history has been cleared: 已刪除觀看紀錄\n    Are you sure you want to remove your entire watch history?: 您確定要移除全部的觀看紀錄嗎？\n    Remove Watch History: 移除觀看紀錄\n    Search cache has been cleared: 搜尋快取已清除\n    Are you sure you want to clear out your search cache?: 您確定要清除搜尋快取嗎？\n    Clear Search Cache: 清除搜尋快取\n    Save Watched Progress: 儲存觀看進度\n    Remember History: 儲存觀看紀錄\n    Privacy Settings: 隱私\n    Are you sure you want to remove all subscriptions and profiles?  This cannot be undone.: 您確定要移除所有訂閱與設定檔嗎嗎?  注意:這無法復原。\n    Remove All Subscriptions / Profiles: 移除所有訂閱／設定檔\n    Save Watched Videos With Last Viewed Playlist: 使用上次觀看的播放清單儲存觀看的影片\n    Remove All Playlists: 移除所有播放清單\n    All playlists have been removed: 所有播放清單已被移除\n    Are you sure you want to remove all your playlists?: 您確定要移除所有播放清單嗎？\n    Are you sure you want to clear out your search history and cache?: 您確定要清除搜尋紀錄與快取嗎？\n    Remember Search History: 儲存搜尋紀錄\n    Clear Search History and Cache: 清除搜尋紀錄與快取\n    Search history and cache have been cleared: 已清除搜尋紀錄與快取\n    Watched Progress Saving Mode:\n      Modes:\n        Never: 從不\n        Auto: 自動\n        Semi-auto: 半自動\n      Tooltip: 「自動」 = 每次退出影片頁面、影片結束以及遇到錯誤（如：速率受限和觀看連線階段已過期）時儲存。「半自動」 = 與自動類似（除了退出影片頁面外），並且可透過影片播放器下方的「儲存觀看進度」按鈕手動儲存進度。\n  Data Settings:\n    How do I import my subscriptions?: 我要如何匯入我的訂閱？\n    Unknown data key: 未知的資料金鑰\n    Unable to write file: 無法寫入檔案\n    Unable to read file: 無法讀取檔案\n    All watched history has been successfully exported: 所有觀看紀錄已成功匯出\n    All watched history has been successfully imported: 所有觀看紀錄已成功匯入\n    History object has insufficient data, skipping item: 觀看紀錄物件資料不足，正在跳過項目\n    Subscriptions have been successfully exported: 訂閱已成功匯出\n    Invalid history file: 無效的觀看紀錄檔案\n    Invalid subscriptions file: 無效的訂閱檔案\n    All subscriptions have been successfully imported: 所有訂閱已成功匯入\n    All subscriptions and profiles have been successfully imported: 所有訂閱與設定檔已成功匯入\n    Profile object has insufficient data, skipping item: 設定檔物件資料不足，正在跳過項目\n    Export History: 匯出觀看紀錄\n    Import History: 匯入觀看紀錄\n    Export NewPipe: 匯出NewPipe\n    Export YouTube: 匯出YouTube\n    Export FreeTube: 匯出FreeTube\n    Export Subscriptions: 匯出訂閱\n    Import Subscriptions: 匯入訂閱\n    Select Export Type: 選取匯出類型\n    Data Settings: 資料\n    Manage Subscriptions: 管理訂閱\n    Import Playlists: 匯入播放清單\n    All playlists has been successfully imported: 所有播放清單都已成功匯入\n    Export Playlists: 匯出播放清單\n    Playlist insufficient data: 「{playlist}」播放清單的資料不足，正在略過項目\n    All playlists has been successfully exported: 所有播放清單都已成功匯出\n    Subscription File: 訂閱檔案\n    History File: 歷史紀錄檔案\n    Playlist File: 播放清單檔案\n    Export Playlists For Older FreeTube Versions:\n      Label: 匯出較舊 FreeTube 版本的播放清單\n      Tooltip: \"此選項將所有播放清單中的影片匯出到名為「我的最愛」的播放清單中。\\n如何匯出和匯入舊版 FreeTube 播放清單中的影片：\\n1. 啟用此選項後匯出播放清單。\\n2. 使用「隱私設定」下的「刪除所有播放清單」選項刪除所有現有播放清單。\\n3. 啟動舊版的 FreeTube 並導入匯出的播放清單。”\"\n    Search history file: 搜尋歷史紀錄檔案\n    Search history: 搜尋歷史紀錄\n    Import search history: 匯入搜尋歷史紀錄\n    Export search history: 匯出搜尋歷史紀錄\n    All search history has been successfully imported: 已成功匯入所有搜尋歷史紀錄\n    All search history has been successfully exported: 已成功匯出所有搜尋歷史紀錄\n  Distraction Free Settings:\n    Hide Video Likes And Dislikes: 隱藏影片喜歡與不喜歡\n    Distraction Free Settings: 勿擾\n    Hide Video Views: 隱藏影片觀看次數\n    Hide Popular Videos: 隱藏流行影片\n    Hide Trending Videos: 隱藏熱門影片\n    Hide Live Chat: 隱藏直播聊天室\n    Hide Comment Likes: 隱藏留言的按讚數量\n    Hide Recommended Videos: 隱藏推薦影片\n    Hide Channel Subscribers: 隱藏頻道訂閱者\n    Hide Active Subscriptions: 隱藏作用中的訂閱\n    Hide Playlists: 隱藏播放清單\n    Hide Video Description: 隱藏影片描述\n    Hide Comments: 隱藏留言\n    Hide Live Streams: 隱藏直播串流\n    Hide Sharing Actions: 隱藏分享動作\n    Hide Videos on Watch: '觀看時隱藏影片'\n    Hide Chapters: 隱藏章節\n    Hide Upcoming Premieres: 隱藏即將到來的首映\n    Hide Channels Placeholder: 頻道 ID\n    Hide Channels: 隱藏頻道中的影片\n    Display Titles Without Excessive Capitalisation: 顯示沒有過多大寫與標點符號的標題\n    Hide Featured Channels: 隱藏精選頻道\n    Hide Channel Playlists: 隱藏頻道「播放清單」分頁\n    Hide Channel Shorts: 隱藏頻道「短片」分頁\n    Sections:\n      Side Bar: 側邊欄\n      Watch Page: 觀看頁面\n      General: 一般\n      Channel Page: 頻道頁面\n      Subscriptions Page: 訂閱頁面\n    Hide Channel Podcasts: 隱藏頻道「Podcast」分頁\n    Hide Channel Releases: 隱藏頻道「發布」分頁\n    Hide Subscriptions Shorts: 隱藏訂閱短片\n    Hide Subscriptions Videos: 隱藏訂閱影片\n    Hide Subscriptions Live: 隱藏訂閱直播\n    Hide Profile Pictures in Comments: 在留言中隱藏個人檔案圖片\n    Hide Channels Invalid: 提供的頻道 ID 無效\n    Hide Channels Disabled Message: 某些頻道被使用 ID 封鎖且無法處理。當這些 ID 更新時，功能將會被封鎖\n    Hide Channels Already Exists: 頻道 ID 已存在\n    Hide Channels API Error: 使用提供的 ID 擷取使用者時發生錯誤。請再次檢查 ID 是否正確。\n    Hide Videos, Playlists and Channels Containing Text: 隱藏包含文字的影片與播放清單\n    Hide Videos, Playlists and Channels Containing Text Placeholder: 單字、單字片段或片語\n    Hide Channel Home: 隱藏頻道「首頁」分頁\n    Show Added Items: 顯示新增的項目\n    Hide Channel Courses: 隱藏頻道“課程”標籤\n    Hide Channel Posts: 隱藏頻道「貼文」分頁\n    Hide Subscriptions Posts: 隱藏訂閱貼文\n  The app needs to restart for changes to take effect. Restart and apply change?: 必須重新啟動應用程式以生效。重新啟動並套用變更嗎？\n  Proxy Settings:\n    Error getting network information. Is your proxy configured properly?: 取得網路資訊時發生錯誤。您的代理伺服器設定正確嗎？\n    City: 城市\n    Region: 區域\n    Country: 國家\n    Ip: IP\n    Your Info: 您的資訊\n    Test Proxy: 測試代理伺服器\n    Clicking on Test Proxy will send a request to: 點擊測試代理伺服器將會傳送請求給\n    Proxy Port Number: 代理伺服器連接埠號\n    Proxy Host: 代理伺服器主機\n    Proxy Protocol: 代理伺服器協定\n    Enable Tor / Proxy: 啟用 Tor 或代理伺服器\n    Proxy Settings: 代理伺服器\n    Proxy Warning: FreeTube 沒有內建代理伺服器，但可以連線至外部代理伺服器，例如在您的機器上執行的代理伺服器，如 Tor 或外部代理伺服器，如某些 VPN 提供的 SOCKS5 代理伺服器。如果啟用，請確定您的代理伺服器/Tor 已經正確設定，否則 FreeTube 將無法取得任何資料。\n    Proxy Username: 代理伺服器使用者名稱\n    Proxy Password: 代理伺服器密碼\n  SponsorBlock Settings:\n    Notify when sponsor segment is skipped: 當贊助商片段被跳過時通知\n    'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API 網址（預設為 https://sponsor.ajay.app）\n    Enable SponsorBlock: 啟用 SponsorBlock\n    SponsorBlock Settings: SponsorBlock\n    Skip Options:\n      Skip Option: 略過選項\n      Auto Skip: 自動略過\n      Show In Seek Bar: 在進度列中顯示\n      Prompt To Skip: 提示略過\n      Do Nothing: 不要做任何事\n    Category Color: 分類色彩\n    UseDeArrowTitles: 使用 DeArrow 影片標題\n    UseDeArrowThumbnails: 使用 DeArrow 製作縮圖\n    'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow 縮圖產生器 API（預設值為 https://dearrow-thumb.ajay.app）\n  External Player Settings:\n    Custom External Player Arguments: 自訂外部播放程式參數\n    Custom External Player Executable: 自訂外部播放程式可執行檔\n    Ignore Unsupported Action Warnings: 忽略不支援的動作警告\n    External Player: 外部播放程式\n    External Player Settings: 外部播放程式\n    Players:\n      None:\n        Name: 無\n    Ignore Default Arguments: 忽略預設引數\n  Parental Control Settings:\n    Hide Unsubscribe Button: 隱藏取消訂閱按鈕\n    Show Family Friendly Only: 僅顯示適合家庭觀看\n    Hide Search Bar: 隱藏搜尋列\n    Parental Control Settings: 家長控制\n    Hide Uploader on Watch page: 在觀看頁面隱藏上傳者\n  Experimental Settings:\n    Replace HTTP Cache: 取代 HTTP 快取\n    Warning: 這些設定是實驗性的，它們啟用時可能會導致當機。強烈建議做好備份。使用時風險自負！\n    Experimental Settings: 實驗\n  Password Settings:\n    Set Password To Prevent Access: 設定密碼以防止存取設定\n    Remove Password: 移除密碼\n    Password Settings: 密碼\n    Set Password: 設定密碼\n  Password Dialog:\n    Password: 密碼\n    Enter Password To Unlock: 輸入密碼以解鎖設定\n  Sort Settings Sections (A-Z): 對設定區塊進行排序 (A-Z)\n  Return to Settings Menu: 回到設定選單\n  SABR:\n    Label: 啟用 SABR 作為 DASH 後端\n    Tooltip: SABR 將在未來版本成為唯一的 DASH 後端，且無法停用。此切換功能僅供早期實作出現無法修復的問題時使用。\nAbout:\n  #On About page\n  About: '關於'\n  #& About\n#On Channel Page\n  Website: 網站\n  Blog: 部落格\n  Credits: 貢獻者\n  FAQ: 常見問題\n  Email: 電子郵件\n  Beta: 測試版\n  Donate: 捐款\n  Help: 說明\n  these people and projects: 這些人與專案\n  FreeTube is made possible by {creditsPageLink}: FreeTube 誕生都要感謝{creditsPageLink}\n  Translate: 翻譯\n  room rules: 聊天室規則\n  Please read the {roomRulesLink}: 請閱讀{roomRulesLink}\n  Chat on Matrix: 在 Matrix 上聊天\n  Mastodon: Mastodon(長毛象/萬象)\n  Please check for duplicates before posting: 提交前請檢查有無重複的問題\n  GitHub issues: GitHub 問題追蹤器\n  Report a problem: 回報問題\n  FreeTube Wiki: FreeTube Wiki\n  GitHub releases: GitHub 版本\n  Downloads / Changelog: 下載 / 變更紀錄\n  Source code: 原始碼\n  Discussions: 討論\n  Licensed under the {licenseLink}: 遵循{licenseLink}許可協議\n  AGPLv3: AGPLv3\nChannel:\n  Subscribe: '訂閱'\n  Unsubscribe: '取消訂閱'\n  Search Channel: '搜尋頻道'\n  Your search results have returned 0 results: '搜尋結果為零'\n  Videos:\n    Videos: '影片'\n    This channel does not currently have any videos: '這個頻道目前沒有任何影片'\n    Sort Types:\n      Newest: '最新'\n      Oldest: '最舊'\n      Most Popular: '最熱門'\n  Playlists:\n    Playlists: '播放清單'\n    This channel does not currently have any playlists: '這個頻道目前沒有任何播放清單'\n    Sort Types:\n      Last Video Added: '最新上傳的影片'\n      Newest: '最新'\n      Oldest: '最舊'\n  About:\n    About: '關於'\n    Channel Description: '頻道說明'\n    Featured Channels: '推薦頻道'\n    Tags:\n      Tags: 標籤\n      Search for: 搜尋「{tag}」\n    Joined: 已加入\n    Location: 位置\n    Details: 詳細資訊\n  Added channel to your subscriptions: 已新增頻道至您的訂閱\n  Removed subscription from {count} other channel(s): 從{count}個其他頻道移除訂閱\n  Channel has been removed from your subscriptions: 頻道已從您的訂閱中移除\n  This channel is age-restricted and currently cannot be viewed in FreeTube.: 此頻道有年齡限制，目前無法在 FreeTube 中檢視。\n  Channel Tabs: 頻道分頁\n  This channel does not exist: 此頻道不存在\n  This channel does not allow searching: 此頻道不允許搜尋\n  Posts:\n    This channel currently does not have any posts: 此頻道目前沒有任何貼文\n    votes: '{votes} 票'\n    Reveal Answers: 揭露答案\n    Hide Answers: 隱藏答案\n    Video hidden by FreeTube: 由 FreeTube 隱藏的影片\n    Viewing Posts Only Supported By Invidious: 僅 Invidious 支援檢視貼文。前往頻道的社群分頁即可檢視其中的內容而不需使用 Invidious。\n    View Full Post: 檢視完整貼文\n  Live:\n    Live: 直播\n    This channel does not currently have any live streams: 此頻道目前沒有任何直播\n  Shorts:\n    This channel does not currently have any shorts: 此頻道目前沒有任何短片\n  Podcasts:\n    This channel does not currently have any podcasts: 此頻道目前沒有 podcast\n    Podcasts: Podcast\n  Releases:\n    Releases: 發布\n    This channel does not currently have any releases: 此頻道目前沒有任何發布\n  Home:\n    Home: 首頁\n    View Playlist: 檢視播放清單\n  Courses:\n    This channel does not currently have any courses: 該頻道目前還沒有任何課程\n    Courses: 課程\nVideo:\n  Open in YouTube: '在 YouTube 中開啟'\n  Copy YouTube Link: '複製 YouTube 連結'\n  Open YouTube Embedded Player: '開啟 YouTube 內嵌播放器'\n  Copy YouTube Embedded Player Link: '複製 YouTube 內嵌播放器連結'\n  Open in Invidious: '在 Invidious 中開啟'\n  Copy Invidious Link: '複製 Invidious 連結'\n  Views: '觀看'\n  Watched: '已觀看'\n  # As in a Live Video\n  Live: '直播'\n  Live Now: '現在直播'\n  Live Chat: '直播聊天室'\n  Enable Live Chat: '啟用直播聊天室'\n  Live Chat is currently not supported in this build.: '直播聊天室在此版本中目前不被支援。'\n  Live chat is enabled. Chat messages will appear here once sent.: '直播聊天結束。 聊天訊息一旦傳送將出現在這裡。'\n  'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': '直播聊天室目前不被Invidious API支援。 需要直接連線YouTube。'\n  Published:\n    In less than a minute: 不到一分鐘內\n  Published on: '發布於'\n#& Videos\n  Video has been removed from your history: 影片已從您的觀看紀錄中移除\n  Video has been marked as watched: 影片標記為已觀看\n  Remove From History: 從觀看紀錄中移除\n  Mark As Watched: 標記為已觀看\n  Autoplay: 自動播放\n  Previous: 上一部\n  Next: 下一個\n  Reverse Playlist: 反向播放清單\n  Shuffle Playlist: 隨機播放清單\n  Loop Playlist: 循環播放清單\n  Starting soon, please refresh the page to check again: 影片即將開始，請重新整理頁面以再次檢查是否有更新\n  Copy Invidious Channel Link: 複製 Invidious 頻道連結\n  Open Channel in Invidious: 在 Invidious 開啟頻道\n  Copy YouTube Channel Link: 複製 YouTube 頻道連結\n  Open Channel in YouTube: 在 YouTube 開啟頻道\n  Started streaming on: '開始直播時間'\n  Streamed on: 直播於\n  Video has been removed from your saved list: 影片已從您的播放清單移除\n  Video has been saved: 影片已儲存\n  Save Video: 儲存影片至播放清單\n  Sponsor Block category:\n    music offtopic: 音樂離題\n    interaction: 互動\n    self-promotion: 自我推廣\n    outro: 其他\n    intro: 介紹\n    sponsor: 贊助商\n    recap: 回顧\n    filler: 填充\n  External Player:\n    Unsupported Actions:\n      looping playlists: 循環播放清單\n      shuffling playlists: 隨機播放清單\n      reversing playlists: 反向播放清單\n      opening specific video in a playlist (falling back to opening the video): 在播放清單中開啟特定影片（汰退至開啟影片）\n      opening playlists: 正在開啟播放清單\n      setting a playback rate: 正在設定播放速度\n      starting video at offset: 在偏移處開始影片\n    UnsupportedActionTemplate: '{externalPlayer} 不支援：{action}'\n    OpeningTemplate: 正於 {externalPlayer} 中開啟 {videoOrPlaylist}……\n    playlist: 播放清單\n    video: 視訊\n    OpenInTemplate: 在 {externalPlayer} 中開啟\n  Premieres: 首映\n  Show Super Chat Comment: 顯示超級聊天留言\n  Scroll to Bottom: 捲動至底部\n  Upcoming: 即將到來\n  'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 即時聊天在此串流不可用。其可能被上傳者停用了。\n  Unhide Channel: 顯示頻道\n  Hide Channel: 隱藏頻道\n  More Options: 更多選項\n  Player:\n    TranslatedCaptionTemplate: '{language}（翻譯自「{originalLanguage}」）'\n    Audio Tracks: 音訊軌\n    Theatre Mode: 劇院模式\n    Exit Theatre Mode: 離開劇院模式\n    Full Window: 全視窗\n    Exit Full Window: 離開全視窗\n    Take Screenshot: 拍攝螢幕截圖\n    Show Stats: 顯示統計資料\n    Hide Stats: 隱藏統計資料\n    Stats:\n      Stats: 統計資料\n      Video ID: 影片 ID：{videoId}\n      Media Formats: 媒體格式：{formats}\n      Resolution: 解析度：{width}x{height}{'@'}{frameRate}\n      Player Dimensions: 播放器尺寸：{width}x{height}\n      Bitrate: 位元速率：{bitrate} kbps\n      Volume: 音量：{volumePercentage}%\n      Bandwidth: 頻寬：{bandwidth} kbps\n      Buffered: 已緩衝：{bufferedPercentage}%\n      Dropped Frames / Total Frames: 丟棄的畫面數：{droppedFrames} / 總畫面數：{totalFrames}\n      CodecAudio: 編解碼器：{audioCodec} ({audioItag})\n      CodecsVideoAudio: 編解碼器：{videoCodec} ({videoItag}) / {audioCodec} ({audioItag})\n      CodecsVideoAudioNoItags: 編解碼器：{videoCodec} / {audioCodec}\n    You appear to be offline: 您似乎已離線。\n    Playback will resume automatically when your connection comes back: 當您的連線恢復時，將會自動繼續播放。\n    Skipped segment: 已跳過 {segmentCategory} 段\n    Autoplay is on: 自動播放已開啟\n    Autoplay is off: 自動播放已關閉\n  IP block: YouTube 已封鎖您的 IP 位址，因此無法觀看影片。請嘗試切換到其他 VPN 或代理伺服器。\n  MembersOnly: 會員專屬影片無法使用 FreeTube 觀看，因為這些影片需要 Google 登入並且必須訂閱上傳者的付費頻道。\n  AgeRestricted: 由於需要 Google 登入並使用經過年齡驗證的 YouTube 帳戶，FreeTube 無法觀看有限制年齡的影片。\n  Unlisted: 未公開\n  DeArrow:\n    Show Original Details: 顯示原始詳細資訊\n    Show Modified Details: 顯示修改後的詳細資訊\n#& Playlists\n  DRMProtected: 受 DRM 保護的影片無法在 FreeTube 上播放，因為它們需要專屬的封閉原始碼元件。如果您想觀賞此影片，請使用支援 DRM 的網路瀏覽器在 YouTube 官方網站觀賞。\n  Save Watched Progress: 儲存觀看進度\n  Watched Progress Saved: 觀看進度已儲存\n  Watch:\n    'Remaining preroll-ad time: {remindingTimeSeconds}s': 剩餘前置廣告時間：{remindingTimeSeconds}秒\n    'Remaining SABR backoff time: {remindingTimeSeconds}s': 剩餘 SABR 後退時間：{remindingTimeSeconds}秒\n  Popout Live Chat: 彈出式聊天\nPlaylist:\n  #& About\n  View Full Playlist: '觀看完整播放清單'\n  Last Updated On: '最後更新於'\n\n# On Video Watch Page\n#* Published\n#& Views\n  Playlist: 播放清單\n  Sort By:\n    DateAddedNewest: 新增日期（最新）\n    DateAddedOldest: 新增日期（最舊）\n    AuthorAscending: 作者 (A-Z)\n    AuthorDescending: 作者 (Z-A)\n    VideoTitleAscending: 標題 (A-Z)\n    VideoTitleDescending: 標題 (Z-A)\n    Custom: 自訂\n    VideoDurationDescending: 持續時間（最長）\n    VideoDurationAscending: 持續時間（最短）\n    PublishedOldest: 發佈日期（最舊）\n    PublishedNewest: 發佈日期（最新）\nChange Format:\n  Change Media Formats: '變更影片格式'\n  Use Dash Formats: '使用 DASH 格式'\n  Use Legacy Formats: '使用傳統格式'\n  Use Audio Formats: '使用音訊格式'\n  Audio formats are not available for this video: 這個影片沒有音訊格式\n  Dash formats are not available for this video: 這個影片沒有 DASH 格式\n  Legacy formats are not available for this video: 舊格式不適用於該影片\nShare:\n  Share Video: '分享影片'\n  Share Playlist: '分享播放清單'\n  Copy Link: '複製連結'\n  Open Link: '開啟連結'\n  Copy Embed: '複製內嵌'\n  Open Embed: '開啟內嵌'\n  # On Click\n  Invidious URL copied to clipboard: '複製Invidious URL到剪貼簿'\n  Invidious Embed URL copied to clipboard: '複製Invidious內嵌URL到剪貼簿'\n  YouTube URL copied to clipboard: '複製 YouTube 連結到剪貼簿'\n  YouTube Embed URL copied to clipboard: '複製YouTube內嵌URL到剪貼簿'\n  Include Timestamp: 包含時間戳\n  YouTube Channel URL copied to clipboard: YouTube頻道URL已複製到剪貼簿\n  Invidious Channel URL copied to clipboard: Invidious頻道URL已複製到剪貼簿\n  Share Channel: 分享頻道\n  Share Post: 分享貼文\nMini Player: '迷你播放器'\nComments:\n  Comments: '留言'\n  Click to View Comments: '點擊查看留言'\n  Getting comment replies, please wait: '正在取得留言回覆，請稍候'\n  Hide Comments: '隱藏留言'\n  # Context: View 10 Replies, View 1 Reply\n  There are no comments available for this video: '這個影片沒有留言'\n  Load More Comments: '載入更多留言'\n  There are no more comments for this video: 此影片無更多留言\n  Newest first: 最新優先\n  Top comments: 最熱門留言\n  Show More Replies: 顯示更多回覆\n  Pinned by: 釘選由\n  Member: 成員\n  View {replyCount} replies: 檢視 1 則回覆 | 檢視 {replyCount} 則回覆\n  Hearted: 喜歡的\n  Subscribed: 已訂閱\n  There are no comments available for this post: 此貼文尚無留言\n  Hide {replyCount} replies: 隱藏 1 則回覆 | 隱藏 {replyCount} 則回覆\n  View 1 reply from {channelName}: 檢視來自 {channelName} 的 1 則回覆\n  View {replyCount} replies from {channelName} and others: 檢視來自 {channelName} 與其他頻道的 {replyCount} 則回覆\nUp Next: '觀看其他類似影片'\n\n# Toast Messages\nLocal API Error (Click to copy): '區域API錯誤（點擊複製）'\nInvidious API Error (Click to copy): 'Invidious API錯誤（點擊複製）'\nFalling back to Invidious API: '回退到Invidious API'\nFalling back to Local API: '回退到區域API'\nLoop is now disabled: '循環播放現在被停用'\nLoop is now enabled: '循環播放現在被啟用'\nShuffle is now disabled: '隨機播放現在被停用'\nShuffle is now enabled: '隨機播放現在被停用'\nPlaying Next Video: '將播放下一影片'\nPlaying Previous Video: '將播放上一影片'\nCanceled next video autoplay: '取消自動播放下一部影片'\n'The playlist has ended. Enable loop to continue playing': '播放清單已播放完畢。 開啟循環播放來繼續播放'\n\nYes: '是'\nNo: '否'\nLocale Name: 繁體中文\nProfile:\n  '{profile} is now the active profile': '{profile}現在是作用中的設定檔'\n  Your default profile has been changed to your primary profile: 您的預設設定檔已變更為您的主要設定檔\n  Removed {profile} from your profiles: 已從您的設定檔移除{profile}\n  Your default profile has been set to {profile}: 您的預設設定檔已設定為{profile}\n  Profile has been updated: 設定檔已更新\n  Profile has been created: 設定檔已建立\n  Your profile name cannot be empty: 您的設定檔名稱不能為空\n  All subscriptions will also be deleted.: 所有訂閱將會被刪除。\n  Are you sure you want to delete this profile?: 您確定您想刪除此設定檔嗎？\n  Delete Profile: 刪除設定檔\n  Make Default Profile: 設為預設設定檔\n  Update Profile: 更新設定檔\n  Create Profile: 建立設定檔\n  Profile Preview: 設定檔預覽\n  Custom Color: 自訂色彩\n  Color Picker: 選色器\n  Edit Profile: 編輯設定檔\n  Create New Profile: 建立新設定檔\n  Profile Manager: 設定檔管理器\n  All Channels: 所有頻道\n  Profile Select: 選取設定檔\n  Are you sure you want to delete the selected channels?  This will not delete the channel from any other profile.: 您確定您想移除選取的頻道？ 這不會從其他設定檔中移除頻道。\n  ? This is your primary profile.  Are you sure you want to delete the selected channels?  The same channels will be deleted in any profile they are found in.\n  : 這是您的主要設定檔。 您確定要移除選取的頻道？ 相同的頻道中任何找到的設定檔會被移除。\n  No channel(s) have been selected: 無頻道已選取\n  Add Selected To Profile: 添加選取的到設定檔\n  Delete Selected: 移除選取的\n  Select None: 全不選\n  Select All: 全選\n  '{number} selected': '{number}個選取的'\n  Other Channels: 其他頻道\n  Subscription List: 訂閱清單\n  Profile Filter: 設定檔篩選器\n  Profile Settings: 設定檔\n  Toggle Profile List: 切換個人檔案清單\n  Open Profile Dropdown: 開啟個人資料下拉式選單\n  Close Profile Dropdown: 關閉個人資料下拉式選單\n  Profile Name: 設定檔名稱\n  Edit Profile Name: 修改設定檔名稱\n  Create Profile Name: 建立設定檔名稱\nThe playlist has been reversed: 播放清單已反轉\nA new blog is now available, {blogTitle}. Click to view more: 已有新的部落格文章，{blogTitle}。點擊以檢視更多\nDownload From Site: 從網站下載\nVersion {versionNumber} is now available!  Click for more details: 有新版本！最新版本是 {versionNumber} ！按此取得更多資訊\nThis video is unavailable because of missing formats. This can happen due to country unavailability.: 沒有這個影片因為缺少格式。這個可能發生由於國家不可用。\nTooltips:\n  Subscription Settings:\n    Fetch Feeds from RSS: 啟用後，FreeTube 將使用 RSS 替代其預設方法來擷取您的訂閱 feed。RSS 的速度較快，而且可以防止 IP 封鎖，但它可能不會提供某些資訊，例如影片長度、直播狀態或貼文\n    Fetch Automatically: 啟用後，FreeTube 將會在啟動時和開啟新視窗時自動擷取您的訂閱 feed。\n  Player Settings:\n    Default Video Format: 設定要用於影片播放的格式。DASH 格式有更高的畫質。傳統格式會限制在 360p 但頻寬需求更低。音訊格式為僅有音訊的串流。\n    Proxy Videos Through Invidious: 將連線到 Invidious 而非直接連線到 YouTube 來提供影片。\n    Scroll Playback Rate Over Video Player: 當游標停在影片上時，按住 Ctrl 鍵（Mac 的話則是 Command 鍵），然後向前或向後滾動滑鼠滾輪來控制播放速度。按住 Ctrl 鍵（Mac 的話則是 Command 鍵）並點擊滑鼠左鍵以快速回到預設的播放速度（1x，除非在設定中更改）。\n    Skip by Scrolling Over Video Player: 使用滾輪跳過影片，MPV 風格。\n  General Settings:\n    Invidious Instance: FreeTube 將連線到 Invidious 站台進行 API 呼叫。\n    Thumbnail Preference: FreeTube 中所有縮圖都會被替換為經過模糊處理或隱藏的影片畫面而非預設縮圖。\n    Fallback to Non-Preferred Backend on Failure: 當您的偏好 API 有問題時，FreeTube 將自動嘗試使用您的非偏好 API 作為汰退方案。\n    Preferred API Backend: 選擇 FreeTube 要用於取得YouTube資料的伺服器。本地 API 是內建擷取器。Invidious API 需要 Invidious 伺服器才能連線。\n    Region for Trending: 熱門影片區域可以讓您選擇想要顯示哪個國家的熱門影片。\n    External Link Handling: \"選擇點擊後無法在 FreeTube 中開啟連結時的預設行為。\\n預設情況下 FreeTube 將會在您的預設瀏覽器中開啟點擊的連結。\\n\"\n    Open Deep Links In New Window: 傳遞給 FreeTube 的 URL，例如透過重定向瀏覽器擴充套件或命令列引數，會在新視窗中開啟。\n  External Player Settings:\n    Custom External Player Arguments: 要傳給外部播放器的任何自訂命令列引數。\n    Ignore Warnings: 當目前的外部播放程式不支援目前動作時（例如反向播放清單等等），消除警告。\n    Custom External Player Executable: 預設情況下，FreeTube 會假設選定的外部播放程式可以透過 PATH 環境變數找到。如果需要的話，請在此設定自訂路徑。\n    External Player: 選擇外部播放程式將會在縮圖上顯示圖示，用來在外部播放程式中開啟影片（若支援的話，播放清單也可以）。警告：Invidious 設定不會影響外部播放程式。\n    DefaultCustomArgumentsTemplate: （預設：'{defaultCustomArguments}'）\n    Ignore Default Arguments: 除了影片 URL 之外，不要向外部播放器傳送任何預設引數（例如播放速率、播放清單 URL 等）。 自訂引數仍會被傳遞。\n  Experimental Settings:\n    Replace HTTP Cache: 停用 Electron 以磁碟為基礎的 HTTP 快取並啟用自訂的記憶體圖片快取。會導致記憶體使用量增加。\n  Distraction Free Settings:\n    Hide Channels: 輸入頻道 ID 以隱藏所有影片、播放清單與頻道本身，使其完全不出現在搜尋、趨勢、熱門與建議中。輸入的頻道 ID 必須完全符合，且區分大小寫。\n    Hide Subscriptions Live: 此設定會被「{settingsSection}」的「{subsection}」部分中應用程式範圍的「{appWideSetting}」設定覆寫\n    Hide Videos, Playlists and Channels Containing Text: 輸入單字、單字片段或片語（不分大小寫），以隱藏整個 FreeTube 中原始標題包含該單字、單字片段或片語的所有影片與播放清單，僅不包括歷史紀錄、您的播放清單與播放清單內的影片。\n    Hide Videos on Watch: 在訂閱和頻道頁面上的影片、短片和直播頁面中隱藏已觀看的影片。這不會影響頻道頁面上的主頁\n  SponsorBlock Settings:\n    UseDeArrowTitles: 將影片標題取代為 DeArrow 使用者遞交的標題。\n    UseDeArrowThumbnails: 將影片縮圖替換為來自 DeArrow 的縮圖。\nPlaying Next Video Interval: 馬上播放下一個影片。點擊取消。| 播放下一個影片的時間為{nextVideoInterval}秒。點擊取消。| 播放下一個影片的時間為{nextVideoInterval}秒。點擊取消。\nMore: 更多\nUnknown YouTube url type, cannot be opened in app: 未知的 YouTube url 類型，無法在應用程式開啟\nOpen New Window: 開新視窗\nDefault Invidious instance has been cleared: 預設 Invidious 站台已被清除\nDefault Invidious instance has been set to {instance}: 預設 Invidious 站台已被設定為 {instance}\nSearch Bar:\n  Clear Input: 清除輸入\n  Remove: 移除\nExternal link opening has been disabled in the general settings: 已在一般設定中停用外部連結開啟\nAre you sure you want to open this link?: 您確定您想要開啟此連結嗎？\nScreenshot Success: 已儲存螢幕截圖\nScreenshot Error: 螢幕截圖失敗。 {error}\nNew Window: 新視窗\nChannels:\n  Channels: 頻道\n  Title: 頻道清單\n  Search bar placeholder: 搜尋頻道\n  Count: 找到 {number} 個頻道。\n  Empty: 您的頻道清單目前為空。\n  Unsubscribe Prompt: 您確定您想要從「{channelName}」取消訂閱嗎？\nClipboard:\n  Copy failed: 複製到剪貼簿失敗\n  Cannot access clipboard without a secure connection: 無法在沒有安全連線的情況下存取剪貼簿\nChapters:\n  Chapters: 章節\n  Key Moments: 重要時刻\nPreferences: 偏好設定\nOk: 確定\nHashtag:\n  Hashtag: 主題標籤\n  This hashtag does not currently have any videos: 此標籤目前沒有任何影片\nChannel Hidden: '{channel} 已新增至頻道過濾條件'\nGo to page: 到 {page}\nChannel Unhidden: '{channel} 已從頻道過濾條件移除'\nTrimmed input must be at least N characters long: 修剪後的輸入必須至少有 1 個字元長 | 修剪後的輸入必須至少有 {length} 個字元長\nTag already exists: 「{tagName}」標籤已存在\nClose Banner: 關閉橫幅\nAge Restricted:\n  This channel is age restricted: 此頻道有年齡限制\n  This video is age restricted: 此影片有年齡限制\ncheckmark: ✓\nDisplay Label: '{label}：{value}'\nMoments Ago: 不久前\nFeed:\n  Feed Last Updated: '{feedName} feed 上次更新時間：{date}'\n  Refresh Feed: 重新整理 {subscriptionName}\nYes, Delete: 是的，刪除\nYes, Restart: 是的，重新啟動\nYes, Open Link: 是的，開啟連結\nCancel: 取消\nSearch character limit: 搜尋查詢超出了 {searchCharacterLimit} 個字元的限制\nSearch Listing:\n  Label:\n    4K: 4K\n    Subtitles: 字幕\n    Closed Captions: 隱藏式字幕\n    8K: 8K\n    VR180: VR180\n    360 Video: 360°\n    New: 新\n    3D: 3D\nKeyboardShortcutTemplate: '{label} ({shortcut})'\nshortcutJoinOperator: +\nKeys:\n  alt: Alt\n  ctrl: Ctrl\n  arrowdown: 向下方向鍵\n  arrowleft: 向左方向鍵\n  arrowright: 向右方向鍵\n  arrowup: 向上方向鍵\n  shift: Shift\n  enter: Enter\n  plus: 加號\nRight-click or hold to see history: 右鍵點選或按住不放可以檢視歷史紀錄\nAutoplay Interruption Timer: 自動播放因 {autoplayInterruptionIntervalHours} 小時未活動而取消\nDescription:\n  Collapse Description: 顯示較少\n  Expand Description: ……更多\nKeyboardShortcutPrompt:\n  History Forward: 前進一頁\n  Navigate to History: 前往紀錄頁面\n  Refresh: 以最新內容重新整理 feed\n  Captions: 切換開啟/關閉字幕\n  Stats: 顯示影片統計資料\n  Large Rewind: 快退 10 秒 / 根據目前的影片播放速率快退影片\n  Keyboard Shortcuts: 鍵盤快捷鍵\n  Sections:\n    Video:\n      Playback: 影片：播放\n      General: 影片：一般\n    App:\n      Situational: 應用程式：情境\n      General: 應用程式：一般\n  Show Keyboard Shortcuts: 顯示鍵盤快捷鍵\n  History Backward: 回上一頁\n  Large Fast Forward: 快轉 10 秒 / 根據目前的影片播放速率快轉影片\n  Mute: 切換靜音\n  Decrease Video Speed: 根據影片播放速率間隔降低影片速度\n  Increase Video Speed: 根據影片播放速率間隔增加影片速度\n  Theatre Mode: 切換劇院模式\n  Focus Secondary Search: 焦點置於次要搜尋列（若有）\n  Take Screenshot: 拍攝螢幕截圖\n  New Window: 建立新視窗\n  Navigate to Settings: 前往設定頁面\n  Focus Search: 將焦點置於搜尋列\n  Search in New Window: 在新視窗中搜尋\n  Last Frame: 前一個畫面（在暫停時）\n  Volume Down: 降低音量\n  Small Rewind: 根據快退間隔與目前的影片播放速率快退 X 秒\n  Small Fast Forward: 根據快轉間隔與目前的影片播放速率快轉 X 秒\n  Last Chapter: 上一章\n  Next Chapter: 下一章\n  Skip by Tenths: 按百分比跳過影片（3 次跳過 30% 的影片時間）\n  Toggle Developer Tools: 切換開發者工具\n  Reset Zoom: 重設縮放層級 / 使用者介面縮放比例\n  Zoom In: 放大\n  Zoom Out: 縮小\n  Next Frame: 下一個畫面（在暫停時）\n  Volume Up: 提高音量\n  Fullscreen: 切換全螢幕\n  Picture in Picture: 切換畫中畫模式\n  Play: 切換播放/暫停\n  Full Window: 切換全視窗\n  Minimize Window: 最小化視窗\n  Close Window: 關閉視窗\n  Home: 跳至影片開頭\n  End: 跳至影片結尾\n  Skip to Next Video: 跳到播放清單中的下一部影片或下一部推薦影片\n  Skip to Previous Video: 跳到播放清單中的上一部影片\nshortcutLabelSeparator: ｜\nCompact side navigation: 簡潔側邊導航\nExpand side navigation: 展開側邊導航\n"
  },
  {
    "path": "static/manifest.json",
    "content": "{\n\t\"dir\" : \"ltr\",\n\t\"lang\" : \"de\",\n\t\"name\" : \"FreeTube\",\n\t\"scope\" : \"/\",\n\t\"display\" : \"standalone\",\n\t\"start_url\" : \"https://app.freetubeapp.io/\",\n\t\"short_name\" : \"FreeTube\",\n\t\"theme_color\" : \"transparent\",\n\t\"description\" : \"A description\",\n\t\"orientation\" : \"any\",\n\t\"background_color\" : \"transparent\",\n\t\"related_applications\" : [],\n\t\"prefer_related_applications\" : false,\n\t\"icons\" : [\"/_icons/logoColor.svg\"],\n\t\"url\" : \"https://app.freetubeapp.io\",\n\t\"screenshots\" : [],\n\t\"generated\" : \"true\"\n}\n"
  },
  {
    "path": "static/pwabuilder-sw.js",
    "content": "/* eslint-disable no-console */\n// This is the service worker with the Advanced caching\n\nconst CACHE = 'pwabuilder-adv-cache'\nconst precacheFiles = [\n  /* Add an array of files to precache for your app */\n  'index.html',\n  'web.js',\n  'web.css',\n  'static/*',\n  '_icons/*',\n  'fonts/*'\n]\n\n// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = \"offline.html\";\nconst offlineFallbackPage = 'index.html'\n\nconst networkFirstPaths = [\n  /* Add an array of regex of paths that should go network first */\n  // Example: /\\/api\\/.*/\n]\n\nconst avoidCachingPaths = [\n  /* Add an array of regex of paths that shouldn't be cached */\n  // Example: /\\/api\\/.*/\n]\n\nfunction pathComparer(requestUrl, pathRegEx) {\n  return requestUrl.match(new RegExp(pathRegEx))\n}\n\nfunction comparePaths(requestUrl, pathsArray) {\n  if (requestUrl) {\n    for (let index = 0; index < pathsArray.length; index++) {\n      const pathRegEx = pathsArray[index]\n      if (pathComparer(requestUrl, pathRegEx)) {\n        return true\n      }\n    }\n  }\n\n  return false\n}\n\nself.addEventListener('install', function (event) {\n  console.log('[PWA Builder] Install Event processing')\n\n  console.log('[PWA Builder] Skip waiting on install')\n  self.skipWaiting()\n\n  event.waitUntil(\n    caches.open(CACHE).then(function (cache) {\n      console.log('[PWA Builder] Caching pages during install')\n\n      return cache.addAll(precacheFiles).then(function () {\n        return cache.add(offlineFallbackPage)\n      })\n    })\n  )\n})\n\n// Allow sw to control of current page\nself.addEventListener('activate', function (event) {\n  console.log('[PWA Builder] Claiming clients for current page')\n  event.waitUntil(self.clients.claim())\n})\n\n// If any fetch fails, it will look for the request in the cache and serve it from there first\nself.addEventListener('fetch', function (event) {\n  if (event.request.method !== 'GET') return\n\n  if (comparePaths(event.request.url, networkFirstPaths)) {\n    networkFirstFetch(event)\n  } else {\n    cacheFirstFetch(event)\n  }\n})\n\nfunction cacheFirstFetch(event) {\n  event.respondWith(\n    fromCache(event.request).then(\n      function (response) {\n        // The response was found in the cache so we respond with it and update the entry\n\n        // This is where we call the server to get the newest version of the\n        // file to use the next time we show view\n        event.waitUntil(\n          fetch(event.request).then(function (response) {\n            return updateCache(event.request, response)\n          })\n        )\n\n        return response\n      },\n      function () {\n        // The response was not found in the cache so we look for it on the server\n        return fetch(event.request)\n          .then(function (response) {\n            // If request was success, add or update it in the cache\n            event.waitUntil(updateCache(event.request, response.clone()))\n\n            return response\n          })\n          .catch(function (error) {\n            // The following validates that the request was for a navigation to a new document\n            if (event.request.destination !== 'document' || event.request.mode !== 'navigate') {\n              return\n            }\n\n            console.error('[PWA Builder] Network request failed and no cache.' + error)\n            // Use the precached offline page as fallback\n            return caches.open(CACHE).then(function (cache) {\n              cache.match(offlineFallbackPage)\n            })\n          })\n      }\n    )\n  )\n}\n\nfunction networkFirstFetch(event) {\n  event.respondWith(\n    fetch(event.request)\n      .then(function (response) {\n        // If request was success, add or update it in the cache\n        event.waitUntil(updateCache(event.request, response.clone()))\n        return response\n      })\n      .catch(function (error) {\n        console.error('[PWA Builder] Network request Failed. Serving content from cache: ' + error)\n        return fromCache(event.request)\n      })\n  )\n}\n\nfunction fromCache(request) {\n  // Check to see if you have it in the cache\n  // Return response\n  // If not in the cache, then return error page\n  return caches.open(CACHE).then(function (cache) {\n    return cache.match(request).then(function (matching) {\n      if (!matching || matching.status === 404) {\n        return Promise.reject(new Error('no-match'))\n      }\n\n      return matching\n    })\n  })\n}\n\nfunction updateCache(request, response) {\n  if (!comparePaths(request.url, avoidCachingPaths)) {\n    return caches.open(CACHE).then(function (cache) {\n      return cache.put(request, response)\n    })\n  }\n\n  return Promise.resolve()\n}\n"
  },
  {
    "path": "stylelint.config.mjs",
    "content": "import logicalSpec from 'stylelint-use-logical-spec'\nimport a11y from '@double-great/stylelint-a11y'\n/** @type {import('stylelint').Config} */\nexport default {\n  plugins: [logicalSpec, ...a11y],\n  extends: ['stylelint-config-standard', 'stylelint-config-sass-guidelines'],\n  overrides: [\n    {\n      files: '**/*.scss',\n      customSyntax: 'postcss-scss',\n      rules: {\n        'max-nesting-depth': null,\n        'selector-max-compound-selectors': null\n      }\n    },\n    {\n      files: '**/*.css',\n      rules: { }\n    }\n  ],\n  rules: {\n    'selector-no-qualifying-type': [\n      true,\n      {\n        ignore: ['attribute']\n      }\n    ],\n    'selector-class-pattern': null,\n    'selector-id-pattern': null,\n    'selector-pseudo-class-no-unknown': [\n      true,\n      {\n        ignorePseudoClasses: ['deep', 'global']\n      }\n    ],\n    'a11y/no-outline-none': true,\n    'liberty/use-logical-spec': ['always']\n  }\n}\n"
  }
]